Initial commit

This commit is contained in:
Dionysus 2023-05-13 01:00:40 -04:00
commit 5426e53daf
Signed by: acidvegas
GPG Key ID: EF4B922DB85DC9DE
3 changed files with 211 additions and 0 deletions

15
LICENSE Normal file
View File

@ -0,0 +1,15 @@
ISC License
Copyright (c) 2023, acidvegas <acid.vegas@acid.vegas>
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.

64
README.md Normal file
View File

@ -0,0 +1,64 @@
# pass
> posix password manager
A very simple password manager that keeps passwords inside gpg encrypted files inside a simple directory tree.
Similar to [password-store](https://git.zx2c4.com/password-store/about/), but written in POSIX compliant shell script instead of bash.
## Requirements
- [gpg](https://gnupg.org/)
- tree
###### Optional Requirements
- [nano](https://www.nano-editor.org/) *(required only if environment variable `$EDITOR` is not set)*
- [dmenu](https://tools.suckless.org/dmenu/) *(required for menu)*
- [pinentry-dmenu](https://github.com/ritze/pinentry-dmenu) *(required for menu)*
- [xclip](https://github.com/astrand/xclip) *(required for menu to copy passwords)*
- [xdotool](https://github.com/jordansissel/xdotool) *(required for menu to type passwords)*
- [oath-toolit](https://www.nongnu.org/oath-toolkit/) *(required for 2FA)*
## Config
Edit the source code to change these settings:
| Setting | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------ |
| `GPG_ID` | Default GPG key ID to use for encrypting/decrypting |
| `GPG_OPTS` | Do not edit this unless you know what you are doing |
| `METHOD` | Method used for the menu *("copy" will use xclip to copy passwords & "type" will use xdotool to type passwords)* |
| `PASS_DIR` | Directory to store all password information |
## Usage
| Command | Description |
| ------------------ | ------------------------------------------------------------------------------------------------------------ |
| `pass` | Display a directory tree of stored passwords |
| `pass <path>` | Display password information for `<path>` or a directory tree of stored passwords if `<path>` is a directory |
| `pass menu` | Use pass in dmenu *(Selected line is copied to the clipboard or typed out depending on the `METHOD` used)* |
| `pass edit <path>` | Display stored password information for `<path>` |
| `pass gen <len>` | Generate a random password that is `<len>` characters long |
| `pass otp <path>` | Return a 2-Factor-Authenticaion code for `<path>` *(Last line of `<path>` must be a valid otpauth:// URI)* |
###### Note
`<path>` is not a direct path per-say. If the password is stored in `$PASS_DIR/www/github.gpg` all you have to put is `www/github` for `<path>`
When using the menu, the clipboard is cleared after 3 seconds or passwords are typed after 3 seconds, depending on what `METHOD` you set in the config.
For setting up 2FA, you can download the QR code image & use [zbar](https://github.com/mchehab/zbar) to convert it to a string to get a valid URI.
## Pinentry Setup
To keep everything in the command line, make sure you edit your `$HOME/.gnupg/gpg-agent.conf` to include `pinentry-program /usr/bin/pinentry-curses`
If you plan on using the menu features, [pinentry-dmenu](https://github.com/ritze/pinentry-dmenu) will allow you to enter your GPG key password inside of dmenu, but in order to do that you will need to create a wrapper for pinetry at `$HOME/.gnupg/pinentry-wrapper`:
```
if [ "$PINENTRY_USER_DATA" = "dmenu" ]; then
exec /usr/local/bin/pinentry-dmenu "$@"
else
exec /usr/bin/pinentry-curses "$@"
fi
```
Make it executable with `chmod +x $HOME/.gnupg/pinentry-wrapper` and then edit your `$HOME/.gnupg/gpg-agent.conf` to include `pinentry-program $HOME/.gnupg/pinentry-wrapper`.
## Mirrors
- [acid.vegas](https://git.acid.vegas/pass)
- [GitHub](https://github.com/acidvegas/pass)
- [GitLab](https://gitlab.com/acidvegas/pass)
- [SuperNETs](https://git.supernets.org/acidvegas/pass)

132
pass Executable file
View File

@ -0,0 +1,132 @@
#!/bin/sh
# posix password manager - developed by acidvegas (https://git.acid.vegas/pass)
umask 077
export GPG_TTY=$(tty)
GPG_ID="acidvegas" # change me
GPG_OPTS="-q --yes --compress-algo=none --no-encrypt-to --batch"
METHOD="copy"
PASS_DIR=$HOME/.secrets
if [ -z $EDITOR ]; then
export EDITOR=nano
fi
mkdir -p $PASS_DIR
edit() {
if [ -d /dev/shm ] && [ -w /dev/shm ] && [ -x /dev/shm ]; then
tmp=$(mktemp -u /dev/shm/pw.XXXXXXXXXX)
trap "rm -rf $tmp" EXIT
else
echo "error: /dev/shm does not exist or is missing permissions required for temporary files"
exit 1
fi
if [ -f $PASS_DIR/$1.gpg ]; then
gpg -d -o $tmp $GPG_OPTS $PASS_DIR/$1.gpg || exit 1
$EDITOR $tmp
if [ ! "$(gpg -d $GPG_OPTS $PASS_DIR/$1.gpg)" = "$(cat $tmp)" ]; then
gpg -e -r $GPG_ID -o $PASS_DIR/$1.gpg $GPG_OPTS $tmp
fi
else
$EDITOR $tmp
if [ -f $tmp ]; then
mkdir -p $(dirname $PASS_DIR/$1)
gpg -e -r $GPG_ID -o $PASS_DIR/$1.gpg $GPG_OPTS $tmp
fi
fi
}
generate() {
case ${1#[-+]} in
*[!0-9]* | '') echo "error: invalid number" ;;
*) cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w $1 | head -n 1 ;;
esac
}
menu() {
cwd=$PASS_DIR
while :
do
if [ $cwd = $PASS_DIR ]; then
cmd=$(ls -p $cwd | dmenu "$@")
else
cmd=$($(echo ".." && ls -p $cwd) | dmenu "$@")
fi
if [ -z $cmd ]; then
break
elif [ $cmd = '..' ]; then
cwd=$(dirname $cwd)
elif [ -d $cwd/$cmd ]; then
cwd=$cwd/$cmd
elif [ -f $cwd/$cmd ]; then
if [ $METHOD = "copy" ]; then
export PINENTRY_USER_DATA="dmenu" | gpg -d $GPG_OPTS $cwd/$cmd | dmenu "$@" | xclip -selection clipboard
sleep 3 && xclip -selection clipboard /dev/null
elif [ $METHOD = "type" ]; then
export PINENTRY_USER_DATA="dmenu" | gpg -d $GPG_OPTS $cwd/$cmd | dmenu "$@" | xdotool type --delay 3 "$D"
fi
break
fi
done
}
otp() {
if [ -f $PASS_DIR/$1.gpg ]; then
otp_uri=$(gpg -d $GPG_OPTS $PASS_DIR/$1.gpg | tail -n 1) || exit 1
if [ "$(echo $otp_uri | head -c 10)" = "otpauth://" ]; then
secret=$(echo "$otp_uri" | sed 's/.*secret=//' | cut -f1 -d'&')
oathtool -b --totp $secret
else
echo "error: OTP URI invalid or not found for '$1'"
fi
else
echo "error: '$1' does not exist"
fi
}
show() {
if [ -d $PASS_DIR/$1 ]; then
echo $1
tree -NCl --noreport $PASS_DIR/$1 3>&- | tail -n +2 | sed -E 's/\.gpg(\x1B\[[0-9]+m)?( ->|$)/\1\2/g'
elif [ -f $PASS_DIR/$1.gpg ]; then
gpg -d $GPG_OPTS $PASS_DIR/$1.gpg
else
echo "error: '$1' does not exist"
fi
}
# Main
[ ! $(command -v gpg) ] && echo "error: missing required packaged 'gpg'" && exit 1
[ ! $(command -v tree) ] && echo "error: missing required packaged 'tree'" && exit 1
if [ "$#" = '1' ]; then
if [ $1 = 'menu' ]; then
[ ! $(command -v dmenu) ] && echo "error: missing required packaged 'dmenu'" && exit 1
[ ! $(command -v pinentry) ] && echo "error: missing required packaged 'pinentry'" && exit 1
[ ! $(command -v pinentry-dmenu) ] && echo "error: missing required packaged 'pinentry-dmenu'" && exit 1
if [ $METHOD = "copy" ]; then
[ ! $(command -v xclip) ] && echo "error: missing required packaged 'xclip'" && exit 1
elif [ $METHOD = 'type' ]; then
[ ! $(command -v xdotool) ] && echo "error: missing required packaged 'xdotool'" && exit 1
else
echo "error: invalid menu method (must be 'copy' or 'type')"
exit 1
fi
menu
else
show $1
fi
elif [ "$#" = '2' ]; then
if [ "$1" = 'edit' ]; then
edit $2
elif [ "$1" = 'gen' ]; then
generate $2
elif [ "$1" = 'otp' ]; then
[ ! $(command -v oathtool) ] && echo "error: missing required packaged 'oathtool'" && exit 1
otp $2
fi
else
tree -NCl --noreport $PASS_DIR 3>&- | tail -n +2 | sed -E 's/\.gpg(\x1B\[[0-9]+m)?( ->|$)/\1\2/g'
fi