#!/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 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|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 "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 TEXT , 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 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-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=`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 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-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" "$@" }