logo

secret

Replacement to pass(1) based on reop(1)
commit: 6ecd112962c6a86e5c92ee990b8086071f5ecb61
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sun, 24 May 2020 15:43:24 +0200

Initial Commit

Diffstat:

ACOPYING13+++++++++++++
AREADME19+++++++++++++++++++
Apass2secret43+++++++++++++++++++++++++++++++++++++++++++
Asecret106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 181 insertions(+), 0 deletions(-)

diff --git a/COPYING b/COPYING @@ -0,0 +1,13 @@ +Copyright (c) 2020, Haelwenn (lanodan) Monnier <contact+secret@hacktivis.me> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/README b/README @@ -0,0 +1,19 @@ +## Secret + +- No audit done +- No warranty is given +- Tagged release when it's frozen enough +- ISC Licensed + +This is a replacment to pass(1), the Unix password manager. It is backed by +reop(1) instead of GnuPG(1). + +## Dependencies +- POSIX Shell +- reop (and so libsodium) <https://flak.tedunangst.com/post/reop> +- dmenu (optionnal) <https://tools.suckless.org/dmenu/> +- oathtool (optionnal) <http://www.nongnu.org/oath-toolkit/> + +## Tested platforms +- System: GNU/Linux (gentoo) +- Shell: mksh diff --git a/pass2secret b/pass2secret @@ -0,0 +1,43 @@ +#!/bin/sh +# pass2secret: Converts pass(1) storage to secret(1) storage +# Copyright 2020 Haelwenn (lanodan) Monnier <contact+secret@hacktivis.me> +# SPDX-License-Identifier: ISC +OLDPWD="$PWD" +workdir="$HOME/.secret-storage/" +PASSWORD_STORE_DIR="${PASSWORD_STORE_DIR:-$HOME/.password-store}" +export SECRET_FILE="/dev/shm/pass2secret" + +set -e + +touch "$SECRET_FILE" +chmod 700 "$SECRET_FILE" + +echo -n "Passphrase: " +read passphrase +echo + +# Create needed directories +cd "$workdir" +(cd "$PASSWORD_STORE_DIR" && find -type d | grep -v ./.git) | xargs mkdir -p + +# Convert each entry +( + cd "$PASSWORD_STORE_DIR" + find -type f -name '*.gpg' | sed -e 's;\.gpg$;;' -e 's;^./;;' +) | while read entry +do + ( pass "$entry" && echo ) > "$SECRET_FILE" + if [[ ! -f "$workdir/$entry" ]]; then secret write "$entry" <<<"$passphrase"; fi + if [[ ! -f "$workdir/$entry.oath" ]] && grep "^otpauth" "$SECRET_FILE"; then + grep "^otpauth" "$SECRET_FILE" | sed \ + -e 's;^otpauth://totp/totp-secret?secret=q;;' \ + -e 's;^;--base32 ;' \ + | secret write "${entry}.oath" <<<"$passphrase" + fi + else + echo "following entry exists, ignoring: $workdir/$entry" + fi +done + +shred -u "$secret_file" +cd "$OLDPWD" diff --git a/secret b/secret @@ -0,0 +1,106 @@ +#!/bin/sh +# secret: Replacement to pass(1) based on reop(1) +# Copyright 2020 Haelwenn (lanodan) Monnier <contact+secret@hacktivis.me> +# SPDX-License-Identifier: ISC +workdir="$HOME/.secret-storage" + +set -e + +secret_list() { + ( cd "$workdir" && find . -type f -name '*.reop' "$@" | sed -e 's;^./;;' -e 's;.reop$;;') | sort | column +} + +secret_list_oath() { + secret_list -name '*.oath.reop' "$@" +} + +tree() { + secret_list "$@" | tree --fromfile +} + +secret_read() { + entry="$*" + target="${SECRET_FILE:--}" + + reop -D -m "$target" -x "${workdir}/${entry}.reop" +} + +secret_write() { + entry="$*" + target="${SECRET_FILE:--}" + + reop -E -m "$target" -x "${workdir}/${entry}.reop" + + if test -f "${workdir}/.git/HEAD" + then + git add "${workdir}/${entry}.reop" + git commit -m "${entry}: encrypt auto-update" + if [ "$(git remote show -n)" != "" ]; then git push; fi + else + echo "No git repository in ‘$workdir’, consider creating one" + fi +} + +secret_read_oath() { + secret_read "$@" | read -r secret + oathtool --totp --base32 "$secret" +} + +secret_dmenu() { + echo | dmenu -nb '#000' -nf '#000' -p "Passphrase: " +} + +secret_dmenu_oath() { + entry="$(secret_find -name '*.oath.reop' | dmenu -i)" + oathtool $(secret_menu | secret_read "$entry") | xclip -i -selection clipboard +} + +secret_dmenu_read() { + entry="$(secret_find | dmenu -i)" + secret_menu | secret_read "$entry" | xclip -i -selection clipboard +} + +secret_usage() { + cat <<-EOF +secret [command] [command-arguments...] + Replacement to pass(1) based on reop(1) + +secret ls [arguments...] + List the entries. Passes arguments to find(1), ls(1)-style output. +secret tree [arguments...] + Same as ‘secret ls’ but outputs via tree(1). +secret read <entry> + Read a secret entry. +secret write <entry> + Write a secret entry. +secret dmenu + dmenu on entries, dmenu for a passphrase, read secret, pipe to xclip(1). + +secret ls-oath [arguments...] + Same as ‘secret ls’ but limited to oath entries(‘*.oath.reop’). +secret read-oath <entry> + Same as ‘secret read’ but entry content passed to oathtool(1) as arguments. +secret dmenu-oath + Same as ‘secret dmenu’ but ‘secret read-oath’ instead of ‘secret read’. +EOF + + exit 1 +} + +command="$1" +[ "$1" = "" ] && secret_usage "$@" +shift || secret_usage "$@" + +case "$command" in + ls) secret_list "$@" ;; + tree) secret_tree "$@" ;; + read) secret_read "$@" ;; + write) secret_write "$@" ;; + dmenu) secret_dmenu_read "$@" ;; + + ls-oath) secret_list_oath "$@" ;; + read-oath) secret_read_oath "$@" ;; + dmenu-oath) secret_dmenu_oath "$@" ;; + + *) secret_usage "$@" ;; +esac