spm (2381B)
1 #!/bin/sh 2 # Copyright (C) 2013-2016 Sören Tempel 3 # Copyright (C) 2016, 2017 Klemens Nanni <kl3@posteo.org> 4 # 5 # This program is free software: you can redistribute it and/or modify 6 # it under the terms of the GNU General Public License as published by 7 # the Free Software Foundation, either version 3 of the License, or 8 # (at your option) any later version. 9 # 10 # This program is distributed in the hope that it will be useful, 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 # GNU General Public License for more details. 14 # 15 # You should have received a copy of the GNU General Public License 16 # along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 set -u 19 umask u=rwx,go= 20 21 ## Variables 22 GPG_OPTS='--quiet --yes --batch' 23 STORE_DIR="${PASSWORD_STORE_DIR:-${HOME}/.spm}" 24 25 ## Helper 26 die() { 27 echo "$@" >&2 28 exit 1 29 } 30 31 check() { 32 [ -n "${entry}" ] || die "spm: no such entry" 33 34 [ $(printf '%s' "${entry}" | wc -l) -eq 0 ] || 35 die "spm: ambigious expression" 36 } 37 38 gpg() { 39 if [ -z "${PASSWORD_STORE_KEY}" ]; then 40 gpg2 ${GPG_OPTS} --default-recipient-self "${@}" 41 else 42 gpg2 ${GPG_OPTS} --recipient "${PASSWORD_STORE_KEY}" "${@}" 43 fi 44 } 45 46 readpw() { 47 [ -t 0 ] && stty -echo && printf '%s' "${1}" 48 IFS= read -r "${2}" 49 [ -t 0 ] && stty echo 50 [ -z "${2}" ] && die "spm: empty password" 51 } 52 53 find() { 54 command find "${STORE_DIR}" -name "*.gpg" -type f -o -type l | grep -ie "${1}" 55 } 56 57 ## Commands 58 add() { 59 [ -e "${STORE_DIR}"/"${1}" ] && die "spm: entry already exists" 60 61 password= 62 readpw "Password for '${1}': " password 63 [ -t 0 ] && printf '\n' 64 65 group="${1%/*}" 66 [ "${group}" = "${1}" ] && group= 67 68 mkdir -p "${STORE_DIR}"/"${group}" && 69 printf '%s\n' "${password}" | 70 gpg --encrypt --output "${STORE_DIR}"/"${1}.gpg" 71 } 72 73 list() { 74 [ -d "${STORE_DIR}"/"${1:-}" ] || die "spm list: no such group" 75 find "${STORE_DIR}"/"${1:-}" 76 } 77 78 del() { 79 entry=$(find "${1}" | head -n2) 80 check; command rm "${entry}" && printf '\n' 81 } 82 83 search() { 84 find "${1}" 85 } 86 87 show() { 88 entry=$(find "${1}" | head -n2) 89 check; gpg --decrypt "${entry}" 90 } 91 92 ## Parse input 93 [ $# -gt 2 ] && die "spm: wrong number of arguments" 94 95 case "${1}" in 96 add|del|search|show) 97 [ -z "${2:-}" ] && die "spm: empty name" 98 ${1} "${2}" 99 ;; 100 list) 101 list "${2:-.}" 102 ;; 103 *) 104 die "usage: ${0} add|del|list|search|show [[group/]entry|expression]" 105 ;; 106 esac