Skip to content

Commit afd65c6

Browse files
edetersmitten
ede
authored andcommitted
release 2.3.1
1 parent f839681 commit afd65c6

File tree

1 file changed

+93
-33
lines changed

1 file changed

+93
-33
lines changed

duply.sh

+93-33
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
# changed from ftplicity to duply. #
1010
# See http://duply.net or http://ftplicity.sourceforge.net/ for more info. #
1111
# (c) 2006 Christiane Ruetten, Heise Zeitschriften Verlag, Germany #
12-
# (c) 2008-2019 Edgar Soldin (changes since version 1.3) #
12+
# (c) 2008-2020 Edgar Soldin (changes since version 1.3) #
1313
################################################################################
1414
# LICENSE: #
1515
# This program is licensed under GPLv2. #
@@ -33,6 +33,16 @@
3333
# - import/export profile from/to .tgz function !!!
3434
#
3535
# CHANGELOG:
36+
# 2.3.1 (11.2.2021)
37+
# - bugfix 123: symmetric encryption errs out, asks for '' private key
38+
#
39+
# 2.3 (30.12.2020)
40+
# - don't import whole key pair anymore if only pub/sec is requested
41+
# - gpg import routine informs on missing key files in profile now
42+
# - add check/import needed secret key for decryption
43+
# - featreq 50: Disable GPG key backups, implemented/added settings
44+
# GPG_IMPORT/GPG_EXPORT='disabled' to conf template
45+
#
3646
# 2.2.2 (24.02.2020)
3747
# - bugfix 120: Failures in "Autoset trust of key" during restore
3848
# because of gpg2.2 fingerprint output change
@@ -520,7 +530,7 @@ function python_binary {
520530
ME_LONG="$0"
521531
ME="$(basename $0)"
522532
ME_NAME="${ME%%.*}"
523-
ME_VERSION="2.2.2"
533+
ME_VERSION="2.3.1"
524534
ME_WEBSITE="http://duply.net"
525535

526536
# default config values
@@ -857,6 +867,10 @@ GPG_PW='${DEFAULT_GPG_PW}'
857867
858868
# disable preliminary tests with the following setting
859869
#GPG_TEST='disabled'
870+
# disable automatic gpg key importing altogether
871+
#GPG_IMPORT='disabled'
872+
# disable automatic gpg key exporting to profile folder
873+
#GPG_EXPORT='disabled'
860874
861875
# backend, credentials & location of the backup target (URL-Format)
862876
# generic syntax is
@@ -1080,25 +1094,15 @@ Hint${hint:+s}:
10801094
Don't forget the used _password_ as you will need it.
10811095
When done enter the 8 digit id & the password in the profile conf file.
10821096
1083-
The key id can be found doing a 'gpg --list-keys'. In the example output
1084-
below the key id would be FFFFFFFF for the public key.
1097+
The key id can be found doing a 'gpg --list-keys'. In the example output
1098+
below the key id for the public key would be FFFFFFFF.
10851099
10861100
pub 1024D/FFFFFFFF 2007-12-17
10871101
uid duplicity
10881102
sub 2048g/899FE27F 2007-12-17
10891103
"
10901104
}
10911105

1092-
function error_gpg_key {
1093-
local KEY_ID="$1"
1094-
local KIND="$2"
1095-
error_gpg "${KIND} gpg key '${KEY_ID}' cannot be found." \
1096-
"Doublecheck if the above key is listed by 'gpg --list-keys' or available
1097-
as gpg key file '$(basename "$(gpg_keyfile "${KEY_ID}")")' in the profile folder.
1098-
If not you can put it there and $ME_NAME will autoimport it on the next run.
1099-
Alternatively import it manually as the user you plan to run $ME_NAME with."
1100-
}
1101-
11021106
function error_gpg_test {
11031107
[ -n "$2" ] && local hint="\n $2\n\n "
11041108

@@ -1525,10 +1529,18 @@ function join {
15251529
echo $OUT
15261530
}
15271531

1532+
function gpg_testing {
1533+
[ "$GPG_TEST" != "disabled" ]
1534+
}
1535+
15281536
function gpg_signing {
15291537
echo ${GPG_KEY_SIGN} | grep -v -q -e '^disabled$'
15301538
}
15311539

1540+
function gpg_keytype {
1541+
echo "$1" | awk '/^PUB$/{print "public"}/^SEC$/{print "secret"}'
1542+
}
1543+
15321544
# parameter key id, key_type
15331545
function gpg_keyfile {
15341546
local GPG_KEY=$(gpg_key_legalize $1) TYPE="$2"
@@ -1539,10 +1551,15 @@ function gpg_keyfile {
15391551
# parameter key id
15401552
function gpg_import {
15411553
local i FILE FOUND=0 KEY_ID="$1" KEY_TYPE="$2" KEY_FP="" ERR=0
1554+
[ "$GPG_IMPORT" = "disabled" ] && {
1555+
echo "Skipping import of needed $(gpg_keytype "$KEY_TYPE") key '$KEY_ID'. (GPG_IMPORT='disabled')"
1556+
return
1557+
}
1558+
15421559
# create a list of legacy key file names and current naming scheme
15431560
# we always import pub and sec if they are avail in conf folder
15441561
local KEYFILES=( "$CONFDIR/gpgkey" $(gpg_keyfile "$KEY_ID") \
1545-
$(gpg_keyfile "$KEY_ID" PUB) $(gpg_keyfile "$KEY_ID" SEC))
1562+
$(gpg_keyfile "$KEY_ID" "$KEY_TYPE") )
15461563

15471564
# Try autoimport from existing old gpgkey files
15481565
# and new gpgkey.XXX.asc files (since v1.4.2)
@@ -1564,7 +1581,8 @@ function gpg_import {
15641581
done
15651582

15661583
if [ "$FOUND" -eq 0 ]; then
1567-
warning "No keyfile for '$KEY_ID' found in profile\n'$CONFDIR'."
1584+
echo "Notice: No keyfile for '$KEY_ID' found in profile folder."
1585+
return 1
15681586
fi
15691587

15701588
# try to set trust automagically
@@ -1592,15 +1610,21 @@ function gpg_fingerprint {
15921610
}
15931611

15941612
function gpg_export_if_needed {
1613+
[ "$GPG_EXPORT" = 'disabled' ] && { \
1614+
echo "Skipping export of gpg keys. (GPG_EXPORT='disabled')"
1615+
return
1616+
}
1617+
15951618
local SUCCESS FILE KEY_TYPE
15961619
local TMPFILE="$TEMP_DIR/${ME_NAME}.$$.$(date_fix %s).gpgexp"
15971620
for KEY_ID in "$@"; do
15981621
# check if already exported, do it if not
15991622
for KEY_TYPE in PUB SEC; do
16001623
FILE="$(gpg_keyfile "$KEY_ID" $KEY_TYPE)"
16011624
if [ ! -f "$FILE" ] && eval gpg_$(tolower $KEY_TYPE)_avail \"$KEY_ID\"; then
1625+
16021626
# exporting
1603-
CMD_MSG="Backup $KEY_TYPE key '$KEY_ID' to profile."
1627+
CMD_MSG="Backup $(gpg_keytype "$KEY_TYPE") key '$KEY_ID' to profile."
16041628
# gpg2.1 insists on passphrase here, gpg2.0- happily exports w/o it
16051629
# we pipe an empty string when GPG_PW is not set to avoid gpg silently waiting for input
16061630
run_cmd $(gpg_pass_pipein GPG_PW_SIGN GPG_PW) gpg $GPG_OPTS $GPG_USEAGENT $(gpg_param_passwd GPG_PW_SIGN GPG_PW) --armor --export"$(test "SEC" = "$KEY_TYPE" && echo -secret-keys)" $(qw "$KEY_ID") '>>' $(qw "$TMPFILE")
@@ -1695,6 +1719,9 @@ function gpg_passwd {
16951719

16961720
# return success if at least one secret key is available
16971721
function gpg_key_decryptable {
1722+
# no keys, no problem
1723+
gpg_symmetric && return 0
1724+
16981725
local KEY_ID
16991726
for KEY_ID in "${GPG_KEYS_ENC_ARRAY[@]}"; do
17001727
gpg_sec_avail "$KEY_ID" && return 0
@@ -1715,7 +1742,7 @@ function gpg_param_passwd {
17151742
fi
17161743
}
17171744

1718-
# select the earlist defined and create an "echo <value> |" string
1745+
# select the earliest defined and create an "echo <value> |" string
17191746
function gpg_pass_pipein {
17201747
var_isset GPG_USEAGENT && exit 1
17211748

@@ -2059,18 +2086,50 @@ Tip: Separate signing keys may have empty passwords e.g. GPG_PW_SIGN=''.
20592086
Tip2: Use gpg-agent."
20602087
fi
20612088

2062-
# check gpg encr public keys availability
2089+
# test - GPG KEY AVAILABILITY ##################################################
2090+
2091+
# check gpg public keys availability, try import if needed
20632092
for (( i = 0 ; i < ${#GPG_KEYS_ENC_ARRAY[@]} ; i++ )); do
20642093
KEY_ID="${GPG_KEYS_ENC_ARRAY[$i]}"
20652094
# test availability, try to import, retest
20662095
if ! gpg_pub_avail "${KEY_ID}"; then
2067-
echo "Encryption public key '${KEY_ID}' not found."
2096+
echo "Encryption public key '${KEY_ID}' not in keychain. Try to import from profile."
20682097
gpg_import "${KEY_ID}" PUB
20692098
gpg_key_cache RESET "${KEY_ID}"
2070-
gpg_pub_avail "${KEY_ID}" || error_gpg_key "${KEY_ID}" "Public"
2099+
gpg_pub_avail "${KEY_ID}" || { \
2100+
gpg_testing && error_gpg \
2101+
"Needed public gpg key '${KEY_ID}' is not available in keychain." \
2102+
"Doublecheck if the above key is listed by 'gpg --list-keys' or available
2103+
as gpg key file '$(basename "$(gpg_keyfile "${KEY_ID}")")' in the profile folder.
2104+
If not you can put it there and $ME_NAME will autoimport it on the next run.
2105+
Alternatively import it manually as the user you plan to run $ME_NAME with."
2106+
}
2107+
else
2108+
echo "Public key '${KEY_ID}' found in keychain."
20712109
fi
20722110
done
20732111

2112+
# check gpg encr secret encryption keys availability and fail
2113+
# if none is available after a round of importing trials
2114+
gpg_key_decryptable || \
2115+
{
2116+
echo "Missing secret keys for decryption in keychain."
2117+
for (( i = 0 ; i < ${#GPG_KEYS_ENC_ARRAY[@]} ; i++ )); do
2118+
KEY_ID="${GPG_KEYS_ENC_ARRAY[$i]}"
2119+
# test availability, try to import, retest
2120+
if ! gpg_sec_avail "${KEY_ID}"; then
2121+
echo "Try to import secret key '${KEY_ID}' from profile."
2122+
gpg_import "${KEY_ID}" SEC
2123+
gpg_key_cache RESET "${KEY_ID}"
2124+
fi
2125+
done
2126+
gpg_key_decryptable || \
2127+
{
2128+
gpg_testing && error_gpg_test "None of the configured keys '$(join "','" "${GPG_KEYS_ENC_ARRAY[@]}")' \
2129+
has a secret key in the keychain. Decryption will be impossible!"
2130+
}
2131+
}
2132+
20742133
# gpg secret sign key availability
20752134
# if none set, autoset first encryption key as sign key
20762135
if ! gpg_signing; then
@@ -2086,6 +2145,7 @@ elif ! var_isset 'GPG_KEY_SIGN'; then
20862145
if gpg_sec_avail "${KEY_ID}"; then
20872146
GPG_KEY_SIGN="${KEY_ID}"
20882147
else
2148+
echo "Signing secret key '${KEY_ID}' not found."
20892149
gpg_import "${KEY_ID}" SEC
20902150
gpg_key_cache RESET "${KEY_ID}"
20912151
if gpg_sec_avail "${KEY_ID}"; then
@@ -2157,15 +2217,15 @@ echo $@ $DUPL_PARAMS | grep -q -e '--asynchronous-upload' && FACTOR=2 || FACTOR=
21572217
# test - GPG SANITY #####################################################################
21582218
# if encryption is disabled, skip this whole section
21592219
if gpg_disabled; then
2160-
echo -e "Test - En/Decryption skipped. (GPG disabled)"
2161-
elif [ "$GPG_TEST" = "disabled" ]; then
2162-
echo -e "Test - En/Decryption skipped. (Testing disabled)"
2220+
echo -e "Test - En/Decryption skipped. (GPG='disabled')"
2221+
elif ! gpg_testing; then
2222+
echo -e "Test - En/Decryption skipped. (GPG_TEST='disabled')"
21632223
else
21642224

2165-
GPG_TEST="$TEMP_DIR/${ME_NAME}.$$.$(date_fix %s)"
2225+
GPG_TEST_PREFIX="$TEMP_DIR/${ME_NAME}.$$.$(date_fix %s)"
21662226
function cleanup_gpgtest {
2167-
echo -en "Cleanup - Delete '${GPG_TEST}_*'"
2168-
rm "${GPG_TEST}"_* 2>/dev/null && echo "(OK)" || echo "(FAILED)"
2227+
echo -en "Cleanup - Delete '${GPG_TEST_PREFIX}_*'"
2228+
rm "${GPG_TEST_PREFIX}"_* 2>/dev/null && echo "(OK)" || echo "(FAILED)"
21692229
}
21702230

21712231
# signing enabled?
@@ -2182,7 +2242,7 @@ if [ ${#GPG_KEYS_ENC_ARRAY[@]} -gt 0 ]; then
21822242
done
21832243
# check encrypting
21842244
CMD_MSG="Test - Encrypt to '$(join "','" "${GPG_KEYS_ENC_ARRAY[@]}")'${CMD_MSG_SIGN:+ & $CMD_MSG_SIGN}"
2185-
run_cmd $(gpg_pass_pipein GPG_PW_SIGN GPG_PW) gpg $CMD_PARAM_SIGN $(gpg_param_passwd GPG_PW_SIGN GPG_PW) $CMD_PARAMS $GPG_USEAGENT --status-fd 1 $GPG_OPTS -o $(qw "${GPG_TEST}_ENC") -e $(qw "$ME_LONG")
2245+
run_cmd $(gpg_pass_pipein GPG_PW_SIGN GPG_PW) gpg $CMD_PARAM_SIGN $(gpg_param_passwd GPG_PW_SIGN GPG_PW) $CMD_PARAMS $GPG_USEAGENT --status-fd 1 $GPG_OPTS -o $(qw "${GPG_TEST_PREFIX}_ENC") -e $(qw "$ME_LONG")
21862246
CMD_ERR=$?
21872247

21882248
if [ "$CMD_ERR" != "0" ]; then
@@ -2196,7 +2256,7 @@ if [ ${#GPG_KEYS_ENC_ARRAY[@]} -gt 0 ]; then
21962256
# check decrypting
21972257
CMD_MSG="Test - Decrypt"
21982258
gpg_key_decryptable || CMD_DISABLED="No matching secret key available."
2199-
run_cmd $(gpg_pass_pipein GPG_PW) gpg $(gpg_param_passwd GPG_PW) $GPG_OPTS -o $(qw "${GPG_TEST}_DEC") $GPG_USEAGENT -d $(qw "${GPG_TEST}_ENC")
2259+
run_cmd $(gpg_pass_pipein GPG_PW) gpg $(gpg_param_passwd GPG_PW) $GPG_OPTS -o $(qw "${GPG_TEST_PREFIX}_DEC") $GPG_USEAGENT -d $(qw "${GPG_TEST_PREFIX}_ENC")
22002260
CMD_ERR=$?
22012261

22022262
if [ "$CMD_ERR" != "0" ]; then
@@ -2207,15 +2267,15 @@ if [ ${#GPG_KEYS_ENC_ARRAY[@]} -gt 0 ]; then
22072267
else
22082268
# check encrypting
22092269
CMD_MSG="Test - Encryption with passphrase${CMD_MSG_SIGN:+ & $CMD_MSG_SIGN}"
2210-
run_cmd $(gpg_pass_pipein GPG_PW) gpg $GPG_OPTS $CMD_PARAM_SIGN --passphrase-fd 0 -o $(qw "${GPG_TEST}_ENC") --batch -c $(qw "$ME_LONG")
2270+
run_cmd $(gpg_pass_pipein GPG_PW) gpg $GPG_OPTS $CMD_PARAM_SIGN --passphrase-fd 0 -o $(qw "${GPG_TEST_PREFIX}_ENC") --batch -c $(qw "$ME_LONG")
22112271
CMD_ERR=$?
22122272
if [ "$CMD_ERR" != "0" ]; then
22132273
error_gpg_test "Encryption failed.${CMD_OUT:+\n$CMD_OUT}"
22142274
fi
22152275

22162276
# check decrypting
22172277
CMD_MSG="Test - Decryption with passphrase"
2218-
run_cmd $(gpg_pass_pipein GPG_PW) gpg $GPG_OPTS --passphrase-fd 0 -o $(qw "${GPG_TEST}_DEC") --batch -d $(qw "${GPG_TEST}_ENC")
2278+
run_cmd $(gpg_pass_pipein GPG_PW) gpg $GPG_OPTS --passphrase-fd 0 -o $(qw "${GPG_TEST_PREFIX}_DEC") --batch -d $(qw "${GPG_TEST_PREFIX}_ENC")
22192279
CMD_ERR=$?
22202280
if [ "$CMD_ERR" != "0" ]; then
22212281
error_gpg_test "Decryption failed.${CMD_OUT:+\n$CMD_OUT}"
@@ -2224,8 +2284,8 @@ fi
22242284

22252285
# compare original w/ decryptginal
22262286
CMD_MSG="Test - Compare"
2227-
[ -r "${GPG_TEST}_DEC" ] || CMD_DISABLED="File not found. Nothing to compare."
2228-
run_cmd "test \"\$(cat '$ME_LONG')\" = \"\$(cat '${GPG_TEST}_DEC')\""
2287+
[ -r "${GPG_TEST_PREFIX}_DEC" ] || CMD_DISABLED="File not found. Nothing to compare."
2288+
run_cmd "test \"\$(cat '$ME_LONG')\" = \"\$(cat '${GPG_TEST_PREFIX}_DEC')\""
22292289
CMD_ERR=$?
22302290
if [ "$CMD_ERR" = "0" ]; then
22312291
cleanup_gpgtest

0 commit comments

Comments
 (0)