commit a8d0411a61ac3a8045de370ed346edf923bc85fb
parent 55fc794cac34496fb5f1ba9d0824683ce976a23d
Author: Nihal Jere <nihal@nihaljere.xyz>
Date: Tue, 7 Sep 2021 13:02:47 -0500
rename npwm to npm
Diffstat:
A | npm | | | 246 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | npwm | | | 232 | ------------------------------------------------------------------------------- |
2 files changed, 246 insertions(+), 232 deletions(-)
diff --git a/npm b/npm
@@ -0,0 +1,246 @@
+#!/bin/sh
+#
+# pash - simple password manager.
+
+core="/home/nihal/projects/npm/npm-core"
+npmc="/home/nihal/projects/npm/npmc"
+
+pw_add() {
+ name=$1
+
+ if yn "Generate a password?"; then
+ # Generate a password by reading '/dev/urandom' with the
+ # 'tr' command to translate the random bytes into a
+ # configurable character set.
+ #
+ # The 'dd' command is then used to read only the desired
+ # password length.
+ #
+ # Regarding usage of '/dev/urandom' instead of '/dev/random'.
+ # See: https://www.2uo.de/myths-about-urandom
+ pass=$(LC_ALL=C tr -dc "${PASH_PATTERN:-_A-Z-a-z-0-9}" < /dev/urandom |
+ dd ibs=1 obs=1 count="${PASH_LENGTH:-50}" 2>/dev/null)
+
+ else
+ # 'sread()' is a simple wrapper function around 'read'
+ # to prevent user input from being printed to the terminal.
+ sread pass "Enter password"
+ sread pass2 "Enter password (again)"
+
+ # Disable this check as we dynamically populate the two
+ # passwords using the 'sread()' function.
+ # shellcheck disable=2154
+ [ "$pass" = "$pass2" ] || die "Passwords do not match"
+ fi
+
+ [ "$pass" ] || die "Failed to generate a password"
+
+ # Mimic the use of an array for storing arguments by... using
+ # the function's argument list. This is very apt isn't it?
+ if [ "$PASH_KEYID" ]; then
+ set -- --trust-model always -aer "$PASH_KEYID"
+ else
+ set -- -c
+ fi
+
+ # Use 'gpg' to store the password in an encrypted file.
+ # A heredoc is used here instead of a 'printf' to avoid
+ # leaking the password through the '/proc' filesystem.
+ #
+ # Heredocs are sometimes implemented via temporary files,
+ # however this is typically done using 'mkstemp()' which
+ # is more secure than '/proc'.
+ printf "got here: %s\n" "$name"
+ "$core" -e > "$name.npm" <<-EOF && \
+ printf '%s\n' "Saved '$name' to the store."
+ $(echo "" | bemenu -x -p "Passphrase:")
+ $pass
+ EOF
+ printf "got here2\n"
+}
+
+pw_del() {
+ yn "Delete pass file '$1'?" && {
+ rm -f "$1.npm"
+ rmdir -p "${1%/*}" 2>/dev/null
+ }
+}
+
+pw_show() {
+ "$npmc" "$1.npm"
+}
+
+pw_copy() {
+ # Disable warning against word-splitting as it is safe
+ # and intentional (globbing is disabled).
+ # shellcheck disable=2086
+ : "${PASH_CLIP:=xclip -sel c}"
+
+ # Wait in the background for the password timeout and
+ # clear the clipboard when the timer runs out.
+ #
+ # If the 'sleep' fails, kill the script. This is the
+ # simplest method of aborting from a subshell.
+ [ "$PASH_TIMEOUT" != off ] && {
+ printf 'Clearing clipboard in "%s" seconds.\n' "${PASH_TIMEOUT:=15}"
+
+ sleep "$PASH_TIMEOUT" || kill 0
+ $PASH_CLIP </dev/null
+ } &
+
+ pw_show "$1" | $PASH_CLIP
+}
+
+pw_list() {
+ find . -type f -name \*.npm | sed 's/..//;s/\.npm$//'
+}
+
+pw_tree() {
+ command -v tree >/dev/null 2>&1 ||
+ die "'tree' command not found"
+
+ tree --noreport | sed 's/\.npm$//'
+}
+
+yn() {
+ printf '%s [y/n]: ' "$1"
+
+ # Enable raw input to allow for a single byte to be read from
+ # stdin without needing to wait for the user to press Return.
+ stty -icanon
+
+ # Read a single byte from stdin using 'dd'. POSIX 'read' has
+ # no support for single/'N' byte based input from the user.
+ answer=$(dd ibs=1 count=1 2>/dev/null)
+
+ # Disable raw input, leaving the terminal how we *should*
+ # have found it.
+ stty icanon
+
+ printf '\n'
+
+ # Handle the answer here directly, enabling this function's
+ # return status to be used in place of checking for '[yY]'
+ # throughout this program.
+ glob "$answer" '[yY]'
+}
+
+sread() {
+ printf '%s: ' "$2"
+
+ # Disable terminal printing while the user inputs their
+ # password. POSIX 'read' has no '-s' flag which would
+ # effectively do the same thing.
+ stty -echo
+ read -r "$1"
+ stty echo
+
+ printf '\n'
+}
+
+glob() {
+ # This is a simple wrapper around a case statement to allow
+ # for simple string comparisons against globs.
+ #
+ # Example: if glob "Hello World" '* World'; then
+ #
+ # Disable this warning as it is the intended behavior.
+ # shellcheck disable=2254
+ case $1 in $2) return 0; esac; return 1
+}
+
+die() {
+ printf 'error: %s.\n' "$1" >&2
+ exit 1
+}
+
+usage() { printf %s "\
+pash 2.3.0 - simple password manager.
+
+=> [a]dd [name] - Create a new password entry.
+=> [c]opy [name] - Copy entry to the clipboard.
+=> [d]el [name] - Delete a password entry.
+=> [l]ist - List all entries.
+=> [s]how [name] - Show password for an entry.
+=> [t]ree - List all entries in a tree.
+
+Using a key pair: export PASH_KEYID=XXXXXXXX
+Password length: export PASH_LENGTH=50
+Password pattern: export PASH_PATTERN=_A-Z-a-z-0-9
+Store location: export PASH_DIR=~/.local/share/pash
+Clipboard tool: export PASH_CLIP='xclip -sel c'
+Clipboard timeout: export PASH_TIMEOUT=15 ('off' to disable)
+"
+exit 1
+}
+
+main() {
+ : "${NPM_DIR:=${XDG_DATA_HOME:=$HOME/.local/share}/npm}"
+
+ [ "$1" = '-?' ] || [ -z "$1" ] &&
+ usage
+
+ # Look for both 'gpg' and 'gpg2',
+ # preferring 'gpg2' if it is available.
+ command -v gpg >/dev/null 2>&1 && gpg=gpg
+ command -v gpg2 >/dev/null 2>&1 && gpg=gpg2
+
+ [ "$gpg" ] ||
+ die "GPG not found"
+
+ mkdir -p "$NPM_DIR" ||
+ die "Couldn't create password directory"
+
+ cd "$NPM_DIR" ||
+ die "Can't access password directory"
+
+ glob "$1" '[acds]*' && [ -z "$2" ] &&
+ die "Missing [name] argument"
+
+ glob "$1" '[cds]*' && [ ! -f "$2.npm" ] &&
+ die "Pass file '$2' doesn't exist"
+
+glob "$1" 'a*' && [ -f "$2.npm" ] &&
+ die "Pass file '$2' already exists"
+
+ glob "$2" '*/*' && glob "$2" '*../*' &&
+ die "Category went out of bounds"
+
+ glob "$2" '/*' &&
+ die "Category can't start with '/'"
+
+ glob "$2" '*/*' && { mkdir -p "${2%/*}" ||
+ die "Couldn't create category '${2%/*}'"; }
+
+ # Set 'GPG_TTY' to the current 'TTY' if it
+ # is unset. Fixes a somewhat rare `gpg` issue.
+ export GPG_TTY=${GPG_TTY:-$(tty)}
+
+ # Restrict permissions of any new files to
+ # only the current user.
+ umask 077
+
+ # Ensure that we leave the terminal in a usable
+ # state on exit or Ctrl+C.
+ trap 'stty echo icanon' INT EXIT
+
+ case $1 in
+ a*) pw_add "$2" ;;
+ c*) pw_copy "$2" ;;
+ d*) pw_del "$2" ;;
+ s*) pw_show "$2" ;;
+ l*) pw_list ;;
+ t*) pw_tree ;;
+ *) usage
+ esac
+}
+
+# Ensure that debug mode is never enabled to
+# prevent the password from leaking.
+set +x
+
+# Ensure that globbing is globally disabled
+# to avoid insecurities with word-splitting.
+set -f
+
+main "$@"
diff --git a/npwm b/npwm
@@ -1,232 +0,0 @@
-#!/bin/sh
-#
-# pash - simple password manager.
-
-pw_add() {
- name=$1
-
- if yn "Generate a password?"; then
- # Generate a password by reading '/dev/urandom' with the
- # 'tr' command to translate the random bytes into a
- # configurable character set.
- #
- # The 'dd' command is then used to read only the desired
- # password length.
- #
- # Regarding usage of '/dev/urandom' instead of '/dev/random'.
- # See: https://www.2uo.de/myths-about-urandom
- pass=$(LC_ALL=C tr -dc "${PASH_PATTERN:-_A-Z-a-z-0-9}" < /dev/urandom |
- dd ibs=1 obs=1 count="${PASH_LENGTH:-50}" 2>/dev/null)
-
- else
- # 'sread()' is a simple wrapper function around 'read'
- # to prevent user input from being printed to the terminal.
- sread pass "Enter password"
- sread pass2 "Enter password (again)"
-
- # Disable this check as we dynamically populate the two
- # passwords using the 'sread()' function.
- # shellcheck disable=2154
- [ "$pass" = "$pass2" ] || die "Passwords do not match"
- fi
-
- [ "$pass" ] || die "Failed to generate a password"
-
- # Use 'gpg' to store the password in an encrypted file.
- # A heredoc is used here instead of a 'printf' to avoid
- # leaking the password through the '/proc' filesystem.
- #
- # Heredocs are sometimes implemented via temporary files,
- # however this is typically done using 'mkstemp()' which
- # is more secure than a leak in '/proc'.
- "$gpg" -o "$name.gpg" <<-EOF &&
- $pass
- EOF
- printf '%s\n' "Saved '$name' to the store."
-}
-
-pw_del() {
- yn "Delete pass file '$1'?" && {
- rm -f "$1.gpg"
-
- # Remove empty parent directories of a password
- # entry. It's fine if this fails as it means that
- # another entry also lives in the same directory.
- rmdir -p "${1%/*}" 2>/dev/null || :
- }
-}
-
-pw_show() {
- "$gpg" -dq "$1.gpg"
-}
-
-pw_copy() {
- # Disable warning against word-splitting as it is safe
- # and intentional (globbing is disabled).
- # shellcheck disable=2086
- : "${PASH_CLIP:=xclip -sel c}"
-
- # Wait in the background for the password timeout and
- # clear the clipboard when the timer runs out.
- #
- # If the 'sleep' fails, kill the script. This is the
- # simplest method of aborting from a subshell.
- [ "$PASH_TIMEOUT" != off ] && {
- printf 'Clearing clipboard in "%s" seconds.\n' "${PASH_TIMEOUT:=15}"
-
- sleep "$PASH_TIMEOUT" || kill 0
- $PASH_CLIP </dev/null
- } &
-
- pw_show "$1" | $PASH_CLIP
-}
-
-pw_list() {
- find . -type f -name \*.gpg | sed 's/..//;s/\.gpg$//'
-}
-
-pw_tree() {
- command -v tree >/dev/null 2>&1 ||
- die "'tree' command not found"
-
- tree --noreport | sed 's/\.gpg$//'
-}
-
-yn() {
- printf '%s [y/n]: ' "$1"
-
- # Enable raw input to allow for a single byte to be read from
- # stdin without needing to wait for the user to press Return.
- stty -icanon
-
- # Read a single byte from stdin using 'dd'. POSIX 'read' has
- # no support for single/'N' byte based input from the user.
- answer=$(dd ibs=1 count=1 2>/dev/null)
-
- # Disable raw input, leaving the terminal how we *should*
- # have found it.
- stty icanon
-
- printf '\n'
-
- # Handle the answer here directly, enabling this function's
- # return status to be used in place of checking for '[yY]'
- # throughout this program.
- glob "$answer" '[yY]'
-}
-
-sread() {
- printf '%s: ' "$2"
-
- # Disable terminal printing while the user inputs their
- # password. POSIX 'read' has no '-s' flag which would
- # effectively do the same thing.
- stty -echo
- read -r "$1"
- stty echo
-
- printf '\n'
-}
-
-glob() {
- # This is a simple wrapper around a case statement to allow
- # for simple string comparisons against globs.
- #
- # Example: if glob "Hello World" '* World'; then
- #
- # Disable this warning as it is the intended behavior.
- # shellcheck disable=2254
- case $1 in $2) return 0; esac; return 1
-}
-
-die() {
- printf 'error: %s.\n' "$1" >&2
- exit 1
-}
-
-usage() { printf %s "\
-pash 2.3.0 - simple password manager.
-
-=> [a]dd [name] - Create a new password entry.
-=> [c]opy [name] - Copy entry to the clipboard.
-=> [d]el [name] - Delete a password entry.
-=> [l]ist - List all entries.
-=> [s]how [name] - Show password for an entry.
-=> [t]ree - List all entries in a tree.
-
-Password length: export PASH_LENGTH=50
-Password pattern: export PASH_PATTERN=_A-Z-a-z-0-9
-Store location: export PASH_DIR=~/.local/share/pash
-Clipboard tool: export PASH_CLIP='xclip -sel c'
-Clipboard timeout: export PASH_TIMEOUT=15 ('off' to disable)
-"
-exit 0
-}
-
-main() {
- : "${PASH_DIR:=${XDG_DATA_HOME:=$HOME/.local/share}/pash}"
-
- # Look for both 'gpg' and 'gpg2',
- # preferring 'gpg2' if it is available.
- command -v gpg >/dev/null 2>&1 && gpg=gpg
- command -v gpg2 >/dev/null 2>&1 && gpg=gpg2
-
- [ "$gpg" ] ||
- die "GPG not found"
-
- mkdir -p "$PASH_DIR" ||
- die "Couldn't create password directory"
-
- cd "$PASH_DIR" ||
- die "Can't access password directory"
-
- glob "$1" '[acds]*' && [ -z "$2" ] &&
- die "Missing [name] argument"
-
- glob "$1" '[cds]*' && [ ! -f "$2.gpg" ] &&
- die "Pass file '$2' doesn't exist"
-
- glob "$1" 'a*' && [ -f "$2.gpg" ] &&
- die "Pass file '$2' already exists"
-
- glob "$2" '*/*' && glob "$2" '*../*' &&
- die "Category went out of bounds"
-
- glob "$2" '/*' &&
- die "Category can't start with '/'"
-
- glob "$2" '*/*' && { mkdir -p "${2%/*}" ||
- die "Couldn't create category '${2%/*}'"; }
-
- # Set 'GPG_TTY' to the current 'TTY' if it
- # is unset. Fixes a somewhat rare `gpg` issue.
- export GPG_TTY=${GPG_TTY:-$(tty)}
-
- # Restrict permissions of any new files to
- # only the current user.
- umask 077
-
- # Ensure that we leave the terminal in a usable
- # state on exit or Ctrl+C.
- [ -t 1 ] && trap 'stty echo icanon' INT EXIT
-
- case $1 in
- a*) pw_add "$2" ;;
- c*) pw_copy "$2" ;;
- d*) pw_del "$2" ;;
- s*) pw_show "$2" ;;
- l*) pw_list ;;
- t*) pw_tree ;;
- *) usage
- esac
-}
-
-# Ensure that debug mode is never enabled to
-# prevent the password from leaking.
-set +x
-
-# Ensure that globbing is globally disabled
-# to avoid insecurities with word-splitting.
-set -f
-
-[ "$1" ] || usage && main "$@"