123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- #!/bin/bash
- #
- # Companion password manager for quickpass.
- #
- # A few things worth noting before you decide to use this program:
- #
- # - An accredited security audit has NOT been performed on this program yet.
- # - This program relies on GnuPG and a PGP key to perform encryption and
- # decryption, so make sure you use a strong (>4000 bits) key!
- # - Unlike KeePass, this program does NOT encrypt the RAM it uses, nor does
- # it encrypt the entire database. Decide for yourself if this is enough.
- #
- # Inspired by alimiracles `pm` file.
- #
- # Copyright (c) 2016 ali abdul ghani <alimiracle@riseup.net>
- # Copyright (c) 2016 kzimmermann <kzimmermann@vivaldi.net>
- #
- # This file is part of quickpass
- #
- # quickpass is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- # quickpass is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- # You should have received a copy of the GNU General Public License
- # along with quickpass. If not, see <http://www.gnu.org/licenses/>.
- #
- #-- predefined variables --#
- VAULT="$HOME/.quickpassdb"
- # change this to a private key available in your keyring.
- # you can use any format that gpg accepts, like an email address or fingerprint
- RECIPIENT=""
- #-- /predefined variables --#
- #-- Function definitions --
- error() {
- # shorthand for a quit-due-to-error message.
- echo "Error: $1"
- exit 1
- }
- helper() {
- cat <<EOF
- $(basename $0): a password manager for quickpass.
- USAGE $(basename $0) COMMAND [ARGUMENT]
- COMMANDS are:
- -h, --help: this help message.
- -n, --new [SERVICE NAME]: creates a new entry in the vault using quickpass.
- -r, --read [SERVICE NAME]: decrypts and reads the entry for [SERVICE NAME].
- -d, --delete [SERVICE NAME]: deletes entry for [SERVICE NAME].
- -l, --list: lists all available password entries.
- -L, --length [N]: generates passwords of N characters long instead of 32.
- EOF
- if [[ -n "$RECIPIENT" ]]
- then
- cat <<EOF
- The current recipient (user) is: $RECIPIENT.
- $(gpg --list-keys $RECIPIENT)
- EOF
- else
- echo "Error: you have not specified a recipient (vault user) yet."
- echo "Please change the line RECIPIENT=\"\" to your gpg key to use it."
- exit 1
- fi
- }
- create_db() {
- # create a db if there's none available.
- if [[ ! -f "$VAULT" ]]
- then
- sqlite3 "$VAULT" "
- CREATE TABLE IF NOT EXISTS entries (
- service TEXT PRIMARY KEY,
- password TEXT
- )"
- echo "New password vault created at $VAULT"
- else
- echo "A password vault already exists at $VAULT."
- fi
- }
- new_entry() {
- # add a new row in the password database.
- service="$1"
- if [[ -z "$LENGTH" ]]
- then
- encrypted=$(quickpass -p | gpg -a -e -r $RECIPIENT)
- else
- encrypted=$(quickpass -p -l $LENGTH | gpg -a -e -r $RECIPIENT)
- fi
- sqlite3 "$VAULT" "
- INSERT INTO entries (service, password)
- VALUES ('$service', '$encrypted')" || error "could not insert into vault..."
- if [[ -z "$LENGTH" ]]
- then
- echo "Created 1 new password entry for service '$service'"
- else
- echo "Created 1 new password $LENGTH characters long for service '$service'"
- fi
- }
- delete_entry() {
- # remove a row from the database.
- sanity=$(sqlite3 "$VAULT" "
- SELECT service FROM entries
- WHERE service = '$1'
- ")
- [[ -z "$sanity" ]] && error "entry '$1' not found"
- printf "Would you like to delete entry '$1'? (y/n) "
- read decision
- if [[ "$decision" == "y" ]]
- then
- sqlite3 "$VAULT" "
- DELETE FROM entries
- WHERE service = '$1'
- "
- echo "Entry '$1' deleted."
- else
- echo "Aborted."
- exit 1
- fi
- }
- read_entry() {
- # return a decrypted row from the database
- encrypted=$(sqlite3 "$VAULT" "
- SELECT password FROM entries
- WHERE service = '$1'
- ")
- if [[ -n "$encrypted" ]]
- then
- echo "Unlock your key to obtain the password"
- printf %b "$encrypted" | gpg --decrypt | xsel -i -b
- echo "Password copied to the clipboard."
- printf "Clearing automatically in "
- for i in $(seq 1 10)
- do
- printf "$(expr 11 - $i)... "
- sleep 1
- done
- echo $RANDOM | xsel -i -b
- echo "** Cleared. **"
- else
- echo "Entry $1 doesn't exist in the vault."
- echo "Use '--list' to see all available entries."
- exit 1
- fi
- }
- list_entry() {
- # list all available entries from the database:
- echo "You have the following password entries available here:"
- sqlite3 "$VAULT" "SELECT service FROM entries"
- }
- #-- /Function definitions --
- [[ -z $(which sqlite3) ]] && error "sqlite3 not found."
- [[ -z $(which gpg) ]] && error "gpg not found."
- [[ -z "$RECIPIENT" ]] && helper
- [[ ! -f "$VAULT" ]] && create_db
- # We can only perform an action at a time. Sorry.
- action=""
- while [[ -n "$1" ]]
- do
- case "$1" in
- "-h" | "--help" )
- helper
- exit 0
- ;;
- "-n" | "--new" )
- [[ -n "$action" ]] && error "one action at a time only."
- action="new"
- shift
- [[ -z "$1" ]] && error "Missing arguments. See --help"
- token="$1"
- ;;
- "-r" | "--read" )
- [[ -n "$action" ]] && error "one action at a time only."
- action="read"
- shift
- [[ -z "$1" ]] && error "Missing arguments. See --help"
- token="$1"
- ;;
- "-d" | "--delete" )
- [[ -n "$action" ]] && error "one action at a time only."
- action="delete"
- shift
- [[ -z "$1" ]] && error "Missing arguments. See --help"
- token="$1"
- ;;
- "-l" | "--list" )
- list_entry
- exit 0
- ;;
- "-L" | "--length" )
- shift
- [[ -z "$1" ]] && error "Missing arguments. See --help"
- LENGTH="$1"
- ;;
- * )
- echo "Unknown option '$1'"
- exit 1
- ;;
- esac
- shift
- done
- # No argument?
- if [[ -z "$action" ]]
- then
- echo "No action specified to proceed."
- helper
- exit 1
- fi
- case "$action" in
- "new" )
- new_entry "$token"
- ;;
- "read" )
- read_entry "$token"
- ;;
- "delete" )
- delete_entry "$token"
- ;;
- esac
|