diff --git a/bin/Makefile b/bin/Makefile index 9026d2f..364366c 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -14,7 +14,8 @@ PREFIX= $(HOME) BIN= ZZZ browser credentials fetch imgresize invidious rfcopen screenshot \ - tor-browser w3m-copy-link xsekrit + sekrit tor-browser w3m-copy-link xsekrit +MAN1= sekrit.1 all: $(BIN) @@ -25,6 +26,9 @@ install: all mkdir -p $(PREFIX)/bin cp -f $(BIN) $(PREFIX)/bin cd $(PREFIX)/bin && chmod 555 $(BIN) + mkdir -p $(PREFIX)/share/man/man1 + cp -f $(MAN1) $(PREFIX)/share/man/man1 + cd $(PREFIX)/share/man/man1 && chmod 444 $(MAN1) uninstall: cd $(PREFIX)/bin && rm -f $(BIN) diff --git a/bin/sekrit.1 b/bin/sekrit.1 new file mode 100644 index 0000000..1632bf9 --- /dev/null +++ b/bin/sekrit.1 @@ -0,0 +1,138 @@ +.\" +.\" sekrit.1 +.\" Written in 2018 by Lucas +.\" CC0 1.0 Universal/Public domain - No rights reserved +.\" +.\" To the extent possible under law, the author(s) have dedicated all +.\" copyright and related and neighboring rights to this software to the +.\" public domain worldwide. This software is distributed without any +.\" warranty. You should have received a copy of the CC0 Public Domain +.\" Dedication along with this software. If not, see +.\" . +.\" +.Dd September 25, 2018 +.Dt SEKRIT 1 +.Os +.Sh NAME +.Nm sekrit +.Nd Secret files manager +.Sh SYNOPSIS +.Nm sekrit +.Cm add +.Ar key +.Op Ar value ... +.Nm sekrit +.Cm gen +.Op Fl l Ar length +.Op Ar chars +.Nm sekrit +.Cm get +.Ar key +.Nm sekrit +.Cm has +.Ar key +.Nm sekrit +.Cm ls +.Op Ar keys ... +.Sh DESCRIPTION +.Nm +is a small shell script for managing encrypted files. +It leverages +.Xr gpg2 1 +to create and read encrypted files, +and can generate random data to populate them. +.Pp +Because of this, +.Nm +can be used as an account credentials manager, +or as a general-purpose key-value store of encrypted information. +.Bl -tag -width Ds +.It Nm Cm add Ar key Op Ar value ... +Adds a value to +.Ar key . +.Ar value +is inserted as is, without any extra modifications. +If no +.Ar value +is specified on command line, +.Cm add +will read the value from standard input. +.Cm add +will fail if +.Ar key +already has a value. +.It Nm Cm gen Oo Fl l Ar length Oc Op Ar chars +Outputs a randomly generated sequence. +The generated sequence consist of characters +.Ar chars . +Defaults to +.Ar +/0-9A-Za-z . +If +.Fl l Ar length +is provided, the randomly generated sequence will be +.Ar length +characters long. +Defaults to 43. +.It Nm Cm get Ar key +Decrypts the value associated with +.Ar key +and prints it to standard output. +Fails if +.Ar key +doesn't have a value associated with it. +.It Nm Cm has Ar key +Returns success if +.Ar key +has a value associated with it. +Fails otherwise. +.It Nm Cm ls Op Ar keys ... +For each +.Ar key +given as argument, +list all the registered keys under that hierarchy. +If no +.Ar key +is given, list all the registeres keys. +.El +.Sh ENVIRONMENT +.Bl -tag -width SEKRIT_GPG_ID +.It Ev SEKRIT_DIR +Secret files base directory. +Defaults to +.Pa ~/keep/sekrit . +.It Ev SEKRIT_GPG_ID +The recipient to whom encrypt the files. +Defaults to +.Ar myself . +.El +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +To use +.Nm +as an account credentials manager, you can run +.Bd -literal -offset indent +sekrit add accounts/example.com/user myuser +sekrit gen accounts/example.com/pass +.Ed +.Pp +Then, to retrieve credentials to login as +.Ar myuser +in +.Ar example.com +you can run +.Bd -literal -offset indent +sekrit get accounts/example.com/user | xclip -l 1 -sel clip -q +sekrit get accounts/example.com/pass | xclip -l 1 -sel clip -q +.Ed +.Sh AUTHORS +.An Lucas +.Sh LICENSE +.Nm +is in the public domain. +.Pp +To the extent possible under law, the author(s) have dedicated all +copyright and related and neighboring rights to this software to the +public domain worldwide. +.Pp +.Lk http://creativecommons.org/publicdomain/zero/1.0/ diff --git a/bin/sekrit.sh b/bin/sekrit.sh new file mode 100644 index 0000000..b18d0bd --- /dev/null +++ b/bin/sekrit.sh @@ -0,0 +1,167 @@ +#!/bin/sh +# sekrit +# Written in 2018-2019 by Lucas +# CC0 1.0 Universal/Public domain - No rights reserved +# +# To the extent possible under law, the author(s) have dedicated all +# copyright and related and neighboring rights to this software to the +# public domain worldwide. This software is distributed without any +# warranty. You should have received a copy of the CC0 Public Domain +# Dedication along with this software. If not, see +# . + +# sekrit is a relatively small shell script for writing and reading +# encrypted files, aimed to deal mostly with accounts credentials, but +# general enough to deal with any content. It can populate each key +# with random data or with fixed data, reading either command-line +# arguments or stdin. +# +# To be used as a password manager, it's recommended to pair it with +# xclip(1). For example, for username, password and optional second +# factor: +# +# sekrit get account/user | xclip -r -l 1 -sel clip -q +# sekrit get account/pass | xclip -r -l 1 -sel clip -q +# sekrit has account/2fa && sekrit get account/2fa \ +# | $program_for_totp | xclip -r -l 1 -sel clip -q + +usage() +{ + cat - <<. >&2 +Usage: + ${0##*/} add key [value ...] + ${0##*/} gen [-l length] [chars] + ${0##*/} get key + ${0##*/} has key + ${0##*/} ls [keys ...] + +If no value was provided on command line, add reads from stdin. +. + exit 1 +} + +err() +{ + printf "%s: %s\n" "${0##*/}" "$*" >&2 + exit 1 +} + +check_key() +{ + [ "$1" = "${1%/}" ] || err "Key can not end in a slash." +} + +to_number() +{ + printf "%u" "$*" 2>/dev/null +} + +sekrit_add() +{ + [ $# -eq 1 ] && [ -n "$1" ] || usage + key=$1 + check_key "$key" + shift + + f=$SEKRIT_DIR/$key.gpg + mkdir -p "${f%/*}" + + [ -f "$f" ] && err "Key \"$key\" already exists." + + if [ $# -ne 0 ]; then + printf "%s\n" "$*" + else + cat - + fi | gpg2 -qae -r "$SEKRIT_GPG_ID" >"$f" + # make it read-only + chmod -- 400 "$f" +} + +sekrit_gen() +{ + len=43 + OPTIND=1 + while getopts l: flag; do + case "$flag" in + l) len=$(to_number "$OPTARG") || + err "Invalid password length." + ;; + [?]) usage + ;; + esac + done + shift $(($OPTIND - 1)) + + [ $# -le 1 ] || usage + + chars=+/0-9A-Za-z + if [ $# -eq 1 ]; then + [ -n "$1" ] || usage + chars=$1 + fi + + tr -cd -- "$chars" /dev/null && + printf "\n" +} + +sekrit_get() +{ + [ $# -eq 1 ] || usage + key=$1 + check_key "$1" + shift + + f=$SEKRIT_DIR/$key.gpg + [ ! -f "$f" ] && err "No data for key \"$key\"." + gpg2 -qd "$f" +} + +sekrit_has() +{ + [ $# -eq 1 ] || usage + key=$1 + check_key "$1" + shift + + [ -f "$SEKRIT_DIR/$key.gpg" ] +} + +ls_key() +{ + d=$SEKRIT_DIR$1 + find "$d" -type f -name "*.gpg" | sort | cut -c $((${#d} + 1))- | + sed "s/\.gpg$//" +} + +sekrit_ls() +{ + if [ $# -eq 0 ]; then + ls_key / + else + for key; do + printf "%s:\n" "$key" + ls_key /"$key"/ | sed "s/^/ /" + printf "\n" + done + fi +} + +set -e + +[ $# -ge 1 ] || usage +cmd=$1 +shift + +umask 077 +: ${SEKRIT_DIR:=~/keep/sekrit} +: ${SEKRIT_GPG_ID:=myself} +mkdir -p "$SEKRIT_DIR" + +case "$cmd" in +add) sekrit_add "$@";; +gen) sekrit_gen "$@" ;; +get) sekrit_get "$@" ;; +has) sekrit_has "$@" ;; +ls) sekrit_ls "$@" ;; +*) usage ;; +esac