#!/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} if [ -f "$RBASH_HOME/keystore.secret" ]; then _AUTH_SECRET=$( cat "$RBASH_HOME/keystore.secret" ) fi complete -W "add del get list query update search secret sync" kstore 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 $@ ;; sync) shift; kstore-sync $@ ;; *) __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]" __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-secret { case "$1" in clear) shift; kstore-secret-clear "$@" ;; config) shift; kstore-secret-config "$@" ;; change) shift; kstore-secret-change "$@" ;; *) __func_head "clear" __func_help "config" __func_help "change" ;; esac } function kstore-init { if [ ! -f "$_AUTH_DB" ]; then cat <<___SQL___ | $_SQLITE "$_AUTH_DB" CREATE TABLE IF NOT EXISTS store ( 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 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 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 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" -a -A } function kstore-secret-auto { case $OSTYPE in darwin*) kstore-secret-macos "$@" ;; *) echo "$OSTYPE is Not supported yet" >&2 ;; esac } 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" ;; del) security delete-generic-password -a default -s rbash-kstore ;; *) 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-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 read -p "Save this password to OS's keystore? (y/n): " _CONFIRM if [ "$_CONFIRM" != "y" ]; then return 0 fi kstore-secret-auto set fi } function kstore-secret-change { kstore-secret-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 store;"`; do _AUTH_SECRET=$_O_SECRET _key=`$_SQLITE -list "$_AUTH_DB" "SELECT key FROM store WHERE _ROWID_ = $i;"` _key=`kstore-quote "$_key"` _prop=`$_SQLITE -list "$_AUTH_DB" "SELECT prop FROM store WHERE _ROWID_ = $i;"` _prop=`kstore-quote "$_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 kstore-secret-auto get if [ -n "$_AUTH_SECRET" ]; then kstore-secret-auto del 2>&1 > /dev/null _AUTH_SECRET=$_NEW_SECRET kstore-secret-auto set if [ $? -eq 0 ]; then echo "New passphrase saved in OS's keystore." fi fi _AUTH_SECRET=$_NEW_SECRET } 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=`kstore-enc "$2"` _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=`kstore-enc "$2"` _val=`kstore-quote "$_val"` _prop=`kstore-quote "${3:-$_KSTORE_DEF_PROP}"` sqlite3 "$_AUTH_DB" \ "INSERT INTO store ( key, prop, data ) VALUES( '$_key', '$_prop', '$_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'" sqlite3 "$_AUTH_DB" "SELECT 1111 FROM store WHERE $_cond;" | grep -q 1111 if [ $? -eq 0 ]; then $_SQLITE -list "$_AUTH_DB" "SELECT ( data ) FROM store WHERE $_cond;" | kstore-dec else echo "\"$1\" not found" >&2 return 1 fi } 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" >&2 fi } function kstore-dl-s3au { local p tmp _NAME p="https://git.k8s.astropenguin.net/penguin/s3-arch-utils/raw/branch/master" _CSUM=$1 _NAME=$2 which "$_NAME" > /dev/null 2>&1 if [ $? -ne 0 ]; then 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 fi } function kstore-sync { kstore-dl-s3au "574d106cdced150fa6e04a9437d356d8688035cb2c63a045fa0d4ead8b3ec941" "arch_delete_aws4.sh" || return 1 kstore-dl-s3au "ce04b3f90b7d9a2578587c8ff841186810d977545943fb4a8234a6d6e9f7b568" "arch_delete_many_aws4.sh" || return 1 kstore-dl-s3au "31709a639fab27b5ba071dd4c843fd3e90d4cea07bbb055c08c9720d31a8d11d" "arch_download_aws4.sh" || return 1 kstore-dl-s3au "0bee6f925a41f496f66654062b49ea2a1cc55d877f4617d56bf91244aaf0be51" "arch_getacl_aws4.sh" || return 1 kstore-dl-s3au "dcb89894e78351af702fabb521cf1cf6ca512db9cd4cf3c70631bb1e51ab9340" "arch_list_aws4.sh" || return 1 kstore-dl-s3au "918cd96e5dd6f3a29f9ac90dc70b14eee595da31a8b6c74bdcd67d393b60ae3e" "arch_upload_aws4.sh" || return 1 } function kstore-search { local _termk _termp _cond _termk=`kstore-quote "$1"` _termp=`kstore-quote "$2"` _cond="key LIKE '%$_termk%' AND prop LIKE '%$_termp%'" $_SQLITE -header -column "$_AUTH_DB" "SELECT key, prop, length( data ) FROM store WHERE $_cond;" } function kstore-list { $_SQLITE -header -column "$_AUTH_DB" "SELECT key, prop, length( data ) FROM store;" } function kstore-query { $_SQLITE "$_AUTH_DB" "$@" }