spm

Personal fork of spm (simple password manager)
git clone git@getsh.org:spm.git
Log | Files | Refs | README | LICENSE

commit 604da370ce8131b43bef63483834eb6cb31b13e0
parent 76b0711584e1fdaadf05ff85108f33c20c015bfd
Author: Klemens Nanni <kl3@posteo.org>
Date:   Wed, 25 May 2016 18:34:47 +0200

Rename tpm to spm (simple massword manager)

Diffstat:
M.gitignore | 2+-
MMakefile | 20++++++++++----------
MREADME.md | 24++++++++++++------------
MREADME.pod | 46+++++++++++++++++++++++-----------------------
Aspm.sh | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dtpm.sh | 118-------------------------------------------------------------------------------
6 files changed, 164 insertions(+), 164 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1 +1 @@ -tpm.1 +spm.1 diff --git a/Makefile b/Makefile @@ -18,20 +18,20 @@ PREFIX = /usr/local BINDIR = $(PREFIX)/bin MANDIR = $(PREFIX)/share/man -all: tpm.1 -tpm.1: README.pod - pod2man --section=1 --center="tpm Manual" --name="tpm" \ - --release="tpm $(VERSION)" $< $@ +all: spm.1 +spm.1: README.pod + pod2man --section=1 --center="spm Manual" --name="spm" \ + --release="spm $(VERSION)" $< $@ -install: tpm.1 - install -Dm755 tpm.sh "$(DESTDIR)$(BINDIR)/tpm" - install -Dm644 tpm.1 "$(DESTDIR)$(MANDIR)/man1/tpm.1" +install: spm.1 + install -Dm755 spm.sh "$(DESTDIR)$(BINDIR)/spm" + install -Dm644 spm.1 "$(DESTDIR)$(MANDIR)/man1/spm.1" uninstall: - $(RM) "$(DESTDIR)$(BINDIR)/tpm" \ - "$(DESTDIR)$(MANDIR)/man1/tpm.1" + $(RM) "$(DESTDIR)$(BINDIR)/spm" \ + "$(DESTDIR)$(MANDIR)/man1/spm.1" clean: - $(RM) tpm.1 + $(RM) spm.1 .PHONY: all install uninstall clean diff --git a/README.md b/README.md @@ -1,5 +1,5 @@ -tpm - tiny password manager -=========================== +spm - simple password manager +============================= This is a fork of [nmeum's tpm](https://github.com/nmeum/tpm), I felt like changing things here and there was necessary to finally get the password manager that suits my needs. @@ -15,31 +15,31 @@ From the original project: Create a new entry with a random password using `pwgen`: - $ pwgen -1 | tpm add system/new-user + $ pwgen -1 | spm add system/new-user Create a new entry called *system/root*: - $ tpm add system/root + $ spm add system/root Write your *system/root* password to standard output: - $ tpm show system/root + $ spm show system/root Write the entry's password that matches the given pattern to standard output: - $ tpm show em/r*t - $ tpm show sys*ot - $ tpm show root + $ spm show em/r*t + $ spm show sys*ot + $ spm show root Copy your *system/root* password to the primary selection using `xclip`: - $ tpm show system/root | tr -d '\n' | xclip + $ spm show system/root | tr -d '\n' | xclip List all entries of the group *system*: - $ tpm list system + $ spm list system --- -Also see my aliases in *.sh/tpm* from my [dotfiles](https://notabug.org/kl3/dotfiles) repository for other -examples on how to make tpm even easier to use. +Also see my aliases in *.sh/spm* from my [dotfiles](https://notabug.org/kl3/dotfiles) repository for other +examples on how to make spm even easier to use. diff --git a/README.pod b/README.pod @@ -1,29 +1,29 @@ =head1 NAME -tpm - tiny password manager +spm - simple password manager =head1 SYNOPSIS -B<tpm> I<COMMAND> [I<ENTRY>|I<GROUP>] +B<spm> I<COMMAND> [I<ENTRY>|I<GROUP>] =head1 DESCRIPTION -tpm is a tiny shell script which is heavily inspired and largely +spm is a simple shell script which is heavily inspired and largely compatible with pass(1). Just like pass it uses gpg2(1) to securely -store your passwords, the major difference between pass and tpm is that -the latter is a lot more minimal. Furthermore, tpm is written entirely -in POSIX shell. +store your passwords, the major difference between pass and spm is that +the latter is a lot more minimal. Furthermore, spm is written entirely +in POSIX shell. spm is a fork of tpm(1). -Adding, removing or showing a password is done by invoking tpm with the +Adding, removing or showing a password is done by invoking spm with the I<add>, I<del> or I<show> command respectively followed by a name. -tpm will then prompt for a password or confirmation before it modifies +spm will then prompt for a password or confirmation before it modifies or shows the corresponding entry. When using the I<show> command, globbing is allowed to avoid typing -potentially long entry paths. In case multiple entries match, tpm exits +potentially long entry paths. In case multiple entries match, spm exits without showing any password but a warning instead. -tpm simply stores everything in a directory structure where passwords +spm simply stores everything in a directory structure where passwords correspond to individually PGP encrypted files, optionally residing inside nested subdirectories of arbitrary depth, where any subdirectory can be interpreted as a (sub)group to manage large collections easily. @@ -35,11 +35,11 @@ Using ln(1) entries can be symlinked to indicate multiple accounts or users share the same passphrase or create shortcuts to frequently used entries for example. -tpm I<list> followed by a directory path, that is a group name, lists +spm I<list> followed by a directory path, that is a group name, lists all entries inside the specified group as well as all its subgroups. If not name is given, all entries will be listed. -tpm I<help> prints information about how to use tpm. +spm I<help> prints information about how to use spm. =head1 ENVIRONMENT @@ -47,7 +47,7 @@ tpm I<help> prints information about how to use tpm. =item B<PASSWORD_STORE_DIR> -The storage directory (default: ~/.tpm/). +The storage directory (default: ~/.spm/). =item B<PASSWORD_STORE_KEY> @@ -59,7 +59,7 @@ GPG key to encrypt files with (default: self). =over 4 -=item I<~/.tpm/> +=item I<~/.spm/> The default storage directory. @@ -75,36 +75,36 @@ The standard error is used for diagnostic messages only. =head1 EXIT STATUS -tpm returns 1 if an error occured otherwise 0. +spm returns 1 if an error occured otherwise 0. =head1 EXAMPLES Create a new entry with a random password using pwgen(1): - $ pwgen -1 | tpm add system/new-user + $ pwgen -1 | spm add system/new-user Create a new entry called 'system/root': - $ tpm add system/root + $ spm add system/root Write your 'system/root' password to standard output: - $ tpm show system/root + $ spm show system/root Write the entry's password that matches the given pattern to standard output: - $ tpm show em/r*t - $ tpm show root + $ spm show em/r*t + $ spm show root Copy your 'system/root' password to the clipboard using xclip(1): - $ tpm show system/root | tr -d '\n' | xclip + $ spm show system/root | tr -d '\n' | xclip List all entries of the group 'system': - $ tpm list system + $ spm list system =head1 SEE ALSO -git(1), gpg2(1), ln(1), pwgen(1), xclip(1) +git(1), gpg2(1), ln(1), pwgen(1), tpm(1), xclip(1) diff --git a/spm.sh b/spm.sh @@ -0,0 +1,118 @@ +#!/bin/sh +# Copyright (C) 2013-2015 Sören Tempel +# Copyright (C) 2016 Klemens Nanni <kl3@posteo.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +umask 077 + +## Variables + +GPG_OPTS='--quiet --yes --batch' +STORE_DIR="${PASSWORD_STORE_DIR:-${HOME}/.spm}" + +if [ -z "${PASSWORD_STORE_KEY}" ]; then + GPG_OPTS="${GPG_OPTS} --default-recipient-self" +else + GPG_OPTS="${GPG_OPTS} --recipient ${PASSWORD_STORE_KEY}" +fi + +## Helper + +die() { + printf '%s\n' "${1}" >&1 + exit 1 +} + +readpw() { + if [ -t 0 ]; then + printf '%s' "${1}" + stty -echo + fi + + IFS= read -r "${2}" + [ -t 0 ] && stty echo +} + +## Commands + +add() { + [ -z "${1}" ] && die 'Name must not be empty.' + [ -e "${STORE_DIR}"/"${1}".gpg ] && die 'Entry already exists.' + + readpw "Password for '${1}': " password + [ -t 0 ] && printf '\n' + + [ -z "${password}" ] && die 'No password specified.' + + mkdir -p "$(dirname "${STORE_DIR}"/"${1}".gpg)" + printf '%s\n' "${password}" \ + | gpg2 ${GPG_OPTS} --encrypt --output "${STORE_DIR}"/"${1}".gpg +} + +list() { + [ -d "${STORE_DIR}" ] || mkdir -p "${STORE_DIR}" + + [ -n "${1}" ] && [ ! -d "${STORE_DIR}/${1}" ] \ + && die "No such group. See 'spm list'." + + tree --noreport -l -C -- "${STORE_DIR}/${1}" \ + | sed "1s,${STORE_DIR}/,,; s,.gpg,,g" +} + +del() { + [ -z "${1}" ] && die 'Name must not be empty.' + [ -w "${STORE_DIR}"/"${1}".gpg ] || die 'No such entry.' + + rm -i "${STORE_DIR}"/"${1}".gpg +} + +show() { + [ -z "${1}" ] && die 'Name must not be empty.' + + entry="${STORE_DIR}"/"${1}".gpg + + if [ ! -r "${entry}" ]; then + entry=$(find "${STORE_DIR}" \( -type f -o -type l \) \ + -iwholename "*${1}*".gpg) + + [ -z "${entry}" ] && die 'No such entry.' + + [ "$(printf '%s' "${entry}" | wc -l)" -gt 0 ] \ + && die 'Too ambigious keyword.' + fi + + gpg2 ${GPG_OPTS} --decrypt "${entry}" +} + +## Parse input + +[ ${#} -eq 0 ] || [ ${#} -gt 2 ] \ + && die "Invalid number of arguments. See 'spm help'." + +case "${1}" in + add|del|list|show) + ${1} "${2}" + ;; + help) + cat <<- EOF + USAGE: spm add|del|list|show|help [ENTRY|GROUP] + + See spm(1) for more information. + EOF + ;; + *) + die "Invalid command. See 'spm help'." + ;; +esac diff --git a/tpm.sh b/tpm.sh @@ -1,118 +0,0 @@ -#!/bin/sh -# Copyright (C) 2013-2015 Sören Tempel -# Copyright (C) 2016 Klemens Nanni <kl3@posteo.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -umask 077 - -## Variables - -GPG_OPTS='--quiet --yes --batch' -STORE_DIR="${PASSWORD_STORE_DIR:-${HOME}/.tpm}" - -if [ -z "${PASSWORD_STORE_KEY}" ]; then - GPG_OPTS="${GPG_OPTS} --default-recipient-self" -else - GPG_OPTS="${GPG_OPTS} --recipient ${PASSWORD_STORE_KEY}" -fi - -## Helper - -die() { - printf '%s\n' "${1}" >&1 - exit 1 -} - -readpw() { - if [ -t 0 ]; then - printf '%s' "${1}" - stty -echo - fi - - IFS= read -r "${2}" - [ -t 0 ] && stty echo -} - -## Commands - -add() { - [ -z "${1}" ] && die 'Name must not be empty.' - [ -e "${STORE_DIR}"/"${1}".gpg ] && die 'Entry already exists.' - - readpw "Password for '${1}': " password - [ -t 0 ] && printf '\n' - - [ -z "${password}" ] && die 'No password specified.' - - mkdir -p "$(dirname "${STORE_DIR}"/"${1}".gpg)" - printf '%s\n' "${password}" \ - | gpg2 ${GPG_OPTS} --encrypt --output "${STORE_DIR}"/"${1}".gpg -} - -list() { - [ -d "${STORE_DIR}" ] || mkdir -p "${STORE_DIR}" - - [ -n "${1}" ] && [ ! -d "${STORE_DIR}/${1}" ] \ - && die "No such group. See 'tpm list'." - - tree --noreport -l -C -- "${STORE_DIR}/${1}" \ - | sed "1s,${STORE_DIR}/,,; s,.gpg,,g" -} - -del() { - [ -z "${1}" ] && die 'Name must not be empty.' - [ -w "${STORE_DIR}"/"${1}".gpg ] || die 'No such entry.' - - rm -i "${STORE_DIR}"/"${1}".gpg -} - -show() { - [ -z "${1}" ] && die 'Name must not be empty.' - - entry="${STORE_DIR}"/"${1}".gpg - - if [ ! -r "${entry}" ]; then - entry=$(find "${STORE_DIR}" \( -type f -o -type l \) \ - -iwholename "*${1}*".gpg) - - [ -z "${entry}" ] && die 'No such entry.' - - [ "$(printf '%s' "${entry}" | wc -l)" -gt 0 ] \ - && die 'Too ambigious keyword.' - fi - - gpg2 ${GPG_OPTS} --decrypt "${entry}" -} - -## Parse input - -[ ${#} -eq 0 ] || [ ${#} -gt 2 ] \ - && die "Invalid number of arguments. See 'tpm help'." - -case "${1}" in - add|del|list|show) - ${1} "${2}" - ;; - help) - cat <<- EOF - USAGE: tpm add|del|list|show|help [ENTRY|GROUP] - - See tpm(1) for more information. - EOF - ;; - *) - die "Invalid command. See 'tpm help'." - ;; -esac