From 85c9c3bea37db984b6cccb75331ecba8ebfc6541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= Date: Sat, 13 Aug 2022 23:40:12 +0800 Subject: [PATCH] Added 16_keystore --- bash/bashrc/sources/16_keystore | 230 ++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 bash/bashrc/sources/16_keystore diff --git a/bash/bashrc/sources/16_keystore b/bash/bashrc/sources/16_keystore new file mode 100644 index 0000000..f455aaf --- /dev/null +++ b/bash/bashrc/sources/16_keystore @@ -0,0 +1,230 @@ +#!/bin/bash + +_SQLITE=$( which sqlite3 2>&1 ) +if [ $? -ne 0 ]; then + echo "sqlite3 is missing" >&2 + return 1 +fi + +echo "test" | openssl enc -e -aes-256-cbc -pbkdf2 -k test 2>/dev/null > /dev/null +if [ $? -ne 0 ]; then + echo "openssl does not exists nor support pbkdf2" >&2 + return 1 +fi + +if [ -z `which xxd` ]; then + echo "xxd is required" >&2 + return 1 +fi + +_AUTH_DB=$RBASH_HOME/keystore.db +_AUTH_SECRET= +_KSTORE_DEF_PROP=${_KSTORE_DEF_PROP:-val} + +if [ -f "$RBASH_HOME/keystore.secret" ]; then + _AUTH_SECRET=$( cat "$RBASH_HOME/keystore.secret" ) +fi + +function kstore { + case $1 in + add) shift; kstore-add "$@" ;; + del) shift; kstore-del "$@" ;; + get) shift; kstore-get "$@" ;; + list) shift; kstore-list "$@" ;; + query) shift; kstore-query "$@" ;; + update) shift; kstore-update "$@" ;; + search) shift; kstore-search $@ ;; + secret) shift; kstore-secret $@ ;; + *) + __func_head "add key value [prop, default: $_KSTORE_DEF_PROP]" + __func_help "update key value [prop, default: $_KSTORE_DEF_PROP]" + __func_help "get key [prop, default: $_KSTORE_DEF_PROP]" + __func_help "list" + __func_help "del key" + __func_help "search key" + __func_help "query SQL" + return 1 + ;; + esac + return $? +} + +function kstore-secret { + case "$1" in + clear) shift; kstore-secret-clear "$@" ;; + config) shift; kstore-secret-config "$@" ;; + *) + __func_head "clear" + __func_help "config" + ;; + esac +} + +function kstore-init { + cat <<___SQL___ | $_SQLITE "$_AUTH_DB" +CREATE TABLE IF NOT EXISTS store ( + key TEXT UNIQUE NOT NULL + , prop TEXT NOT NULL + , data BLOB + , PRIMARY KEY( key ASC, prop ASC ) +); +___SQL___ + kstore secret config +} + +function kstore-quote { + echo -n "$1" | sed -e "s/'/''/g" +} + +function kstore-enc { + if [ -z "$_AUTH_SECRET" ]; then + echo "Secret key is not set yet" >&2 + return 1 + fi + + openssl enc -e -aes-256-cbc -pbkdf2 -k "$_AUTH_SECRET" | xxd -p | tr -d "\n" +} + +function kstore-dec { + if [ -z "$_AUTH_SECRET" ]; then + echo "Secret key is not set yet" >&2 + return 1 + fi + + openssl enc -d -aes-256-cbc -pbkdf2 -k "$_AUTH_SECRET" +} + +function kstore-secret-macos { + local _A + case $1 in + get) + _A=`security find-generic-password -a default -gs rbash-kstore 2>&1 | grep ^password | cut -c 11-` + if [ $? -ne 0 ]; then + return 1 + fi + _AUTH_SECRET="${_A:1:-1}" + ;; + set) + security add-generic-password -a default -s rbash-kstore -w "$_AUTH_SECRET" + ;; + *) + echo "Unknown action: $1" >&2 + return 1 + ;; + esac +} + +function kstore-secret-windows { + # Not impelemented yet + if [ "$1" == "get" ]; then + return 1 + fi + return 1 +} + +function kstore-secret-config { + local _CONFIRM + if [ -z "$_AUTH_SECRET" ]; then + + kstore-secret-windows get || kstore-secret-macos get + if [ -n "$_AUTH_SECRET" ]; then + return 0 + fi + + read -sp "Enter passphrase: " _AUTH_SECRET + echo + if [ -z "$_AUTH_SECRET" ]; then + echo "Passphrase cannot be empty" >&2 + return 1 + fi + + read -p "Save this password to OS's keystore? (y/n): " _CONFIRM + if [ "$_CONFIRM" != "y" ]; then + return 0 + fi + + case $OSTYPE in + darwin*) kstore-secret-macos "set" ;; + esac + fi +} + +function kstore-secret-clear { + _AUTH_SECRET= + case $OSTYPE in + darwin*) + security delete-generic-password -a default -s rbash-kstore 2>&1 > /dev/null + ;; + esac +} + +function kstore-update { + kstore-init || return 1 + local _key _val _prop + _key=`kstore-quote "$1"` + _val=`echo -n "$2" | kstore-enc` + _val=`kstore-quote "$_val"` + _prop=`kstore-quote "${3:-$_KSTORE_DEF_PROP}"` + _cond="key = '$_key' AND prop = '$_prop'" + $_SQLITE "$_AUTH_DB" "UPDATE store SET data = '$_val' WHERE $_cond;" +} + +function kstore-add { + kstore-init || return 1 + local _key _val _prop + _key=`kstore-quote "$1"` + _val=`echo -n "$2" | kstore-enc` + _val=`kstore-quote "$_val"` + _prop=`kstore-quote "${3:-$_KSTORE_DEF_PROP}"` + sqlite3 "$_AUTH_DB" \ + "INSERT INTO store ( key, prop, data ) + VALUES( '$_key', '$_prop', X'$_val' );" +} + +function kstore-get { + kstore-init || return 1 + local _key _prop _cond + _key=`kstore-quote "$1"` + _prop=`kstore-quote "${2:-$_KSTORE_DEF_PROP}"` + _cond="key = '$_key' AND prop = '$_prop'" + + echo -n "`$_SQLITE -list "$_AUTH_DB" "SELECT ( data ) FROM store WHERE $_cond;"`" | kstore-dec +} + +function kstore-del { + kstore-init || return 1 + + local _CONFIRM _key _prop _cond + _key=`kstore-quote "$1"` + _prop=`kstore-quote "${2:-$_KSTORE_DEF_PROP}"` + _cond="key = '$_key' AND prop = '$_prop'" + + sqlite3 "$_AUTH_DB" "SELECT 1111 FROM store WHERE $_cond;" | grep -q 1111 + if [ $? -eq 0 ]; then + sqlite3 "$_AUTH_DB" "SELECT * FROM store WHERE $_cond;" + echo + read -p "Delete this entry (yes/no)? " _CONFIRM + if [ "$_CONFIRM" == "yes" ]; then + sqlite3 "$_AUTH_DB" "DELETE FROM store WHERE $_cond;" + if [ $? -eq 0 ]; then + echo "deleted" + fi + else + echo "action canceled" + fi + else + echo "$1 not found" + fi +} + +function kstore-search { + echo "Not implemented yet" +} + +function kstore-list { + $_SQLITE -header -column "$_AUTH_DB" "SELECT key, prop, length( data ) FROM store;" +} + +function kstore-query { + sqlite3 "$_AUTH_DB" "$@" +}