809 lines
25 KiB
Bash
Executable File
809 lines
25 KiB
Bash
Executable File
#!/bin/bash
|
|
trap nfcunmount EXIT
|
|
|
|
set -o noglob
|
|
|
|
SCRIPT="$(readlink -f "${BASH_SOURCE}")"
|
|
CONFIGURATION="/home/user/scripts/admin.conf"
|
|
|
|
if [ "$EUID" -ne 0 ]; then
|
|
echo "Ce script nécessite des privilèges administrateur."
|
|
echo "Relance avec sudo..."
|
|
exec sudo "$0" "$@"
|
|
fi
|
|
|
|
echo "Le script est bien lancé avec sudo/root !"
|
|
|
|
function show()
|
|
{
|
|
NC='\033[0m'
|
|
if [ -z "$2" ]; then
|
|
COLOR=$NC
|
|
elif [ "$2" == "ERR" ]; then
|
|
COLOR='\033[1;31m'
|
|
else
|
|
COLOR='\033[0;32m'
|
|
fi
|
|
printf "${COLOR}$1${NC}\n"
|
|
}
|
|
|
|
function assign()
|
|
{
|
|
KEYS=$(cat "$1"|sed 's/.*%\([A-Z0-9]*\)%.*/%\1/g'|grep "%"|tr -d '%')
|
|
while read -r KEY; do
|
|
REALKEY=$(eval echo \$${KEY})
|
|
show "Apply key $KEY" 1
|
|
sed -i "s#%${KEY}%#${REALKEY}#g" /mnt/usb/rclone/rclone.conf
|
|
done < <(echo "${KEYS}")
|
|
}
|
|
|
|
function extract()
|
|
{
|
|
ALLCONTENT=$(cat "${SCRIPT}"|grep "#$1"|sed "s/^#$1\(.*\)$/\1/")
|
|
CONTENT=$(echo "${ALLCONTENT}"|tail -n +2)
|
|
CONTENTSIZE=$(echo "${CONTENT}"|wc -c)
|
|
FILEINFO=$(echo "${ALLCONTENT}"|head -n1)
|
|
FILENAME=$(echo "${FILEINFO}"|cut -d"," -f1)
|
|
FILEMOD=$(echo "${FILEINFO}"|cut -d"," -f2)
|
|
show "Extract piece $1 (${CONTENTSIZE}o) at ${FILENAME} with ${FILEMOD}"
|
|
echo "${CONTENT}" > "${FILENAME}"
|
|
chmod ${FILEMOD} "${FILENAME}"
|
|
}
|
|
|
|
function excludepath()
|
|
{
|
|
EXCLUD=""
|
|
while read SRC; do
|
|
if [ ! -z "${SRC}" ]; then
|
|
EXCLUD="${EXCLUD} --exclude ${SRC}"
|
|
fi
|
|
done < <(echo "$1"|tr "," "\n")
|
|
echo "${EXCLUD}"
|
|
}
|
|
|
|
function nfcunmount()
|
|
{
|
|
TMPFS=$(mount -t tmpfs|grep "/mnt/usb")
|
|
if [ ! -z "${TMPFS}" ]; then
|
|
umount /mnt/usb
|
|
fi
|
|
TMPFS=$(mount -t tmpfs|grep "/mnt/usb")
|
|
if [ ! -z "${TMPFS}" ]; then
|
|
show "Unable to umount" ERR
|
|
fi
|
|
}
|
|
|
|
function nfcmountonly()
|
|
{
|
|
if [ ! -d /mnt/usb ]; then
|
|
mkdir -p /mnt/usb
|
|
fi
|
|
TMPFS=$(mount -t tmpfs|grep "/mnt/usb")
|
|
if [ -z "${TMPFS}" ]; then
|
|
mount -t tmpfs tmpfs /mnt/usb
|
|
fi
|
|
}
|
|
|
|
function rclonemount()
|
|
{
|
|
if [ ! -f /mnt/usb/rclone/rclone.conf ]; then
|
|
show "NO RCLONE CONFIGURATION FILE" ERR
|
|
nfcmountonly
|
|
if [ ! -d /mnt/usb/rclone ]; then
|
|
show "Create /mnt/usb/rclone" 1
|
|
mkdir -p /mnt/usb/rclone
|
|
show "Create rclone.conf" 1
|
|
extract 5
|
|
TOKEN=$(${ZFS} get rclone:token $1 -o value -H|decrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
|
|
if [[ "${TOKEN}" == "" ]]; then
|
|
show "Unable to find connexion information: token"
|
|
nfcunmount
|
|
exit
|
|
fi
|
|
if [[ "$2" == "rclone" ]]; then
|
|
show "RCLONE mode"
|
|
PASSWD1=$(${ZFS} get rclone:password1 $1 -o value -H|decrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
|
|
if [[ "${PASSWD1}" == "" ]]; then
|
|
show "Unable to find connexion information: passwd1"
|
|
nfcunmount
|
|
exit
|
|
fi
|
|
PASSWD2=$(${ZFS} get rclone:password2 $1 -o value -H|decrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
|
|
if [[ "${PASSWD2}" == "" ]]; then
|
|
show "Unable to find connexion information: passwd2"
|
|
nfcunmount
|
|
exit
|
|
fi
|
|
REMOTE=$(${ZFS} get sync:dstpath $1 -o value -H)
|
|
if [[ "${REMOTE}" == "" ]]; then
|
|
show "Unable to find connexion information: dstpath"
|
|
nfcunmount
|
|
exit
|
|
fi
|
|
ACTIVE=$(${ZFS} get sync:active $1 -o value -H)
|
|
if [[ ! "${ACTIVE}" == "on" ]]; then
|
|
show "Sync not active"
|
|
nfcunmount
|
|
exit
|
|
fi
|
|
RCLONE_EXCLUDE=$(${ZFS} get sync:exclude $1 -o value -H)
|
|
RCLONE_VOLS="/$1"
|
|
else
|
|
PASSWD1=$(${ZFS} get restic:password1 $1 -o value -H|decrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
|
|
if [[ "${PASSWD1}" == "" ]]; then
|
|
show "Unable to find connexion information: passwd1"
|
|
nfcunmount
|
|
exit
|
|
fi
|
|
PASSWD2=$(${ZFS} get restic:password2 $1 -o value -H|decrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
|
|
if [[ "${PASSWD2}" == "" ]]; then
|
|
show "Unable to find connexion information: passwd2"
|
|
nfcunmount
|
|
exit
|
|
fi
|
|
show "RESTIC mode"
|
|
REMOTE=$(${ZFS} get backup:dstpath $1 -o value -H)
|
|
if [[ "${REMOTE}" == "" ]]; then
|
|
show "Unable to find connexion information: dstpath"
|
|
nfcunmount
|
|
exit
|
|
fi
|
|
ACTIVE=$(${ZFS} get backup:active $1 -o value -H)
|
|
if [[ ! "${ACTIVE}" == "on" ]]; then
|
|
show "Backup not active"
|
|
nfcunmount
|
|
exit
|
|
fi
|
|
|
|
RESTIC_PASSWORD=$(${ZFS} get restic:password $1 -o value -H|decrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
|
|
if [[ "${RESTIC_PASSWORD}" == "" ]]; then
|
|
show "Unable to find connexion information: passwd"
|
|
nfcunmount
|
|
exit
|
|
fi
|
|
RESTIC_EXCLUDE=$(${ZFS} get backup:exclude $1 -o value -H)
|
|
RESTIC_ALL=$(${ZFS} get backup:retention $1 -o value -H)
|
|
RESTIC_MONTHLY=$(echo "${RESTIC_ALL}"|cut -d',' -f1)
|
|
RESTIC_WEEKLY=$(echo "${RESTIC_ALL}"|cut -d',' -f2)
|
|
RESTIC_DAILY=$(echo "${RESTIC_ALL}"|cut -d',' -f3)
|
|
RESTIC_VOLS="/$1"
|
|
fi
|
|
assign /mnt/usb/rclone/rclone.conf
|
|
fi
|
|
fi
|
|
TOKEN=""
|
|
PASSWD1=""
|
|
PASSWD2=""
|
|
show "List remotes" 1
|
|
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf listremotes
|
|
show "Connect to Cloud without cyphering" 1
|
|
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf lsd pcloud:/
|
|
show "Connect to Cloud with cyphering" 1
|
|
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf lsd crypt:/
|
|
}
|
|
|
|
function attribute()
|
|
{
|
|
VAL=""
|
|
ATTRIBUTE=$(${ZFS} get $1 $4 -o value -H)
|
|
if [[ "${ATTRIBUTE}" == "-" ]]; then
|
|
ATTRIBUTE="$5"
|
|
show "Init attribute $1 with $5"
|
|
${ZFS} set $1=$5 $4
|
|
fi
|
|
if [[ "$2" == "passwd" ]]; then
|
|
ATTRIBUTE_DEC=$(echo -en "${ATTRIBUTE}"|decrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
|
|
BEGIN=$(echo "${ATTRIBUTE_DEC}"|head -c 10)
|
|
MIDDLE="..."
|
|
END=$(echo "${ATTRIBUTE_DEC}"|tail -c 10)
|
|
BLOB="${BEGIN}${MIDDLE}${END}"
|
|
read -p "$3 [${BLOB}]:" ASK_DEC </dev/tty
|
|
if [[ "${ASK_DEC}" == "" ]]; then
|
|
ASK=""
|
|
else
|
|
ASK=$(echo -en "${ASK_DEC}"|encrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
|
|
fi
|
|
ATTRIBUTE_DEC=""
|
|
ASK_DEC=""
|
|
elif [[ "$2" == "bool" ]]; then
|
|
if [[ "${ATTRIBUTE}" == "on" ]]; then
|
|
VALUE="off"
|
|
else
|
|
VALUE="on"
|
|
fi
|
|
read -p "$3 [${ATTRIBUTE}]/${VALUE}:" ASK </dev/tty
|
|
else
|
|
read -p "$3 [${ATTRIBUTE}]:" ASK </dev/tty
|
|
fi
|
|
if [[ "${ASK}" != "${ATTRIBUTE}" ]]; then
|
|
if [[ "${ASK}" == "" ]]; then
|
|
#${ZFS} set $1=${ATTRIBUTE} $4
|
|
VAL=${ATTRIBUTE}
|
|
elif [[ "${ASK}" == "-" ]]; then
|
|
show "...with $5"
|
|
${ZFS} set $1=$5 $4
|
|
VAL=$5
|
|
else
|
|
show "..."
|
|
${ZFS} set $1=${ASK} $4
|
|
VAL=${ASK}
|
|
fi
|
|
else
|
|
VAL="${ATTRIBUTE}"
|
|
fi
|
|
}
|
|
|
|
function configure()
|
|
{
|
|
show "********* Configure pools ***********"
|
|
while read ITEM; do
|
|
show " - ${ITEM}"
|
|
attribute rclone:token passwd "Pcloud token" ${ITEM} ""
|
|
if [[ "${VAL}" == "" ]]; then
|
|
continue
|
|
fi
|
|
attribute rclone:password1 passwd "Pcloud password N1" ${ITEM} ""
|
|
if [[ "${VAL}" == "" ]]; then
|
|
continue
|
|
fi
|
|
attribute rclone:password2 passwd "Pcloud password N2" ${ITEM} ""
|
|
if [[ "${VAL}" == "" ]]; then
|
|
continue
|
|
fi
|
|
attribute sync:active bool "Sync active" ${ITEM} off
|
|
if [[ "${VAL}" == "on" ]]; then
|
|
attribute sync:dstpath str "Sync path" ${ITEM} ${RCLONE_PATH}
|
|
attribute sync:exclude str "Sync exclude" ${ITEM} ""
|
|
fi
|
|
attribute restic:password1 passwd "Restic password N1" ${ITEM} ""
|
|
if [[ "${VAL}" == "" ]]; then
|
|
continue
|
|
fi
|
|
attribute restic:password2 passwd "Restic password N2" ${ITEM} ""
|
|
if [[ "${VAL}" == "" ]]; then
|
|
continue
|
|
fi
|
|
attribute backup:active bool "Backup active" ${ITEM} off
|
|
if [[ "${VAL}" == "on" ]]; then
|
|
attribute restic:password passwd "Backup password" ${ITEM} ""
|
|
if [[ "${VAL}" == "" ]]; then
|
|
continue
|
|
fi
|
|
attribute backup:dstpath str "Backup path" ${ITEM} ${RESTIC_PATH}
|
|
attribute backup:exclude str "Backup exclude" ${ITEM} ""
|
|
attribute backup:retention str "Backup retention" ${ITEM} ${RESTIC_MONTHLY},${RESTIC_WEEKLY},${RESTIC_DAILY}
|
|
fi
|
|
done < <(${ZFS} list -o name -d 1 -t filesystem|grep "/")
|
|
}
|
|
|
|
function help()
|
|
{
|
|
show "Usage: admin [ command ] [ args... ]" 1
|
|
show ""
|
|
show "help for COMPLEX commands: admin command"
|
|
show ""
|
|
show "-< Save/Restore"
|
|
show "sync - sync, check data to cloud COMPLEX"
|
|
show "backup - backup data to cloud COMPLEX"
|
|
show "config - configure Restic and Rclone NOARG"
|
|
show ""
|
|
show "-< Tang"
|
|
show "tangcrypt - encrypt /dev/stdin to /dev/stdout NOARG"
|
|
show "tangdecrypt - decrypt /dev/stdin to /dev/stdout NOARG"
|
|
show ""
|
|
exit 2
|
|
}
|
|
|
|
function help_restic()
|
|
{
|
|
show "Usage: admin backup ${ZFS}dataset [ init|view|ls|check|now|prune|remove|config ]" 1
|
|
show ""
|
|
show "Use the restic backend to make some cloud backup operations"
|
|
show ""
|
|
show "init - initialize the data storage on cloud"
|
|
show "view - view snapshots stored on cloud"
|
|
show "ls - list all files 1ARG"
|
|
show "check - check integrity of distant data"
|
|
show "now - perform a backup on cloud"
|
|
show "prune - purge unused data on cloud storage"
|
|
show "remove - remove a snapshot store on cloud 1ARG"
|
|
show "unlock - unlock data storage on cloud"
|
|
show ""
|
|
exit 2
|
|
}
|
|
|
|
function help_rclone()
|
|
{
|
|
show "Usage: admin sync ${ZFS}dataset [ now|dryrun|copy|view|ls|check|config ]" 1
|
|
show ""
|
|
show "Use the rclone backend to make cloud mirror operations"
|
|
show ""
|
|
show "now - perform a sync with the cloud"
|
|
show "dryrun - perform a simulation of sync with the cloud"
|
|
show "copy - copy ARG to local"
|
|
show "view - view interactivly server data"
|
|
show "ls - list all files"
|
|
show "check - check integrity of distant data"
|
|
show ""
|
|
exit 2
|
|
}
|
|
|
|
function encrypt_now() {
|
|
SUMMARY="Encrypts using a Tang binding server policy"
|
|
|
|
if [ "$1" == "--summary" ]; then
|
|
echo "$SUMMARY"
|
|
exit 0
|
|
fi
|
|
|
|
if [ -t 0 ]; then
|
|
exec >&2
|
|
echo
|
|
echo "Usage: clevis encrypt tang CONFIG [-y] < PLAINTEXT > JWE"
|
|
echo
|
|
echo "$SUMMARY"
|
|
echo
|
|
echo " -y Use this option for skipping the advertisement"
|
|
echo " trust check. This can be useful in automated"
|
|
echo " deployments"
|
|
echo
|
|
echo "This command uses the following configuration properties:"
|
|
echo
|
|
echo " url: <string> The base URL of the Tang server (REQUIRED)"
|
|
echo
|
|
echo " thp: <string> The thumbprint of a trusted signing key"
|
|
echo
|
|
echo " adv: <string> A filename containing a trusted advertisement"
|
|
echo " adv: <object> A trusted advertisement (raw JSON)"
|
|
echo
|
|
echo "Obtaining the thumbprint of a trusted signing key is easy. If you"
|
|
echo "have access to the Tang server's database directory, simply do:"
|
|
echo
|
|
echo " $ jose jwk thp -i \$DBDIR/\$SIG.jwk "
|
|
echo
|
|
echo "Alternatively, if you have certainty that your network connection"
|
|
echo "is not compromised (not likely), you can download the advertisement"
|
|
echo "yourself using:"
|
|
echo
|
|
echo " $ curl -f \$URL/adv > adv.jws"
|
|
echo
|
|
exit 2
|
|
fi
|
|
if ! cfg="$(jose fmt -j- -Oo- <<< "$1" 2>/dev/null)"; then
|
|
echo "Configuration is malformed!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
CLEVIS_DEFAULT_THP_ALG=S256 # SHA-256.
|
|
CLEVIS_ALTERNATIVE_THP_ALGS=S1 # SHA-1.
|
|
|
|
trust=
|
|
[ -n "${2}" ] && [ "${2}" == "-y" ] && trust=yes
|
|
|
|
if ! url="$(jose fmt -j- -Og url -u- <<< "$cfg")"; then
|
|
echo "Missing the required 'url' property!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
thp="$(jose fmt -j- -Og thp -Su- <<< "$cfg")" || true
|
|
|
|
### Get the advertisement
|
|
if jws="$(jose fmt -j- -g adv -Oo- <<< "$cfg")"; then
|
|
thp="${thp:-any}"
|
|
elif jws="$(jose fmt -j- -g adv -Su- <<< "$cfg")"; then
|
|
if ! [ -f "$jws" ]; then
|
|
echo "Advertisement file '$jws' not found!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! jws="$(jose fmt --json="${jws}" -Oo- 2>/dev/null)"; then
|
|
echo "Advertisement file '$jws' is malformed!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
thp="${thp:-any}"
|
|
elif ! jws="$(curl -sfg "$url/adv/$thp")"; then
|
|
echo "Unable to fetch advertisement: '$url/adv/$thp'!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! jwks="$(jose fmt --json="${jws}" -Og payload -SyOg keys \
|
|
-AUo- 2>/dev/null)"; then
|
|
echo "Advertisement is malformed!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
### Check advertisement validity
|
|
ver="$(jose jwk use -i- -r -u verify -o- <<< "$jwks")"
|
|
if ! jose jws ver -i "$jws" -k- -a <<< "$ver"; then
|
|
echo "Advertisement is missing signatures!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
### Check advertisement trust
|
|
if [ -z "${trust}" ]; then
|
|
if [ -z "$thp" ]; then
|
|
echo "The advertisement contains the following signing keys:" >&2
|
|
echo >&2
|
|
jose jwk thp -i- -a "${CLEVIS_DEFAULT_THP_ALG}" <<< "$ver" >&2
|
|
echo >&2
|
|
|
|
elif [ "$thp" != "any" ] && \
|
|
! jose jwk thp -i- -f "${thp}" -a "${CLEVIS_DEFAULT_THP_ALG}" \
|
|
-o /dev/null <<< "$ver"; then
|
|
# Thumbprint of trusted JWK did not match the signature. Let's check
|
|
# alternative thumbprints generated with clevis supported hash
|
|
# algorithms to be sure.
|
|
for alg in ${CLEVIS_ALTERNATIVE_THP_ALGS}; do
|
|
srv="$(jose jwk thp -i- -f "${thp}" -a "${alg}" <<< "${ver}")" \
|
|
&& break
|
|
done
|
|
if [ -z "${srv}" ]; then
|
|
echo "Trusted JWK '$thp' did not sign the advertisement!" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
### Perform encryption
|
|
if ! enc="$(jose jwk use -i- -r -u deriveKey -o- <<< "$jwks")"; then
|
|
echo "Key derivation key not available!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
jose fmt -j "$enc" -Og keys -A || enc="{\"keys\":[$enc]}"
|
|
|
|
if ! jwk="$(jose fmt -j- -Og keys -Af- <<< "$enc")"; then
|
|
echo "No exchange keys found!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
jwk="$(jose fmt -j- -Od key_ops -o- <<< "$jwk")"
|
|
jwk="$(jose fmt -j- -Od alg -o- <<< "$jwk")"
|
|
kid="$(jose jwk thp -i- -a "${CLEVIS_DEFAULT_THP_ALG}" <<< "$jwk")"
|
|
jwe='{"protected":{"alg":"ECDH-ES","enc":"A256GCM","clevis":{"pin":"tang","tang":{}}}}'
|
|
jwe="$(jose fmt -j "$jwe" -g protected -q "$kid" -s kid -UUo-)"
|
|
jwe="$(jose fmt -j "$jwe" -g protected -g clevis -g tang -q "$url" -s url -UUUUo-)"
|
|
jwe="$(jose fmt -j "$jwe" -g protected -g clevis -g tang -j- -s adv -UUUUo- <<< "$jwks")"
|
|
exec jose jwe enc -i- -k- -I- -c < <(echo -n "$jwe$jwk"; /bin/cat)
|
|
echo -en ""
|
|
}
|
|
|
|
|
|
function decrypt_now() {
|
|
[ $# -eq 1 ] && [ "$1" == "--summary" ] && exit 2
|
|
|
|
if [ -t 0 ]; then
|
|
exec >&2
|
|
echo
|
|
echo "Usage: clevis decrypt tang < JWE > PLAINTEXT"
|
|
echo
|
|
exit 2
|
|
fi
|
|
|
|
read -r -d . hdr
|
|
|
|
if ! jhd="$(jose b64 dec -i- <<< "$hdr")"; then
|
|
echo "Error decoding JWE protected header!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$(jose fmt -j- -Og clevis -g pin -u- <<< "$jhd")" != "tang" ]; then
|
|
echo "JWE pin mismatch!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! clt="$(jose fmt -j- -Og epk -Oo- <<< "$jhd")"; then
|
|
echo "JWE missing required 'epk' header parameter!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! kid="$(jose fmt -j- -Og kid -Su- <<< "$jhd")"; then
|
|
echo "JWE missing required 'kid' header parameter!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Tang advertisement validation.
|
|
if ! keys="$(jose fmt -j- -Og clevis -g tang -g adv -Oo- <<< "${jhd}")"; then
|
|
echo "JWE missing required 'clevis.tang.adv' header parameter!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Check if the thumbprint we have in `kid' is in the advertised keys.
|
|
CLEVIS_DEFAULT_THP_ALG=S256 # SHA-256.
|
|
CLEVIS_DEFAULT_THP_LEN=43 # Length of SHA-256 thumbprint.
|
|
CLEVIS_ALTERNATIVE_THP_ALGS=S1 # SHA-1.
|
|
|
|
# Issue a warning if we are using a hash that has a shorter length than the
|
|
# default one.
|
|
if [ "${#kid}" -lt "${CLEVIS_DEFAULT_THP_LEN}" ]; then
|
|
echo "WARNING: tang using a deprecated hash for the JWK thumbprints" >&2
|
|
fi
|
|
|
|
if ! srv="$(jose jwk thp -i- -f "${kid}" -a "${CLEVIS_DEFAULT_THP_ALG}" \
|
|
<<< "${keys}")"; then
|
|
# `kid' thumprint not in the advertised keys, but it's possible it was
|
|
# generated using a different algorithm than the default one.
|
|
# Let us try the alternative supported algorithms to make sure `kid'
|
|
# really is not part of the advertised keys.
|
|
for alg in ${CLEVIS_ALTERNATIVE_THP_ALGS}; do
|
|
srv="$(jose jwk thp -i- -f "$kid" -a "${alg}" <<< "${keys}")" && break
|
|
done
|
|
if [ -z "${srv}" ]; then
|
|
echo "JWE header validation of 'clevis.tang.adv' failed: key thumbprint does not match" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if ! url="$(jose fmt -j- -Og clevis -g tang -g url -Su- <<< "$jhd")"; then
|
|
echo "JWE missing required 'clevis.tang.url' header parameter!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! crv="$(jose fmt -j- -Og crv -Su- <<< "$clt")"; then
|
|
echo "Unable to determine EPK's curve!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! eph="$(jose jwk gen -i "{\"alg\":\"ECMR\",\"crv\":\"$crv\"}")"; then
|
|
echo "Error generating ephemeral key!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
xfr="$(jose jwk exc -i '{"alg":"ECMR"}' -l- -r- <<< "$clt$eph")"
|
|
|
|
rec_url="$url/rec/$kid"
|
|
ct="Content-Type: application/jwk+json"
|
|
if ! rep="$(curl -sfg -X POST -H "$ct" --data-binary @- "$rec_url" <<< "$xfr")"; then
|
|
echo "Error communicating with server $url" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! rep="$(jose fmt -j- -Og kty -q EC -EUUg crv -q "$crv" -EUUo- <<< "$rep")"; then
|
|
echo "Received invalid server reply!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
tmp="$(jose jwk exc -i '{"alg":"ECMR"}' -l- -r- <<< "$eph$srv")"
|
|
rep="$(jose jwk pub -i- <<< "$rep")"
|
|
jwk="$(jose jwk exc -l- -r- <<< "$rep$tmp")"
|
|
(echo -n "$jwk$hdr."; /bin/cat) | exec jose jwe dec -k- -i-
|
|
echo -en ""
|
|
}
|
|
|
|
function rcloneapp()
|
|
{
|
|
if [ -z "$1" ]; then
|
|
help_rclone
|
|
fi
|
|
case "$2" in
|
|
copy)
|
|
DEST="/tmp/"
|
|
show "Copy from $3 to ${DEST}" 1
|
|
rclonemount $1 rclone
|
|
${RCLONE_CMD} -vv --config /mnt/usb/rclone/rclone.conf copy crypt:/$2 ${DEST}
|
|
;;
|
|
dryrun)
|
|
show "Dry run..." 1
|
|
echo "********* Synchonize *************" >> /var/log/rclone.log
|
|
date >> /var/log/rclone.log
|
|
rclonemount $1 rclone
|
|
excluded=$(excludepath $RCLONE_EXCLUDE)
|
|
while read src; do
|
|
dstemp=$(basename "${src^}")
|
|
dst=${dstemp^}
|
|
show "$src => $dst"
|
|
echo "$src => $dst" >> /var/log/rclone.log
|
|
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf sync -c -P --dry-run --links --checkers=20 --low-level-retries=10 --retries=10 --retries-sleep=1s --transfers=20 --delete-excluded $excluded --exclude ".zfs/**" $src crypt:/${dst}/ 2>&1 | tee -a /var/log/rclone.log
|
|
done < <(echo "$RCLONE_VOLS"|tr "," "\n")
|
|
echo "***********************************" >> /var/log/rclone.log
|
|
;;
|
|
now)
|
|
show "Synchronize..." 1
|
|
echo "********* Synchonize *************" >> /var/log/rclone.log
|
|
date >> /var/log/rclone.log
|
|
rclonemount $1 rclone
|
|
excluded=$(excludepath $RCLONE_EXCLUDE)
|
|
while read src; do
|
|
dstemp=$(basename "${src^}")
|
|
dst=${dstemp^}
|
|
show "$src => $dst"
|
|
echo "$src => $dst" >> /var/log/rclone.log
|
|
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf sync -c -P ${DRY} --links --checkers=20 --low-level-retries=10 --retries=10 --retries-sleep=1s --transfers=20 --delete-excluded $excluded --exclude ".zfs/**" $src crypt:/${dst}/ 2>&1 | tee -a /var/log/rclone.log
|
|
done < <(echo "$RCLONE_VOLS"|tr "," "\n")
|
|
echo "***********************************" >> /var/log/rclone.log
|
|
;;
|
|
view)
|
|
show "View..." 1
|
|
rclonemount $1 rclone
|
|
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf ncdu crypt:
|
|
;;
|
|
ls)
|
|
show "View files..." 1
|
|
rclonemount $1 rclone
|
|
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf lsd crypt: -R
|
|
;;
|
|
check)
|
|
show "Check..." 1
|
|
echo "************** Check **************" >> /var/log/rclone.log
|
|
date >> /var/log/rclone.log
|
|
rclonemount $1 rclone
|
|
excluded=$(excludepath $RCLONE_EXCLUDE)
|
|
while read src; do
|
|
dstemp=$(basename "${src^}")
|
|
dst=${dstemp^}
|
|
show "$src => $dst"
|
|
echo "$src => $dst" >> /var/log/rclone.log
|
|
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf check -c -P --differ /var/log/differ_${dst}.log --links --checkers=20 --low-level-retries=10 --retries=10 --retries-sleep=1s --transfers=20 $excluded --exclude ".zfs/**" $src crypt:/${dst}/ 2>&1 | tee -a /var/log/rclone.log
|
|
done < <(echo "$RCLONE_VOLS"|tr "," "\n")
|
|
echo "***********************************" >> /var/log/rclone.log
|
|
;;
|
|
*)
|
|
help_rclone
|
|
;;
|
|
esac
|
|
nfcunmount
|
|
}
|
|
|
|
function resticapp()
|
|
{
|
|
if [ -z "$1" ]; then
|
|
help_restic
|
|
fi
|
|
export RCLONE_CONFIG
|
|
export RESTIC_PASSWORD
|
|
case "$2" in
|
|
init)
|
|
show "Initializing..." 1
|
|
echo "********* Initialiazing *************" >> /var/log/restic.log
|
|
date >> /var/log/restc.log
|
|
rclonemount $1 restic
|
|
${RESTIC_CMD} init -r rclone:crypt:/ | tee -a /var/log/restic.log
|
|
echo "***********************************" >> /var/log/restic.log
|
|
;;
|
|
unlock)
|
|
show "Unlocking..." 1
|
|
echo "********* Unlocking *************" >> /var/log/restic.log
|
|
date >> /var/log/restc.log
|
|
rclonemount $1 restic
|
|
${RESTIC_CMD} unlock -r rclone:crypt:/ | tee -a /var/log/restic.log
|
|
echo "***********************************" >> /var/log/restic.log
|
|
;;
|
|
ls)
|
|
show "View files..." 1
|
|
rclonemount $1 restic
|
|
${RESTIC_CMD} ls -r rclone:crypt:/ $3
|
|
;;
|
|
view)
|
|
show "View..." 1
|
|
rclonemount $1 restic
|
|
${RESTIC_CMD} snapshots -r rclone:crypt:/
|
|
;;
|
|
check)
|
|
show "Check..." 1
|
|
echo "************** Check **************" >> /var/log/restic.log
|
|
date >> /var/log/restic.log
|
|
rclonemount $1 restic
|
|
${RESTIC_CMD} check --read-data -r rclone:crypt:/ | tee -a /var/log/restic.log
|
|
${RESTIC_CMD} rebuild-index -r rclone:crypt:/ | tee -a /var/log/restic.log
|
|
echo "***********************************" >> /var/log/restic.log
|
|
;;
|
|
prune)
|
|
show "Cleaning..." 1
|
|
echo "************** Cleaning **************" >> /var/log/restic.log
|
|
date >> /var/log/restic.log
|
|
rclonemount $1 restic
|
|
${RESTIC_CMD} prune -r rclone:crypt:/ | tee -a /var/log/restic.log
|
|
echo "***********************************" >> /var/log/restic.log
|
|
;;
|
|
remove)
|
|
show "Removing..." 1
|
|
echo "************** Removing **************" >> /var/log/restic.log
|
|
date >> /var/log/restic.log
|
|
rclonemount $1 restic
|
|
${RESTIC_CMD} forget $2 -r rclone:crypt:/ | tee -a /var/log/restic.log
|
|
echo "***********************************" >> /var/log/restic.log
|
|
;;
|
|
now)
|
|
show "Backing up..." 1
|
|
echo "************** Backup **************" >> /var/log/restic.log
|
|
date >> /var/log/restic.log
|
|
rclonemount $1 restic
|
|
excluded=$(excludepath $RESTIC_EXCLUDE)
|
|
while read src; do
|
|
dstemp=$(basename "${src^}")
|
|
dst=${dstemp^}
|
|
show "$src => $dst"
|
|
echo "$src => $dst" >> /var/log/restic.log
|
|
${RESTIC_CMD} backup $src -r rclone:crypt:/ --verbose=1 $excluded --exclude ".zfs/**" --tag admin_command|tee -a /var/log/restic.log
|
|
${RESTIC_CMD} forget -r rclone:crypt:/ --tag admin_command --keep-monthly=$RESTIC_MONTHLY --keep-weekly=$RESTIC_WEEKLY --keep-daily=$RESTIC_DAILY
|
|
done < <(echo "$RESTIC_VOLS"|tr "," "\n")
|
|
echo "***********************************" >> /var/log/restic.log
|
|
;;
|
|
*)
|
|
help_restic
|
|
;;
|
|
esac
|
|
nfcunmount
|
|
}
|
|
|
|
if [[ ! -f "${CONFIGURATION}" ]]; then
|
|
show "Creating configuration file..."
|
|
extract 4
|
|
fi
|
|
|
|
source "${CONFIGURATION}"
|
|
|
|
nfcunmount
|
|
COMMAND="$1"
|
|
shift
|
|
case "${COMMAND}" in
|
|
config)
|
|
configure
|
|
;;
|
|
backup)
|
|
resticapp $1 $2 $3
|
|
;;
|
|
sync)
|
|
rcloneapp $1 $2 $3
|
|
;;
|
|
nfcunmount)
|
|
nfcunmount
|
|
;;
|
|
tangcrypt)
|
|
cat /dev/stdin|encrypt_now "{\"url\": \"${URL}\"}"
|
|
;;
|
|
tangdecrypt)
|
|
cat /dev/stdin|decrypt_now "{\"url\": \"${URL}\"}"
|
|
;;
|
|
*)
|
|
help
|
|
;;
|
|
esac
|
|
|
|
#4/home/user/scripts/admin.conf,644
|
|
#4# Hard settings
|
|
#4ALIB="--module /usr/lib/x86_64-linux-gnu/libykcs11.so.2"
|
|
#4ZFS="zfs"
|
|
#4PZFS="zfs"
|
|
#4ZPOOL="zpool"
|
|
#4PZPOOL="zpool"
|
|
#4PATH="/usr/local/bin:/usr/bin:$PATH"
|
|
#4FONT=""
|
|
#4MAXSIZE=700
|
|
#4RCLONE_CMD="rclone"
|
|
#4RESTIC_CMD="restic"
|
|
#4
|
|
#4# Settings
|
|
#4RCLONE_CONFIG="/mnt/usb/rclone/rclone.conf"
|
|
#4URL="https://tang.ia86.cc"
|
|
#4
|
|
#4# Default parameters
|
|
#4RCLONE_PATH="/hetzner/kube.ia86.cc"
|
|
#4RCLONE_EXCLUDE=""
|
|
#4RESTIC_PATH="/hetzner/restic"
|
|
#4RESTIC_MONTHLY="12"
|
|
#4RESTIC_WEEKLY="10"
|
|
#4RESTIC_DAILY="31"
|
|
#4RESTIC_EXCLUDE=""
|
|
|
|
#5/mnt/usb/rclone/rclone.conf,644
|
|
#5[pcloud]
|
|
#5type = pcloud
|
|
#5hostname = eapi.pcloud.com
|
|
#5token = {"access_token":"%TOKEN%","token_type":"bearer","expiry":"0001-01-01T00:00:00Z"}
|
|
#5[crypt]
|
|
#5type = crypt
|
|
#5remote = pcloud:%REMOTE%
|
|
#5filename_encryption = standard
|
|
#5directory_name_encryption = true
|
|
#5password = %PASSWD1%
|
|
#5password2 = %PASSWD2%
|
|
#5[sauvegarde]
|
|
#5type = crypt
|
|
#5remote = pcloud:%REMOTE%
|
|
#5filename_encryption = standard
|
|
#5directory_name_encryption = true
|
|
#5password = %PASSWD3%
|
|
#5password2 = %PASSWD4%
|