#!/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 _AUTH_DB=$RBASH_HOME/keystore.db _AUTH_SECRET= _KSTORE_DEF_PROP=${_KSTORE_DEF_PROP:-val} _KSTORE_DEC_FAILED="$RBASH_HOME/.decypt-failed" _KSTORE_TABLE=store if [ -f "$RBASH_HOME/keystore.secret" ]; then _AUTH_SECRET=$( cat "$RBASH_HOME/keystore.secret" ) fi function kstore { case $1 in add) shift; _kstoreadd "$@" ;; del) shift; _kstoredel "$@" ;; get) shift; _kstoreget "$@" ;; list) shift; _kstorelist "$@" ;; query) shift; _kstorequery "$@" ;; update) shift; _kstoreupdate "$@" ;; search) shift; _kstoresearch $@ ;; secret) shift; _kstoresecret $@ ;; *) __func_head "add [key] [value|file|-] [prop, default: $_KSTORE_DEF_PROP]" __func_help "update [key] [value|file|-] [prop, default: $_KSTORE_DEF_PROP]" __func_help "get [key] [prop, default: $_KSTORE_DEF_PROP]" __func_help "del [key] [prop, default: $_KSTORE_DEF_PROP]" __func_help "list" __func_help "search [key] [prop]" __func_help "secret ..." __func_help "upload s3-compatible-provider-name" __func_help "query SQL" return 1 ;; esac return $? } function _kstore { local CUR=${COMP_WORDS[COMP_CWORD]} local SCOPE=${COMP_WORDS[COMP_CWORD-1]} local t COMPREPLY=() case "$SCOPE" in kstore) COMPREPLY=( $(compgen -W "add del get list query update search secret" -- $CUR) ) return ;; get|update) COMPREPLY=( $(compgen -W "$( _kstorequery "SELECT DISTINCT key FROM $_KSTORE_TABLE" )" -- $CUR) ) ;; esac t=${COMP_WORDS[COMP_CWORD-2]} case "$t" in get|update) t=`_kstorequote "$SCOPE"` COMPREPLY=( $(compgen -W "$( _kstorequery "SELECT DISTINCT prop FROM $_KSTORE_TABLE WHERE key = '$t'" )" -- $CUR) ) ;; esac } complete -F _kstore kstore function _kstoresecret { case "$1" in clear) shift; _kstoresecret-clear "$@" ;; config) shift; _kstoresecret-config "$@" ;; change) shift; _kstoresecret-change "$@" ;; *) __func_head "clear" __func_help "config" __func_help "change" ;; esac } function _kstoreinit { if [ ! -f "$_AUTH_DB" ]; then cat <<___SQL___ | $_SQLITE "$_AUTH_DB" CREATE TABLE IF NOT EXISTS $_KSTORE_TABLE ( key TEXT NOT NULL , prop TEXT NOT NULL , data TEXT , PRIMARY KEY( key ASC, prop ASC ) ); ___SQL___ chmod 600 "$_AUTH_DB" fi kstore secret config } function _kstorequote { echo -n "$1" | sed -e "s/'/''/g" } function _kstoreenc { if [ -z "$_AUTH_SECRET" ]; then echo "Secret key is not set yet" >&2 return 1 fi if [ "$1" == "-" ]; then openssl enc -e -aes-256-cbc -pbkdf2 -k "$_AUTH_SECRET" -a -A elif [ -f "$1" ]; then openssl enc -e -aes-256-cbc -pbkdf2 -k "$_AUTH_SECRET" -a -A -in "$1" else echo -n "$1" | openssl enc -e -aes-256-cbc -pbkdf2 -k "$_AUTH_SECRET" -a -A fi } function _kstoredec { 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" -a -A _code=$? if [ $_code -ne 0 ]; then touch $_KSTORE_DEC_FAILED return $_code fi } function _kstoresecret-auto { case $OSTYPE in darwin*) _kstoresecret-macos "$@" ;; cygwin) _kstoresecret-cygwin "$@" ;; *) echo "$OSTYPE is Not supported yet" >&2 ;; esac } function _kstoresecret-cygwin { local _A which kstorecred 2>/dev/null > /dev/null if [ $? -ne 0 ]; then _kstoredl-kstorecred fi case $1 in get) _A=$( kstorecred get ) if [ $? -ne 0 ]; then return 1 fi _AUTH_SECRET="$_A" ;; set) kstorecred set "$_AUTH_SECRET" ;; del) kstorecred del ;; *) echo "Unknown action: $1" >&2 return 1 ;; esac } function _kstoresecret-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" ;; del) security delete-generic-password -a default -s rbash-kstore ;; *) echo "Unknown action: $1" >&2 return 1 ;; esac } function _kstoresecret-config { local _CONFIRM if [ -f "$_KSTORE_DEC_FAILED" ]; then rm $_KSTORE_DEC_FAILED _AUTH_SECRET= fi if [ -z "$_AUTH_SECRET" ]; then _kstoresecret-auto 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 case $OSTYPE in cygwin|darwin*) read -p "Save this password to OS's keystore? (y/n): " _CONFIRM if [ "$_CONFIRM" != "y" ]; then return 0 fi _kstoresecret-auto set ;; esac fi } function _kstoresecret-change { _kstoresecret-config local _NEW_SECRET i _key _prop _O_SECRET _BAK read -sp "Enter the new passphrase: " _NEW_SECRET echo read -sp "Enter the passphrase again: " i echo if [ "$i" != "$_NEW_SECRET" ]; then echo "Passphrase mismatched" >&2 return 1 fi _BAK=$( mktemp ) cp "$_AUTH_DB" "$_BAK" echo "Backed up at $_BAK" _O_SECRET="$_AUTH_SECRET" for i in `$_SQLITE -list "$_AUTH_DB" "SELECT _ROWID_ FROM $_KSTORE_TABLE;"`; do _AUTH_SECRET=$_O_SECRET _key=`$_SQLITE -list "$_AUTH_DB" "SELECT key FROM $_KSTORE_TABLE WHERE _ROWID_ = $i;"` _key=`_kstorequote "$_key"` _prop=`$_SQLITE -list "$_AUTH_DB" "SELECT prop FROM $_KSTORE_TABLE WHERE _ROWID_ = $i;"` _prop=`_kstorequote "$_prop"` _val=`kstore get "$_key" "$_prop"` if [ $? -ne 0 ]; then echo "Current passphrase is incorrect?" >&2 return 1 fi _AUTH_SECRET=$_NEW_SECRET echo Updating: [$_key] [$_prop] kstore update "$_key" "$_val" "$_prop" done _kstoresecret-auto get if [ -n "$_AUTH_SECRET" ]; then _kstoresecret-auto del 2>&1 > /dev/null _AUTH_SECRET=$_NEW_SECRET _kstoresecret-auto set if [ $? -eq 0 ]; then echo "New passphrase saved in OS's keystore." fi fi _AUTH_SECRET=$_NEW_SECRET } function _kstoresecret-clear { unset _AUTH_SECRET _kstoresecret-auto del } function _kstoreupdate { if [ -z "$1" ]; then __func_head "[key] [value|file|-] [prop, default: $_KSTORE_DEF_PROP]" return 1 fi _kstoreinit || return 1 local _key _val _prop _key=`_kstorequote "$1"` _val=`_kstoreenc "$2"` _val=`_kstorequote "$_val"` _prop=`_kstorequote "${3:-$_KSTORE_DEF_PROP}"` _cond="key = '$_key' AND prop = '$_prop'" $_SQLITE "$_AUTH_DB" "UPDATE $_KSTORE_TABLE SET data = '$_val' WHERE $_cond;" } function _kstoreadd { if [ -z "$1" ]; then __func_head "[key] [value|file|-] [prop, default: $_KSTORE_DEF_PROP]" return 1 fi _kstoreinit || return 1 local _key _val _prop _key=`_kstorequote "$1"` _val=`_kstoreenc "$2"` _val=`_kstorequote "$_val"` _prop=`_kstorequote "${3:-$_KSTORE_DEF_PROP}"` $_SQLITE "$_AUTH_DB" \ "INSERT INTO $_KSTORE_TABLE ( key, prop, data ) VALUES( '$_key', '$_prop', '$_val' );" } function _kstoreget { if [ -z "$1" ]; then __func_head "[key] [prop, default: $_KSTORE_DEF_PROP]" return 1 fi _kstoreinit || return 1 local _key _prop _cond _key=`_kstorequote "$1"` _prop=`_kstorequote "${2:-$_KSTORE_DEF_PROP}"` _cond="key = '$_key' AND prop = '$_prop'" $_SQLITE "$_AUTH_DB" "SELECT 1111 FROM $_KSTORE_TABLE WHERE $_cond;" | grep -q 1111 if [ $? -eq 0 ]; then $_SQLITE -list "$_AUTH_DB" "SELECT ( data ) FROM $_KSTORE_TABLE WHERE $_cond;" | _kstoredec else echo "\"$1\" not found (prop: $_prop)" >&2 return 1 fi } function _kstoredel { if [ -z "$1" ]; then __func_head "[key] [prop, default: $_KSTORE_DEF_PROP]" return 1 fi _kstoreinit || return 1 local _CONFIRM _key _prop _cond _key=`_kstorequote "$1"` _prop=`_kstorequote "${2:-$_KSTORE_DEF_PROP}"` _cond="key = '$_key' AND prop = '$_prop'" $_SQLITE "$_AUTH_DB" "SELECT 1111 FROM $_KSTORE_TABLE WHERE $_cond;" | grep -q 1111 if [ $? -eq 0 ]; then $_SQLITE "$_AUTH_DB" "SELECT * FROM $_KSTORE_TABLE WHERE $_cond;" echo read -p "Delete this entry (yes/no)? " _CONFIRM if [ "$_CONFIRM" == "yes" ]; then $_SQLITE "$_AUTH_DB" "DELETE FROM $_KSTORE_TABLE WHERE $_cond;" if [ $? -eq 0 ]; then echo "deleted" fi else echo "action canceled" fi else echo "\"$1\" not found (prop: $_prop)" >&2 fi } function _kstoredl-s3au { local p tmp _NAME p="https://git.k8s.astropenguin.net/penguin/s3-arch-utils/raw/branch/master" _CSUM=$1 _NAME=$2 tmp=$( mktemp ) __download "$p/$_NAME" > $tmp sha256sum $tmp | grep -q "$_CSUM" if [ $? -eq 0 ]; then _NAME=$( basename "${_NAME//_/-}" .sh ) mv $tmp "$RBASH_BIN/$_NAME" chmod +x "$RBASH_BIN/$_NAME" echo "> $RBASH_BIN/$_NAME" else echo "$_NAME: Signature mismatch" return 1 fi } function _kstoredl-kstorecred { local p tmp _NAME _NAME="kstorecred" p="https://penguins-workspace.s3.ap-southeast-1.astropenguin.net/keystore/kstorecred.exe" _CSUM="031b4474b8eb8deafbb96df73b79f8b654fd3c2209f041fd34cb6f494791bcd4" tmp=$( mktemp ) __download "$p" > $tmp sha256sum $tmp | grep -q "$_CSUM" if [ $? -eq 0 ]; then mv $tmp "$RBASH_BIN/$_NAME" chmod +x "$RBASH_BIN/$_NAME" echo "> $RBASH_BIN/$_NAME" else echo "$_NAME: Signature mismatch" return 1 fi } function _kstoreinit-s3au { _kstoredl-s3au "574d106cdced150fa6e04a9437d356d8688035cb2c63a045fa0d4ead8b3ec941" "arch_delete_aws4.sh" || return 1 _kstoredl-s3au "ce04b3f90b7d9a2578587c8ff841186810d977545943fb4a8234a6d6e9f7b568" "arch_delete_many_aws4.sh" || return 1 _kstoredl-s3au "31709a639fab27b5ba071dd4c843fd3e90d4cea07bbb055c08c9720d31a8d11d" "arch_download_aws4.sh" || return 1 _kstoredl-s3au "0bee6f925a41f496f66654062b49ea2a1cc55d877f4617d56bf91244aaf0be51" "arch_getacl_aws4.sh" || return 1 _kstoredl-s3au "dcb89894e78351af702fabb521cf1cf6ca512db9cd4cf3c70631bb1e51ab9340" "arch_list_aws4.sh" || return 1 _kstoredl-s3au "759ef3841525ce240d00e03578c39533c30bf246d61c12c2f3ba2ab37c5f814e" "arch_upload_aws4.sh" || return 1 } function _kstoreupload-db { local _T _W _kstoreinit || return 1 _T=$( date +%Y%m%d%H%M%S ) echo $_T > "$RBASH_HOME/keystore.latest" which arch-upload-aws4 2>&1 > /dev/null if [ $? -ne 0 ]; then _kstoreinit-s3au fi _kstoreenc $_AUTH_DB > "$RBASH_HOME/$_T.enc" arch-upload-aws4 "keystore/$_T.enc" "$RBASH_HOME/$_T.enc" arch-upload-aws4 "keystore/latest" "$RBASH_HOME/keystore.latest" rm "$RBASH_HOME/$_T.enc" rm "$RBASH_HOME/keystore.latest" } function _kstoredownload-db { local _T _DOMAIN _URL _TMP _CONFIRM kstore secret config || return 1 _DOMAIN="penguins-workspace.s3.ap-southeast-1.astropenguin.net" _T=$( __download "https://$_DOMAIN/keystore/latest" ) if [ $? -ne 0 ]; then return 1 fi _TMP=$( mktemp ) __download "https://$_DOMAIN/keystore/$_T.enc" | _kstoredec > $_TMP if [ $? -ne 0 ]; then return 1 fi _T=$( $_SQLITE "$_TMP" "SELECT COUNT( * ) FROM $_KSTORE_TABLE" ) if [ $? -ne 0 ]; then return 1 fi if [ -f "$_AUTH_DB" ]; then read -p "Replace existing db? (yes/no): " _CONFIRM if [ "$_CONFIRM" == "yes" ]; then _T="$_AUTH_DB.old.$( date +%Y%m%d%H%M%S )" mv "$_AUTH_DB" "$_T" mv $_TMP $_AUTH_DB echo "Original copy: $_T" else echo "action canceled" rm $_TMP fi else mv $_TMP $_AUTH_DB fi } function _kstoresearch { local _termk _termp _cond _termk=`_kstorequote "$1"` _termp=`_kstorequote "$2"` _cond="key LIKE '%$_termk%' AND prop LIKE '%$_termp%'" $_SQLITE -header -column "$_AUTH_DB" "SELECT key, prop, length( data ) FROM $_KSTORE_TABLE WHERE $_cond;" } function _kstorelist { $_SQLITE -header -column "$_AUTH_DB" "SELECT key, prop, length( data ) FROM $_KSTORE_TABLE;" } function _kstorequery { $_SQLITE "$_AUTH_DB" "$@" }