bash/sources/16_keystore
raw ยท 18819 bytes
#!/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
_KSTORE_GPG_RCPT="penguin@rbash.io"
: "${_KSTORE_OPENSSL_ITER:=1000000}"
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 $@ ;;
upload) shift; _kstoreupload $@ ;;
download) shift; _kstoredownload $@ ;;
*)
__func_head "add [key] [value|file|-] [prop, default: $_KSTORE_DEF_PROP]"
__func_help "update [key] [value|file|-] [prop, default: $_KSTORE_DEF_PROP]"
__func_help "upload [DIR]"
__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 NAME files..."
__func_help "download 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 download get list query update upload search secret" -- $CUR) )
return
;;
get|update)
COMPREPLY=( $(compgen -W "$( _kstorequery "SELECT DISTINCT key FROM $_KSTORE_TABLE" )" -- $CUR) )
;;
upload)
COMPREPLY=( $(compgen -f -- "$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 \
-iter "$_KSTORE_OPENSSL_ITER" \
-md sha256 \
-salt \
-a \
-A \
-pass fd:3 \
3<<<"$_AUTH_SECRET"
elif [ -f "$1" ]; then
openssl enc \
-e \
-aes-256-cbc \
-pbkdf2 \
-iter "$_KSTORE_OPENSSL_ITER" \
-md sha256 \
-salt \
-a \
-A \
-in "$1" \
-pass fd:3 \
3<<<"$_AUTH_SECRET"
else
printf "%s" "$1" | openssl enc \
-e \
-aes-256-cbc \
-pbkdf2 \
-iter "$_KSTORE_OPENSSL_ITER" \
-md sha256 \
-salt \
-a \
-A \
-pass fd:3 \
3<<<"$_AUTH_SECRET"
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 \
-iter "$_KSTORE_OPENSSL_ITER" \
-md sha256 \
-a \
-A \
-pass fd:3 \
3<<<"$_AUTH_SECRET"
_code=$?
if [ "$_code" -ne 0 ]; then
[ -n "$_KSTORE_DEC_FAILED" ] && touch "$_KSTORE_DEC_FAILED"
return "$_code"
fi
}
function _kstoresecret-auto {
case $OSTYPE in
darwin*) _kstoresecret-macos "$@" ;;
cygwin) _kstoresecret-cygwin "$@" ;;
linux*) _kstoresecret-linux "$@" ;;
*)
echo "$OSTYPE is not supported yet" >&2
;;
esac
}
function _kstoresecret-linux-ensure-gpg-key {
local _GNUPGHOME _FPR
if ! command -v gpg >/dev/null 2>&1; then
echo "gpg is required" >&2
return 1
fi
_GNUPGHOME="${GNUPGHOME:-$HOME/.gnupg}"
mkdir -p "$_GNUPGHOME" || return 1
chmod 700 "$_GNUPGHOME" 2>/dev/null || true
if [ -n "${_KSTORE_GPG_RCPT:-}" ]; then
_FPR=$(
gpg --batch --with-colons --list-secret-keys "$_KSTORE_GPG_RCPT" 2>/dev/null |
awk -F: '$1 == "fpr" { print $10; exit }'
)
if [ -n "$_FPR" ]; then
export _KSTORE_GPG_RCPT="$_FPR"
return 0
fi
fi
_FPR=$(
gpg --batch --with-colons --list-secret-keys 2>/dev/null |
awk -F: '$1 == "fpr" { print $10; exit }'
)
if [ -n "$_FPR" ]; then
export _KSTORE_GPG_RCPT="$_FPR"
return 0
fi
return 1
}
function _kstoresecret-linux-generate-gpg-key {
local _SECRET _UID _TMP _FPR _CODE
_SECRET="$1"
_UID="${KSTORE_GPG_UID:-rbash kstore <kstore@rbash.local>}"
if [ -z "$_SECRET" ]; then
echo "empty local unlock secret" >&2
return 1
fi
_TMP=$(mktemp) || return 1
chmod 600 "$_TMP" 2>/dev/null || true
cat > "$_TMP" <<EOF
Key-Type: eddsa
Key-Curve: ed25519
Key-Usage: sign
Subkey-Type: ecdh
Subkey-Curve: cv25519
Subkey-Usage: encrypt
Name-Real: rbash kstore
Name-Email: kstore@rbash.local
Expire-Date: 0
Passphrase: $_SECRET
%commit
EOF
gpg --batch --pinentry-mode loopback --generate-key "$_TMP"
_CODE=$?
rm -f "$_TMP"
if [ "$_CODE" -ne 0 ]; then
return "$_CODE"
fi
_FPR=$(
gpg --batch --with-colons --list-secret-keys "$_UID" 2>/dev/null |
awk -F: '$1 == "fpr" { print $10; exit }'
)
if [ -z "$_FPR" ]; then
echo "failed to find generated GPG key fingerprint" >&2
return 1
fi
export _KSTORE_GPG_RCPT="$_FPR"
}
function _kstoresecret-linux {
local _SECRET_FILE _RECIPIENT _TMP _A _SECRET _SECRET2
_SECRET_FILE="${RBASH_HOME:-$HOME/.rbash}/keystore.secret.gpg"
if ! _kstoresecret-linux-ensure-gpg-key; then
read -rsp "Enter new local kstore unlock secret: " _SECRET
echo >&2
read -rsp "Confirm new local kstore unlock secret: " _SECRET2
echo >&2
if [ -z "$_SECRET" ]; then
echo "empty local unlock secret" >&2
unset _SECRET _SECRET2
return 1
fi
if [ "$_SECRET" != "$_SECRET2" ]; then
echo "local unlock secrets do not match" >&2
unset _SECRET _SECRET2
return 1
fi
_kstoresecret-linux-generate-gpg-key "$_SECRET" || {
unset _SECRET _SECRET2
return 1
}
unset _SECRET _SECRET2
fi
case "$1" in
get)
if [ ! -f "$_SECRET_FILE" ]; then
return 1
fi
_A=$(
gpg --quiet --decrypt "$_SECRET_FILE"
) || {
echo "failed to decrypt $_SECRET_FILE" >&2
return 1
}
if [ -z "$_A" ]; then
echo "decrypted _AUTH_SECRET is empty: $_SECRET_FILE" >&2
return 1
fi
_AUTH_SECRET="$_A"
unset _A
;;
set)
if [ -z "$_AUTH_SECRET" ]; then
echo "_AUTH_SECRET is not loaded; cannot create $_SECRET_FILE" >&2
return 1
fi
_RECIPIENT="$_KSTORE_GPG_RCPT"
mkdir -p "${RBASH_HOME:-$HOME/.rbash}" || return 1
chmod 700 "${RBASH_HOME:-$HOME/.rbash}" 2>/dev/null || true
_TMP=$(mktemp) || return 1
if printf "%s" "$_AUTH_SECRET" | gpg \
--quiet \
--batch \
--yes \
--encrypt \
--recipient "$_RECIPIENT" \
--output "$_TMP"
then
chmod 600 "$_TMP" 2>/dev/null || true
else
rm -f "$_TMP"
echo "failed to create $_SECRET_FILE" >&2
return 1
fi
_A=$(
gpg --quiet --decrypt "$_TMP"
) || {
rm -f "$_TMP"
echo "failed to verify $_SECRET_FILE" >&2
return 1
}
if [ "$_A" != "$_AUTH_SECRET" ]; then
rm -f "$_TMP"
unset _A
echo "verification mismatch for $_SECRET_FILE" >&2
return 1
fi
unset _A
mv "$_TMP" "$_SECRET_FILE"
;;
del)
rm -f "$_SECRET_FILE"
;;
*)
echo "Unknown action: $1" >&2
return 1
;;
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)
printf "%s" "$_AUTH_SECRET" | kstorecred set
;;
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 -s rbash-kstore -w 2>/dev/null) || return 1
_AUTH_SECRET="$_A"
;;
set)
security add-generic-password -a default -s rbash-kstore -w "$_AUTH_SECRET" -U
;;
del)
security delete-generic-password -a default -s rbash-kstore 2>/dev/null
;;
*)
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
# Test the key first
$_SQLITE -list "$_AUTH_DB" "SELECT ( data ) FROM $_KSTORE_TABLE LIMIT 1;" | _kstoredec >/dev/null
if [ $? -eq 0 ]; then
echo "" >&2
read -p "Save this password to OS's keystore? (y/n): " _CONFIRM
if [ "$_CONFIRM" == "y" ]; then
_kstoresecret-auto set
fi
fi
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 _kstoreupload {
if [ -z "$1" ]; then
__func_head "NAME files..."
return 1
fi
_kstoreinit || return 1
which arch-upload-aws4 2>&1 > /dev/null
if [ $? -ne 0 ]; then
_kstoreinit-s3au
fi
local _TARGET _FNAME _TEMP
_TARGET="$1"
shift
_TEMP="$(mktemp "${TMPDIR:-/tmp}/kstoreupload.XXXXXXXXXX")" || return 1
tar zcf "$_TEMP" $@
_kstoreenc "$_TEMP" > "${_TEMP}.enc"
echo "Size: $(du -sh "${_TEMP}.enc")"
arch-upload-aws4 "uploads/$_TARGET.enc" "${_TEMP}.enc"
rm "${_TEMP}"
rm "${_TEMP}.enc"
}
function _kstoredownload {
if [ -z "$1" ]; then
__func_head "NAME"
return 1
fi
_kstoreinit || return 1
if ! command -v arch-download-aws4 >/dev/null 2>&1; then
_kstoreinit-s3au || return 1
fi
local _TARGET _TMP _OLD_PIPEFAIL
local _ENTRY
local -a _EXISTING=()
_TARGET="$1"
_TMP="$(mktemp "${TMPDIR:-/tmp}/kstoredownload.XXXXXXXXXX")" || return 1
_OLD_PIPEFAIL="$(set +o | grep pipefail)"
set -o pipefail
if ! arch-download-aws4 "uploads/$_TARGET.enc" |
_kstoredec > "$_TMP"
then
eval "$_OLD_PIPEFAIL"
rm -f "$_TMP"
echo "Download/decrypt failed. Incorrect bucket? ($ARCH_S3_BUCKET_URL)" >&2
return 1
fi
eval "$_OLD_PIPEFAIL"
if ! tar tzf "$_TMP" >/dev/null; then
rm -f "$_TMP"
echo "Downloaded data is not a valid tar.gz archive." >&2
return 1
fi
# Reject absolute paths and path traversal before extracting.
while IFS= read -r _ENTRY; do
case "$_ENTRY" in
/*|../*|*/../*|*/..)
rm -f "$_TMP"
echo "Unsafe archive path: $_ENTRY" >&2
return 1
;;
esac
# Ignore directory collisions; existing directories are expected.
if [[ "$_ENTRY" != */ && -e "$_ENTRY" ]]; then
_EXISTING+=("$_ENTRY")
fi
done < <(tar tzf "$_TMP")
if ((${#_EXISTING[@]})); then
echo "The following files already exist:"
printf ' %s\n' "${_EXISTING[@]}"
local _ANSWER
read -r -p "Replace these files? [y/N] " _ANSWER
case "$_ANSWER" in
[yY]|[yY][eE][sS])
;;
*)
rm -f "$_TMP"
echo "Extraction cancelled."
return 1
;;
esac
fi
if ! tar xzf "$_TMP"; then
rm -f "$_TMP"
echo "Archive extraction failed." >&2
return 1
fi
rm -f "$_TMP"
}
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 _URL="https://sgit.k8s.astropenguin.net/penguin/s3-arch-utils/raw/master/$2"
local _NAME=$( basename "${2//_/-}" .sh )
rbash_download_sig "$1" "$_URL" "$RBASH_BIN/$_NAME"
if [ $? -eq 0 ]; then
echo "> $RBASH_BIN/$_NAME"
chmod +x "$RBASH_BIN/$_NAME"
fi
}
function _kstoredl-kstorecred {
local _URL="https://penguins-workspace.s3.ap-southeast-1.astropenguin.net/keystore/kstorecred.exe"
local _NAME="kstorecred"
local _CSUM="031b4474b8eb8deafbb96df73b79f8b654fd3c2209f041fd34cb6f494791bcd4"
rbash_download_sig "$_CSUM" "$_URL" "$RBASH_BIN/$_NAME"
if [ $? -eq 0 ]; then
echo "> $RBASH_BIN/$_NAME"
chmod +x "$RBASH_BIN/$_NAME"
fi
}
function _kstoreinit-s3au {
_kstoredl-s3au "574d106cdced150fa6e04a9437d356d8688035cb2c63a045fa0d4ead8b3ec941" "arch_delete_aws4.sh" || return 1
_kstoredl-s3au "0be740bced7b698d3b23931bf7bd9a77aa22eb3c81f6e9205be4cce4eded0d11" "arch_delete_many_aws4.sh" || return 1
_kstoredl-s3au "4c2a3d67fd97f1b54847424a596f08e2901ee183301f268e2ffd92a4f0ccef32" "arch_download_aws4.sh" || return 1
_kstoredl-s3au "0bee6f925a41f496f66654062b49ea2a1cc55d877f4617d56bf91244aaf0be51" "arch_getacl_aws4.sh" || return 1
_kstoredl-s3au "4eb3aba45d9d20b15b8aab575955084bf525be62661e5b7de2bdeac0260ec9fc" "arch_list_aws4.sh" || return 1
_kstoredl-s3au "e90d197e4f965f88c30f8ff4b0a43ee4b5d656032781f1647770637fff0b9481" "arch_upload_aws4.sh" || return 1
}
function _kstoreupload-db {
local _T
_kstoreinit || return 1
_T=$(date +%Y%m%d%H%M%S)
echo "$_T" > "$RBASH_HOME/keystore.latest"
which arch-upload-aws4 >/dev/null 2>&1
if [ $? -ne 0 ]; then
_kstoreinit-s3au || return 1
fi
_kstoreenc "$_AUTH_DB" > "$RBASH_HOME/$_T.enc" || return 1
chmod 600 "$RBASH_HOME/$_T.enc"
arch-upload-aws4 "keystore/$_T.enc" "$RBASH_HOME/$_T.enc" || return 1
arch-upload-aws4 "keystore/latest" "$RBASH_HOME/keystore.latest" || return 1
rm -f "$RBASH_HOME/$_T.enc" "$RBASH_HOME/keystore.latest"
}
function _kstoredownload-db {
local _T _TMP _CONFIRM _OLD_PIPEFAIL
kstore secret config || return 1
which arch-download-aws4 >/dev/null 2>&1
if [ $? -ne 0 ]; then
_kstoreinit-s3au || return 1
fi
_T=$(arch-download-aws4 "keystore/latest") || return 1
_TMP=$(mktemp) || return 1
_OLD_PIPEFAIL=$(set +o | grep pipefail)
set -o pipefail
if ! arch-download-aws4 "keystore/$_T.enc" | _kstoredec > "$_TMP"; then
eval "$_OLD_PIPEFAIL"
rm -f "$_TMP"
echo "Download/decrypt failed. Incorrect bucket? ($ARCH_S3_BUCKET_URL)" >&2
return 1
fi
eval "$_OLD_PIPEFAIL"
if [ "$($_SQLITE "$_TMP" "PRAGMA integrity_check;")" != "ok" ]; then
rm -f "$_TMP"
echo "Downloaded DB failed SQLite integrity check" >&2
return 1
fi
if ! $_SQLITE "$_TMP" "SELECT COUNT(*) FROM $_KSTORE_TABLE;" >/dev/null; then
rm -f "$_TMP"
echo "Downloaded DB does not look like a kstore DB" >&2
return 1
fi
chmod 600 "$_TMP"
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 -f "$_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" "$@"
}