This is a bunch of shell functions to organize my immensly growing amount of user accounts.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

267 lines
6.1 KiB

#!/bin/sh
AMNGRDB="${AMNGRDB:-${HOME}/.account.db}"
AMNGRID="${AMNGRID:-${USER}@${HOSTNAME}}"
AMNGRPWLEN="${AMNGRPWLEN:-10}"
alias random="cat /dev/urandom"
function rand_printable() {
if ! [[ "${1}" =~ "^[0-9]+$" ]]
then
printf "Usage: %s: [len]" "$0"
fi
echo -n "$(random | tr -dc ' !#-&(-~' | head -c${1:-512})"
}
function amngrdbinit() {
local DB="${1:-${AMNGRDB}}"
sqlite3 "${DB}" <<-EOD
PRAGMA foreign_keys = ON;
CREATE TABLE IF NOT EXISTS account (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(128) UNIQUE NOT NULL,
desc TEXT DEFAULT NULL);
CREATE TABLE IF NOT EXISTS cred (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user VARCHAR(128) NOT NULL,
pass TEXT NOT NULL);
CREATE TABLE IF NOT EXISTS account_cred (
account_id INTEGER,
cred_id INTEGER,
state SMALLINT(1) NOT NULL,
FOREIGN KEY(account_id) REFERENCES account(id)
ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY(cred_id) REFERENCES cred(id)
ON UPDATE CASCADE ON DELETE CASCADE);
EOD
}
function amngrdbdestroy() {
local DB="${1:-${AMNGRDB}}"
local CHECK
cat <<-EOT
WARNING: You are about to remove your account data. There is no way to
recover from this. Are you really shure you want to do this?
EOT
echo -n "[Yes|[No]]: " && read CHECK
CHECK="${CHECK:-No}"
test "${CHECK}" == "Yes" && rm -f "${AMNGRDB}"
}
function amngrid() {
local ACCOUNT_NAME="${1}"
echo "$(sqlite3 "${AMNGRDB}" <<-EOD
SELECT id FROM account WHERE name='${ACCOUNT_NAME}';
EOD
)"
}
function amngrcrypt() {
local PLAIN="${1}"
echo -n "${PLAIN}" | gpg -aeqr "${AMNGRID}"
}
function amngrgen() {
local LEN="${0:-${AMNGRPWLEN}}"
amngrcrypt "$(rand_printable "${LEN}")"
}
function amngradd() {
local ACCOUNT_NAME="${1}"
local USER="${2}"
local PASSWORD="$(amngrcrypt "${3}")"
local DESCRIPTION="${4:-NO DESCRIPTION}"
local ACCOUNT_ID="$(amngrid "${ACCOUNT_NAME}")"
local QUERY="$(cat <<-EOD
PRAGMA foreign_keys = ON;
BEGIN TRANSACTION;
INSERT INTO cred (user, pass)
VALUES ('${USER}', '${PASSWORD}');
EOD
)"
if [ -z "${ACCOUNT_ID}" ]
then
QUERY="$(cat <<-EOD
${QUERY}
INSERT INTO account (name, desc)
VALUES ('${ACCOUNT_NAME}', '${DESCRIPTION}');
EOD
)"
else
QUERY="$(cat <<-EOD
${QUERY}
UPDATE account_cred SET state=0
WHERE account_id=(SELECT id FROM account
WHERE name='${ACCOUNT_NAME}' AND state=2);
UPDATE account_cred SET state=2
WHERE account_id=(SELECT id FROM account
WHERE name='${ACCOUNT_NAME}' AND state=1);
EOD
)"
fi
QUERY="$(cat <<-EOD
${QUERY}
INSERT INTO account_cred (account_id, cred_id, state)
VALUES ((SELECT id FROM account WHERE name='${ACCOUNT_NAME}'),
(SELECT id FROM cred WHERE user='${USER}' AND pass='${PASSWORD}'),
1);
COMMIT TRANSACTION;
EOD
)"
sqlite3 "${AMNGRDB}" "${QUERY}"
}
function amngrcreate() {
local ACCOUNT_NAME="${1}"
local USER="${2}"
local DESCRIPTION="${3:-NO DESCRIPTION}"
local PASSWORD="$(rand_printable 10)"
amngradd "${ACCOUNT_NAME}" "${USER}" "${PASSWORD}" "${DESCRIPTION}"
amngrgetpass "${ACCOUNT_NAME}"
}
function amngrgetuser() {
local ACCOUNT_NAME="${1}"
local STATE="${2:-"1"}"
test "${STATE}" != "1" -a "${STATE}" != "2" && STATE="1"
sqlite3 "${AMNGRDB}" <<-EOD |\
awk 'NR>1{print p}{p=$0}END{ORS="";print}' | xclip -i
SELECT user FROM account
JOIN account_cred ON account.id=account_cred.account_id
JOIN cred ON cred.id=account_cred.cred_id
WHERE name='${ACCOUNT_NAME}' AND state=${STATE};
EOD
}
function amngrgetolduser() {
local ACCOUNT_NAME="${1}"
amngrgetuser "${ACCOUNT_NAME}" "2"
}
function amngrgetpass() {
local ACCOUNT_NAME="${1}"
local STATE="${2:-1}"
test "${STATE}" != "1" -a "${STATE}" != "2" && STATE="1"
sqlite3 "${AMNGRDB}" <<-EOD |\
awk 'NR>1{print p}{p=$0}END{ORS="";print}' | gpg -dq | xclip -i
SELECT pass FROM account
JOIN account_cred ON account.id=account_cred.account_id
JOIN cred ON cred.id=account_cred.cred_id
WHERE name='${ACCOUNT_NAME}' AND state=${STATE};
EOD
}
function amngrgetoldpass() {
local ACCOUNT_NAME="${1}"
amngrgetpass "${ACCOUNT_NAME}" "2"
}
function amngrrename() {
local OLD_NAME="${1}"
local NEW_NAME="${2}"
test -z "${OLD_NAME}" -o -z "${NEW_NAME}" && return 1
sqlite3 "${AMNGRDB}" <<-EOD
UPDATE account SET name='${NEW_NAME}'
WHERE name='${OLD_NAME}';
EOD
}
function amngrdelete() {
local ACCOUNT_NAME="${1}"
sqlite3 "${AMNGRDB}" <<-EOD
PRAGMA foreign_keys = ON;
BEGIN TRANSACTION;
DELETE FROM cred WHERE id IN (
SELECT cred_id FROM account
JOIN account_cred ON account.id=account_cred.account_id
WHERE name='${ACCOUNT_NAME}');
DELETE FROM account WHERE name='${ACCOUNT_NAME}';
COMMIT TRANSACTION;
EOD
}
function amngrlist() {
local SEPARATOR="${1:-" => "}"
sqlite3 -separator "${SEPARATOR}" "${AMNGRDB}" <<-EOD
SELECT name, user, desc FROM account
JOIN account_cred ON account.id=account_cred.account_id
JOIN cred ON cred.id=account_cred.cred_id
WHERE state=1;
EOD
}
function amngrsearch() {
local PATTERN
local DELIMITER=" => "
local USAGE="$(printf "Usage: %s: [-d delimiter] pattern" "$0")"
while getopts d: opt
do
case $opt in
d)
DELIMITER="${OPTARG}";;
?)
echo "${USAGE}"
exit 1;;
esac
done
shift $(($OPTIND-1))
if [ $# -lt 2 ]
then
echo "${USAGE}"
exit 1;;
fi
PATTERN="${1}"
sqlite3 -separator " => " "${AMNGRDB}" <<-EOD
SELECT name, user, desc FROM account
JOIN account_cred ON account.id=account_cred.account_id
JOIN cred ON cred.id=account_cred.cred_id
WHERE state=1 AND (
name LIKE '%${PATTERN}%' OR user LIKE '%${PATTERN}%' OR
desc LIKE '%${PATTERN}%');
EOD
}
case "$(basename -- "$0")" in
random) random;;
rand_printable) rand_printable;;
amngrdbinit) amngrdbinit;;
amngrdbdestroy) amngrdbdestroy;;
amngradd) amngradd "$@";;
amngrcreate) amngrcreate "$@";;
amngrcrypt) amngrcrypt "$@";;
amngrdelete) amngrdelete "$@";;
amngrgen) amngrgen "$@";;
amngrgetoldpass) amngrgetoldpass "$@";;
amngrgetolduser) amngrgetolduser "$@";;
amngrgetpass) amngrgetpass "$@";;
amngrgetuser) amngrgetuser "$@";;
amngrid) amngrid "$@";;
amngrlist) amngrlist;;
amngrrename) amngrrename "$@";;
amngrsearch) amngrsearch "$@";;
*) ;;
esac
# vim: set ft=sh ts=4 sw=4: