#!/bin/sh # sekrit # Written in 2018-2019 by Lucas # CC0 1.0 Universal/Public domain - No rights reserved # # To the extent possible under law, the author(s) have dedicated all # copyright and related and neighboring rights to this software to the # public domain worldwide. This software is distributed without any # warranty. You should have received a copy of the CC0 Public Domain # Dedication along with this software. If not, see # . # sekrit is a relatively small shell script for writing and reading # encrypted files, aimed to deal mostly with accounts credentials, but # general enough to deal with any content. It can populate each key # with random data or with fixed data, reading either command-line # arguments or stdin. # # To be used as a password manager, it's recommended to pair it with # xclip(1). For example, for username, password and optional second # factor: # # sekrit get account/user | xclip -r -l 1 -sel clip -q # sekrit get account/pass | xclip -r -l 1 -sel clip -q # sekrit has account/2fa && sekrit get account/2fa \ # | $program_for_totp | xclip -r -l 1 -sel clip -q usage() { cat - <<. >&2 Usage: ${0##*/} add key [value ...] ${0##*/} gen [-l length] [chars] ${0##*/} get key ${0##*/} has key ${0##*/} ls [keys ...] If no value was provided on command line, add reads from stdin. . exit 1 } err() { printf "%s: %s\n" "${0##*/}" "$*" >&2 exit 1 } check_key() { [ "$1" = "${1%/}" ] || err "Key can not end in a slash." } to_number() { printf "%u" "$*" 2>/dev/null } sekrit_add() { [ $# -eq 1 ] && [ -n "$1" ] || usage key=$1 check_key "$key" shift f=$SEKRIT_DIR/$key.gpg mkdir -p "${f%/*}" [ -f "$f" ] && err "Key \"$key\" already exists." if [ $# -ne 0 ]; then printf "%s\n" "$*" else cat - fi | gpg2 -qae -r "$SEKRIT_GPG_ID" >"$f" # make it read-only chmod -- 400 "$f" } sekrit_gen() { len=43 OPTIND=1 while getopts l: flag; do case "$flag" in l) len=$(to_number "$OPTARG") || err "Invalid password length." ;; [?]) usage ;; esac done shift $(($OPTIND - 1)) [ $# -le 1 ] || usage chars=+/0-9A-Za-z if [ $# -eq 1 ]; then [ -n "$1" ] || usage chars=$1 fi tr -cd -- "$chars" /dev/null && printf "\n" } sekrit_get() { [ $# -eq 1 ] || usage key=$1 check_key "$1" shift f=$SEKRIT_DIR/$key.gpg [ ! -f "$f" ] && err "No data for key \"$key\"." gpg2 -qd "$f" } sekrit_has() { [ $# -eq 1 ] || usage key=$1 check_key "$1" shift [ -f "$SEKRIT_DIR/$key.gpg" ] } ls_key() { d=$SEKRIT_DIR$1 find "$d" -type f -name "*.gpg" | sort | cut -c $((${#d} + 1))- | sed "s/\.gpg$//" } sekrit_ls() { if [ $# -eq 0 ]; then ls_key / else for key; do printf "%s:\n" "$key" ls_key /"$key"/ | sed "s/^/ /" printf "\n" done fi } set -e [ $# -ge 1 ] || usage cmd=$1 shift umask 077 : ${SEKRIT_DIR:=~/keep/sekrit} : ${SEKRIT_GPG_ID:=myself} mkdir -p "$SEKRIT_DIR" case "$cmd" in add) sekrit_add "$@";; gen) sekrit_gen "$@" ;; get) sekrit_get "$@" ;; has) sekrit_has "$@" ;; ls) sekrit_ls "$@" ;; *) usage ;; esac