308 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			308 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
| #!/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 $@ ;;
 | |
| 		upload) shift; kstore-upload $@ ;;
 | |
| 		*)
 | |
| 			__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 {
 | |
| 	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___
 | |
| 	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
 | |
| 	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 {
 | |
| 	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 {
 | |
| 	sqlite3 "$_AUTH_DB" "$@"
 | |
| }
 |