1 b93a49bc 2015-03-13 soeren+gi #!/bin/sh
2 f522506c 2016-08-16 soeren+gi # Copyright (C) 2013-2016 Sören Tempel
3 080fbd05 2017-07-02 xhr # Copyright (C) 2017 Matthias Schmidt
5 666022b7 2015-01-02 soeren+gi # This program is free software: you can redistribute it and/or modify
6 666022b7 2015-01-02 soeren+gi # it under the terms of the GNU General Public License as published by
7 666022b7 2015-01-02 soeren+gi # the Free Software Foundation, either version 3 of the License, or
8 666022b7 2015-01-02 soeren+gi # (at your option) any later version.
10 666022b7 2015-01-02 soeren+gi # This program is distributed in the hope that it will be useful,
11 666022b7 2015-01-02 soeren+gi # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 666022b7 2015-01-02 soeren+gi # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 666022b7 2015-01-02 soeren+gi # GNU General Public License for more details.
15 666022b7 2015-01-02 soeren+gi # You should have received a copy of the GNU General Public License
16 666022b7 2015-01-02 soeren+gi # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 99d77107 2013-11-15 git-nmeum umask 077
23 9f54b1bb 2017-07-04 xhr # Variables r/w
26 080fbd05 2017-07-02 xhr GPG_OPTS="--quiet --yes"
28 ad8e14c1 2017-07-04 xhr TMPDIR="/tmp"
30 b2af058c 2017-07-04 xhr PASSWORD_STORE_KEY=${PASSWORD_STORE_KEY:-""}
31 1dcc939a 2017-07-04 xhr EDITOR=${EDITOR:-""}
32 a17f5db3 2020-10-05 noreply TOPTS="-C"
35 9f54b1bb 2017-07-04 xhr # Variables r/o
38 9f54b1bb 2017-07-04 xhr readonly STORE_DIR="${HOME}/.password-store"
39 bd3332af 2017-07-04 xhr readonly PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
42 98cc485f 2013-11-14 git-nmeum # Helper
45 9f54b1bb 2017-07-04 xhr if [ -r "${STORE_DIR}/.gpg-id" ] && [ -z "${PASSWORD_STORE_KEY}" ]; then
46 9f54b1bb 2017-07-04 xhr read -r PASSWORD_STORE_KEY < "${STORE_DIR}/.gpg-id"
50 c1cdc08b 2017-07-03 xhr echo "Usage: $(basename $0) [option] [argument]"
52 c1cdc08b 2017-07-03 xhr echo "Option can be one of the following"
54 c1cdc08b 2017-07-03 xhr echo " show <entry> Shows password <entry>"
55 a17f5db3 2020-10-05 noreply echo " insert <entry> Inserts new <entry>"
56 c1cdc08b 2017-07-03 xhr echo " find <entry> Searches for <entry>"
57 c1cdc08b 2017-07-03 xhr echo " rm <entry> Removes <entry>"
59 c1cdc08b 2017-07-03 xhr echo "If you do not specify an option, all entries will be shown"
63 98cc485f 2013-11-14 git-nmeum abort() {
64 c1fcb205 2017-07-03 xhr echo "$(basename ${0}): ${1}" 1>&2
70 89fd4ad2 2017-07-04 xhr if [ -z "$(which gpg2 2> /dev/null)" ]; then
71 89fd4ad2 2017-07-04 xhr if [ -z "$(which gpg 2> /dev/null)" ]; then
72 ae641176 2017-07-04 xhr abort "gpg or gpg2 not found. Please install."
78 fec3955f 2017-07-03 xhr if [ -n "${PASSWORD_STORE_KEY}" ]; then
79 ae641176 2017-07-04 xhr ${GPGB} ${GPG_OPTS} --recipient "${PASSWORD_STORE_KEY}" "$@"
81 ae641176 2017-07-04 xhr ${GPGB} ${GPG_OPTS} --default-recipient-self "$@"
87 b93a49bc 2015-03-13 soeren+gi readpw() {
88 bad9c329 2015-05-26 soeren+gi if [ -t 0 ]; then
89 d4c9e192 2015-06-27 soeren+gi printf "%s" "${1}"
90 bad9c329 2015-05-26 soeren+gi stty -echo
93 b93a49bc 2015-03-13 soeren+gi IFS= read -r "${2}"
94 bad9c329 2015-05-26 soeren+gi [ -t 0 ] && stty echo
97 dc1ea6be 2017-07-02 xhr entry_exists() {
98 dc1ea6be 2017-07-02 xhr local _entry_name="${1}"
99 dc1ea6be 2017-07-02 xhr local _entry_path="${STORE_DIR}/${_entry_name}.gpg"
101 179af88f 2017-07-03 xhr if [ ! -f "${_entry_path}" ]; then
102 dc1ea6be 2017-07-02 xhr abort "The requested entry doesn't exist."
106 1add099f 2017-07-03 xhr choose_tmp() {
107 1add099f 2017-07-03 xhr # Create the temp file on a shared memory fs if available
108 1add099f 2017-07-03 xhr if [ -d "/dev/shm" -a -k "/dev/shm" ]; then
109 1add099f 2017-07-03 xhr TMPDIR="/dev/shm"
113 fea25380 2017-07-03 xhr nuke_file() {
114 fea25380 2017-07-03 xhr OSV=$(uname -s)
116 fea25380 2017-07-03 xhr if [ -n ${OSV} ]; then
117 fea25380 2017-07-03 xhr if [ "${OSV}" = "Linux" ]; then
118 01452577 2020-10-05 thexhr if [[ -z "$(which shred 2> /dev/null)" ]]; then
119 01452577 2020-10-05 thexhr echo "Cannot find shred. Using rm"
122 fea25380 2017-07-03 xhr NUKE="shred -u"
123 fea25380 2017-07-03 xhr elif [ "${OSV}" = "OpenBSD" -o "${OSV}" = "FreeBSD" -o "${OSV}" = "DragonFly" -o "${OSV}" = "NetBSD" ]; then
124 fea25380 2017-07-03 xhr NUKE="rm -P"
130 98cc485f 2013-11-14 git-nmeum # Commands
133 98cc485f 2013-11-14 git-nmeum show() {
134 54d8a6df 2017-07-02 xhr local _entry_name="${1}"
135 54d8a6df 2017-07-02 xhr local _entry_path="${STORE_DIR}/${_entry_name}.gpg"
137 54d8a6df 2017-07-02 xhr if [ -z "${_entry_name}" ]; then
138 54d8a6df 2017-07-02 xhr abort "show needs an argument"
141 54d8a6df 2017-07-02 xhr entry_exists ${_entry_name}
143 b2af058c 2017-07-04 xhr mygpg --decrypt "${_entry_path}" || abort "Cannot open entry"
146 98cc485f 2013-11-14 git-nmeum insert() {
147 54d8a6df 2017-07-02 xhr local _entry_name="${1}"
148 54d8a6df 2017-07-02 xhr local _entry_path="${STORE_DIR}/${_entry_name}.gpg"
150 54d8a6df 2017-07-02 xhr if [ -z "${_entry_name}" ]; then
151 a5472807 2017-07-02 xhr abort "insert needs an argument"
154 179af88f 2017-07-03 xhr if [ -f "${_entry_path}" ]; then
155 a5472807 2017-07-02 xhr abort "This entry already exists"
158 a3e9af3e 2015-09-24 soeren+gi password=""
159 54d8a6df 2017-07-02 xhr readpw "Password for '${_entry_name}': " password
160 a3e9af3e 2015-09-24 soeren+gi if [ -t 0 ]; then
161 a3e9af3e 2015-09-24 soeren+gi printf "\n"
164 b93a49bc 2015-03-13 soeren+gi if [ -z "${password}" ]; then
165 98cc485f 2013-11-14 git-nmeum abort "You didn't specify a password."
168 fd0070ba 2017-07-03 xhr command mkdir -p "${_entry_path%/*}" || abort "Cannot create password entry"
169 080fbd05 2017-07-02 xhr printf '%s\n' "${password}" | mygpg --encrypt \
170 54d8a6df 2017-07-02 xhr --output "${_entry_path}"
173 080fbd05 2017-07-02 xhr show_all() {
174 a17f5db3 2020-10-05 noreply ${TREE} -l -x --noreport $TOPTS "${STORE_DIR}" -P "*.gpg" --prune | sed 's/\.gpg//'
177 080fbd05 2017-07-02 xhr remove_entry() {
178 0dd6aa62 2017-07-03 xhr local _entry_name="${1}" _answer
180 aa36579a 2017-07-03 xhr [ -z "${_entry_name}" ] && abort "rm needs an argument"
182 54d8a6df 2017-07-02 xhr entry_exists ${_entry_name}
184 83a735d6 2020-10-05 thexhr nuke_file
186 e2ddb685 2017-07-04 xhr echo -n "$0: Really remove ${_entry_name} [y/N]? "
187 e2ddb685 2017-07-04 xhr read -r _answer
188 0dd6aa62 2017-07-03 xhr case "${_answer}" in
189 0dd6aa62 2017-07-03 xhr [yY]) command ${NUKE} -f "${STORE_DIR}/${_entry_name}.gpg" ;;
194 080fbd05 2017-07-02 xhr find_entry() {
195 080fbd05 2017-07-02 xhr local _entry_name="${1}"
197 aa36579a 2017-07-03 xhr [ -z "${_entry_name}" ] && abort "find needs an argument"
198 a17f5db3 2020-10-05 noreply ${TREE} -l -x --noreport $TOPTS "${STORE_DIR}/" -P "*${_entry_name}*" --prune \
199 e38aa8f0 2017-07-03 xhr --matchdirs --ignore-case | sed 's/\.gpg//'
203 dc1ea6be 2017-07-02 xhr edit_entry() {
204 dc1ea6be 2017-07-02 xhr local _entry_name="${1}" _tmpfile
206 aa36579a 2017-07-03 xhr [ -z "${_entry_name}" ] && abort "edit needs an argument"
208 dc1ea6be 2017-07-02 xhr entry_exists ${_entry_name}
210 83a735d6 2020-10-05 thexhr nuke_file
213 1add099f 2017-07-03 xhr _tmpfile=$(mktemp ${TMPDIR}/tpm.XXXXXXXXXX) || abort "Cannot create temporary file"
214 fea25380 2017-07-03 xhr trap "${NUKE} -f ${_tmpfile}; exit 0" 0 1 2 3 15
216 bd3332af 2017-07-04 xhr mygpg --output ${_tmpfile} --decrypt "${STORE_DIR}/${_entry_name}.gpg" || \
217 bd3332af 2017-07-04 xhr abort "Cannot edit file"
219 aa36579a 2017-07-03 xhr if [ -n "${EDITOR}" ]; then
220 fd0070ba 2017-07-03 xhr ${EDITOR} ${_tmpfile} || abort "Cannot open file using \$EDITOR"
222 fd0070ba 2017-07-03 xhr vi ${_tmpfile} || abort "Neither vi or an editor in \$EDITOR was found"
225 bd3332af 2017-07-04 xhr mygpg --output "${STORE_DIR}/${_entry_name}.gpg" --encrypt ${_tmpfile} || \
226 a17f5db3 2020-10-05 noreply abort "Cannot re-encrypt temporary file"
228 1add099f 2017-07-03 xhr # If the file is there, remove it
229 fea25380 2017-07-03 xhr [ -e "${_tmpfile}" ] && ${NUKE} -f "${_tmpfile}"
233 98cc485f 2013-11-14 git-nmeum # Parse input
237 8779f26f 2017-07-03 xhr [ "${1}" != "insert" -a ! -d "${STORE_DIR}" ] && abort "Password directory does not exist."
239 a17f5db3 2020-10-05 noreply # Disable colors for colortree if NO_COLOR is set
240 a17f5db3 2020-10-05 noreply [[ -n $NO_COLOR ]] && TOPTS="-n"
243 a80d4dc9 2017-07-08 xhr if [ ! -z "$(which colortree 2> /dev/null)" ]; then
244 598a12fe 2017-07-03 xhr TREE=colortree
245 a80d4dc9 2017-07-08 xhr elif [ ! -z "$(which tree 2> /dev/null)" ]; then
248 598a12fe 2017-07-03 xhr abort "tpm needs tree or colortree to run. Please install"
251 080fbd05 2017-07-02 xhr if [ $# -eq 0 ]; then
254 080fbd05 2017-07-02 xhr elif [ $# -gt 2 ]; then
255 1517b3d4 2016-05-24 soeren+gi abort "tpm doesn't accept more than two arguments."
258 ffd5a3e7 2015-10-12 soeren+gi case "${1}" in
259 ffd5a3e7 2015-10-12 soeren+gi "show") show "${2}" ;;
260 ffd5a3e7 2015-10-12 soeren+gi "insert") insert "${2}" ;;
261 080fbd05 2017-07-02 xhr "find") find_entry "${2}" ;;
262 080fbd05 2017-07-02 xhr "rm") remove_entry "${2}" ;;
263 dc1ea6be 2017-07-02 xhr "edit") edit_entry "${2}" ;;
264 c1cdc08b 2017-07-03 xhr "help") usage ;;
265 080fbd05 2017-07-02 xhr *) show "${1}" ;;