logo

secret

Replacement to pass(1) based on reop(1)

secret (3529B)


      1 #!/bin/sh
      2 # secret: Replacement to pass(1) based on reop(1)
      3 # Copyright 2020 Haelwenn (lanodan) Monnier <contact+secret@hacktivis.me>
      4 # SPDX-License-Identifier: ISC
      5 basepath="$HOME/.secret-storage"
      6 
      7 set -e
      8 
      9 secret_clip() {
     10 	head -n 1 | tr -d '\n' | xclip -i -selection clipboard
     11 }
     12 
     13 secret_init() {
     14 	set -x
     15 
     16 	test -f "${basepath}.pub" -a -f "${basepath}.priv" || reop -G -p "${basepath}.pub" -s "${basepath}.priv"
     17 	chmod 0400 "${basepath}.pub" "${basepath}.priv"
     18 
     19 	test -d "$basepath/.git" || git init "${basepath}"
     20 	chmod 0700 "$basepath"
     21 }
     22 
     23 secret_list() {
     24 	( cd "$basepath" && find . -type f -name '*.reop' "$@" | sed -e 's;^./;;' -e 's;.reop$;;') | sort
     25 }
     26 
     27 secret_list_oath() {
     28 	secret_list -name '*.oath.reop' "$@"
     29 }
     30 
     31 tree() {
     32 	secret_list "$@" | tree --fromfile
     33 }
     34 
     35 secret_read() {
     36 	entry="$*"
     37 	target="${SECRET_FILE:--}"
     38 
     39 	reop -D -p "${basepath}.pub" -s "${basepath}.priv" -m "$target" -x "${basepath}/${entry}.reop"
     40 }
     41 
     42 secret_write() {
     43 	entry="$*"
     44 	target="${SECRET_FILE:--}"
     45 
     46 	reop -E -p "${basepath}.pub" -s "${basepath}.priv" -m "$target" -x "${basepath}/${entry}.reop"
     47 
     48 	if test -f "${basepath}/.git/HEAD"
     49 	then
     50 		oldpwd="$PWD"
     51 		cd "${basepath}"
     52 
     53 		git add "${entry}.reop"
     54 		git commit -m "${entry}: encrypt auto-update"
     55 		if [ "$(git remote show -n)" != "" ]; then git push; fi
     56 
     57 		cd "${oldpwd}"
     58 	else
     59 		echo "No git repository in ‘$basepath’, consider creating one"
     60 	fi
     61 }
     62 
     63 secret_read_oath() {
     64 	oathtool $(secret_read "$@")
     65 }
     66 
     67 secret_edit() {
     68 	file="${basepath}/.secret_$RANDOM.txt"
     69 	unset SECRET_FILE
     70 
     71 	secret_read "$@" > "$file"
     72 
     73 	$EDITOR "$file" || rm -f "$file"
     74 
     75 	secret_write "$@" < "$file" ; rm -f "$file"
     76 }
     77 
     78 secret_dmenu() {
     79 	echo | dmenu -nb '#000' -nf '#000' -p "Passphrase: "
     80 }
     81 
     82 secret_dmenu_oath() {
     83 	entry="$(secret_list -name '*.oath.reop' | dmenu -i)"
     84 	export SECRET_FILE="${basepath}/.secret_$RANDOM.txt"
     85 	secret_dmenu | secret_read "$entry"
     86 
     87 	oathtool $(cat "${SECRET_FILE}") | secret_clip
     88 
     89 	shred -u "${SECRET_FILE}"
     90 }
     91 
     92 secret_dmenu_read() {
     93 	entry="$(secret_list | dmenu -i)"
     94 	export SECRET_FILE="${basepath}/.secret_$RANDOM.txt"
     95 	secret_dmenu | secret_read "$entry"
     96 
     97 	cat "${SECRET_FILE}" | secret_clip
     98 	shred -u "${SECRET_FILE}"
     99 }
    100 
    101 secret_usage() {
    102 	cat <<-EOF
    103 secret [command] [command-arguments...]
    104     Replacement to pass(1) based on reop(1)
    105 
    106 secret init
    107     Initializes secret keys and git storage repo.
    108 
    109 secret ls [arguments...]
    110     List the entries. Passes arguments to find(1).
    111 secret tree [arguments...]
    112     Same as ‘secret ls’ but outputs via tree(1).
    113 secret read <entry>
    114     Read a secret entry.
    115 secret write <entry>
    116     Write a secret entry.
    117 secret edit <entry>
    118     Wrapper around $EDITOR for easy secret edition.
    119 secret dmenu
    120     dmenu on entries, dmenu for a passphrase, read secret, pipe to xclip(1).
    121 
    122 secret ls-oath [arguments...]
    123     Same as ‘secret ls’ but limited to oath entries(‘*.oath.reop’).
    124 secret read-oath <entry>
    125     Same as ‘secret read’ but entry content passed to oathtool(1) as arguments.
    126 secret dmenu-oath
    127     Same as ‘secret dmenu’ but ‘secret read-oath’ instead of ‘secret read’.
    128 EOF
    129 
    130 	exit 1
    131 }
    132 
    133 command="$1"
    134 [ "$1" = "" ] && secret_usage "$@"
    135 shift || secret_usage "$@"
    136 
    137 case "$command" in
    138 	init) secret_init "$@" ;;
    139 	ls) secret_list "$@" ;;
    140 	tree) secret_tree "$@" ;;
    141 	read) secret_read "$@" ;;
    142 	write) secret_write "$@" ;;
    143 	edit) secret_edit "$@" ;;
    144 	dmenu) secret_dmenu_read "$@" ;;
    145 
    146 	ls-oath) secret_list_oath "$@" ;;
    147 	read-oath) secret_read_oath "$@" ;;
    148 	dmenu-oath) secret_dmenu_oath "$@" ;;
    149 
    150 	*) secret_usage "$@" ;;
    151 esac