Initial commit
This commit is contained in:
commit
5426e53daf
15
LICENSE
Normal file
15
LICENSE
Normal 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
64
README.md
Normal 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
132
pass
Executable 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
|
Loading…
Reference in New Issue
Block a user