Skip to content

Commit 17b3853

Browse files
authored
Merge pull request #243 from tegonal/feature/secret-utils
introduce secret-utils with helpers for secret-tool
2 parents 4a5062d + 3c77445 commit 17b3853

File tree

5 files changed

+222
-1
lines changed

5 files changed

+222
-1
lines changed

.github/ISSUE_TEMPLATE/bug_report.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ body:
6060
- utility/replace-snippet.sh
6161
- utility/replace-help-snippet.sh
6262
- utility/string-utils.sh
63+
- utility/secret-utils.sh
6364
- utility/source-once.sh
6465
- utility/update-bash-docu.sh
6566
- setup.sh

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ The scripts are ordered by topic:
142142
- [Parse utils](#parse-utils)
143143
- [Recursive `declare -p`](#recursive-declare--p)
144144
- [Replace Snippets](#replace-snippets)
145+
- [Secret utils](#secret-utils)
145146
- [`source` once](#source-once)
146147
- [string utils](#string-utils)
147148
- [Update Documentation](#update-bash-documentation)
@@ -2015,6 +2016,45 @@ cat "$file"
20152016

20162017
</utility-replace-snippet>
20172018

2019+
## Secret utils
2020+
2021+
Utility functions around secrets and `secret-tool`.
2022+
2023+
<utility-secret-utils>
2024+
2025+
<!-- auto-generated, do not modify here but in src/utility/secret-utils.sh.doc -->
2026+
```bash
2027+
#!/usr/bin/env bash
2028+
set -euo pipefail
2029+
shopt -s inherit_errexit
2030+
# Assumes tegonal's scripts were fetched with gt - adjust location accordingly
2031+
dir_of_tegonal_scripts="$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" >/dev/null && pwd 2>/dev/null)/../lib/tegonal-scripts/src"
2032+
source "$dir_of_tegonal_scripts/setup.sh" "$dir_of_tegonal_scripts"
2033+
2034+
source "$dir_of_tegonal_scripts/utility/secret-utils.sh"
2035+
2036+
# stores the entered password into the variable `secret`
2037+
promptForSecret "enter your password: " secret
2038+
2039+
# retrieves a secret identified by `group` and `key` via secret-tool from the login keyring
2040+
# shellcheck disable=SC2034 # we know secret is not used, only a sample
2041+
secret="$(getSecretViaSecretTool "group" "key")"
2042+
2043+
# stores the secret identified by `group` and `key` and value `mySecret` via secret-tool into the login keyring
2044+
storeSecretViaSecretTool "group" "key" "label as shown in e.g. seahorse" "mySecret"
2045+
2046+
# stores the secret identified by `group` and `key` via secret-tool into the login keyring
2047+
# uses stdin as input (prompts for a password if there is no input)
2048+
storeSecretViaSecretTool "group" "key" "label as shown in e.g. seahorse"
2049+
2050+
# retrieves a secret identified by `group` and `key` via secret-tool from the login keyring and
2051+
# stores it in the variable password. If the secret does not exist yet, then the given prompt is used and the secret is
2052+
# stores accordingly
2053+
getSecretViaSecretToolOrPromptAndStore "group" "key" "label as shown in e.g. seahorse" "enter your password: " password
2054+
```
2055+
2056+
</utility-secret-utils>
2057+
20182058
## Source once
20192059

20202060
Establishes a guard by creating a variable based on the file which shall be sourced.

src/utility/cleanups.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ if ! [[ -v dir_of_tegonal_scripts ]]; then
4141
dir_of_tegonal_scripts="$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" >/dev/null && pwd 2>/dev/null)/.."
4242
source "$dir_of_tegonal_scripts/setup.sh" "$dir_of_tegonal_scripts"
4343
fi
44-
sourceOnce "$dir_of_tegonal_scripts/utility/log.sh"
4544

4645
function removeUnusedSignatures() {
4746
if ! (($# == 1)); then

src/utility/secret-utils.doc.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
shopt -s inherit_errexit
4+
# Assumes tegonal's scripts were fetched with gt - adjust location accordingly
5+
dir_of_tegonal_scripts="$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" >/dev/null && pwd 2>/dev/null)/../lib/tegonal-scripts/src"
6+
source "$dir_of_tegonal_scripts/setup.sh" "$dir_of_tegonal_scripts"
7+
8+
source "$dir_of_tegonal_scripts/utility/secret-utils.sh"
9+
10+
# stores the entered password into the variable `secret`
11+
promptForSecret "enter your password: " secret
12+
13+
# retrieves a secret identified by `group` and `key` via secret-tool from the login keyring
14+
# shellcheck disable=SC2034 # we know secret is not used, only a sample
15+
secret="$(getSecretViaSecretTool "group" "key")"
16+
17+
# stores the secret identified by `group` and `key` and value `mySecret` via secret-tool into the login keyring
18+
storeSecretViaSecretTool "group" "key" "label as shown in e.g. seahorse" "mySecret"
19+
20+
# stores the secret identified by `group` and `key` via secret-tool into the login keyring
21+
# uses stdin as input (prompts for a password if there is no input)
22+
storeSecretViaSecretTool "group" "key" "label as shown in e.g. seahorse"
23+
24+
# retrieves a secret identified by `group` and `key` via secret-tool from the login keyring and
25+
# stores it in the variable password. If the secret does not exist yet, then the given prompt is used and the secret is
26+
# stores accordingly
27+
getSecretViaSecretToolOrPromptAndStore "group" "key" "label as shown in e.g. seahorse" "enter your password: " password

src/utility/secret-utils.sh

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
#!/usr/bin/env bash
2+
#
3+
# __ __
4+
# / /____ ___ ____ ___ ___ _/ / This script is provided to you by https://github.com/tegonal/scripts
5+
# / __/ -_) _ `/ _ \/ _ \/ _ `/ / It is licensed under Apache License 2.0
6+
# \__/\__/\_, /\___/_//_/\_,_/_/ Please report bugs and contribute back your improvements
7+
# /___/
8+
# Version: v4.5.0-SNAPSHOT
9+
#
10+
####### Description #############
11+
#
12+
# Utility functions for secret-tool and secrets in general.
13+
#
14+
####### Usage ###################
15+
#
16+
# #!/usr/bin/env bash
17+
# set -euo pipefail
18+
# shopt -s inherit_errexit
19+
# # Assumes tegonal's scripts were fetched with gt - adjust location accordingly
20+
# dir_of_tegonal_scripts="$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" >/dev/null && pwd 2>/dev/null)/../lib/tegonal-scripts/src"
21+
# source "$dir_of_tegonal_scripts/setup.sh" "$dir_of_tegonal_scripts"
22+
#
23+
# source "$dir_of_tegonal_scripts/utility/secret-utils.sh"
24+
#
25+
# # stores the entered password into the variable `secret`
26+
# promptForSecret "enter your password: " secret
27+
#
28+
# # retrieves a secret identified by `group` and `key` via secret-tool from the login keyring
29+
# # shellcheck disable=SC2034 # we know secret is not used, only a sample
30+
# secret="$(getSecretViaSecretTool "group" "key")"
31+
#
32+
# # stores the secret identified by `group` and `key` and value `mySecret` via secret-tool into the login keyring
33+
# storeSecretViaSecretTool "group" "key" "label as shown in e.g. seahorse" "mySecret"
34+
#
35+
# # stores the secret identified by `group` and `key` via secret-tool into the login keyring
36+
# # uses stdin as input (prompts for a password if there is no input)
37+
# storeSecretViaSecretTool "group" "key" "label as shown in e.g. seahorse"
38+
#
39+
# # retrieves a secret identified by `group` and `key` via secret-tool from the login keyring and
40+
# # stores it in the variable password. If the secret does not exist yet, then the given prompt is used and the secret is
41+
# # stores accordingly
42+
# getSecretViaSecretToolOrPromptAndStore "group" "key" "label as shown in e.g. seahorse" "enter your password: " password
43+
#
44+
###################################
45+
set -euo pipefail
46+
shopt -s inherit_errexit
47+
unset CDPATH
48+
49+
if ! [[ -v dir_of_tegonal_scripts ]]; then
50+
dir_of_tegonal_scripts="$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" >/dev/null && pwd 2>/dev/null)/.."
51+
source "$dir_of_tegonal_scripts/setup.sh" "$dir_of_tegonal_scripts"
52+
fi
53+
sourceOnce "$dir_of_tegonal_scripts/utility/checks.sh"
54+
sourceOnce "$dir_of_tegonal_scripts/utility/parse-utils.sh"
55+
56+
function getSecretViaSecretToolOrPromptAndStore() {
57+
58+
exitIfCommandDoesNotExist "secret-tool" "install it via 'sudo apt install libsecret-tools'"
59+
60+
if (($# != 5)); then
61+
logError "getSecretViaSecretToolOrPromptAndStore requires exactly 5 arguments, given \033[0;36m%s\033[0m\nFollowing a description of the parameters:\n" "$#"
62+
echo >&2 "1: group the group in which the secret shall be stored -- referred to as attribute in secret-tool's documentation"
63+
echo >&2 "2: key the secret key -- referred to as value in the secret-tool's documentation"
64+
echo >&2 '3: label the description of this key (will be shown e.g. in seahorse)'
65+
echo >&2 '4: prompt the text used in case the secret does not yet exist'
66+
echo >&2 '5: outVar variable name where the secret shall be stored (next to the secret-tool itself)'
67+
exit 1
68+
fi
69+
local -r getSecretViaSecretToolOrPromptAndStore_group=$1
70+
local -r getSecretViaSecretToolOrPromptAndStore_key=$2
71+
local -r getSecretViaSecretToolOrPromptAndStore_label=$3
72+
local -r getSecretViaSecretToolOrPromptAndStore_prompt=$4
73+
local -r getSecretViaSecretToolOrPromptAndStore_outVar=$5
74+
75+
exitIfVariablesNotDeclared "$getSecretViaSecretToolOrPromptAndStore_outVar"
76+
77+
local getSecretViaSecretToolOrPromptAndStore_secret
78+
79+
# shellcheck disable=SC2310 # we are aware of that set -e has no effect for getSecretViaSecretTool
80+
if ! getSecretViaSecretToolOrPromptAndStore_secret=$(getSecretViaSecretTool "$getSecretViaSecretToolOrPromptAndStore_group" "$getSecretViaSecretToolOrPromptAndStore_key"); then
81+
promptForSecret "$getSecretViaSecretToolOrPromptAndStore_prompt" getSecretViaSecretToolOrPromptAndStore_outVar
82+
storeSecretViaSecretTool "$getSecretViaSecretToolOrPromptAndStore_group" "$getSecretViaSecretToolOrPromptAndStore_key" "$getSecretViaSecretToolOrPromptAndStore_label" "$getSecretViaSecretToolOrPromptAndStore_secret"
83+
fi
84+
assignToVariableInOuterScope "$getSecretViaSecretToolOrPromptAndStore_outVar" "$getSecretViaSecretToolOrPromptAndStore_secret"
85+
}
86+
87+
function getSecretViaSecretTool() {
88+
exitIfCommandDoesNotExist "secret-tool" "install it via 'sudo apt install libsecret-tools'"
89+
if (($# != 2)); then
90+
logError "getSecretViaSecretTool requires exactly 2 arguments, given \033[0;36m%s\033[0m\nFollowing a description of the parameters:\n" "$#"
91+
echo >&2 "1: group the group from which the secret shall be read -- referred to as attribute in secret-tool's documentation"
92+
echo >&2 "2: key the secret key -- referred to as value in the secret-tool's documentation"
93+
exit 1
94+
fi
95+
secret-tool lookup "$1" "$2"
96+
}
97+
98+
function storeSecretViaSecretTool() {
99+
exitIfCommandDoesNotExist "secret-tool" "install it via 'sudo apt install libsecret-tools'"
100+
if (($# != 3)) && (($# != 4)); then
101+
logError "storeSecretViaSecretTool requires either 3 or 4 arguments, given \033[0;36m%s\033[0m\nFollowing a description of the parameters:\n" "$#"
102+
echo >&2 "1: group the group from which the secret shall be read -- referred to as attribute in secret-tool's documentation"
103+
echo >&2 "2: key the secret key -- referred to as value in the secret-tool's documentation"
104+
echo >&2 '3: label the description of this key (will be shown e.g. in seahorse)'
105+
echo >&2 '4: secret the secret as such (or pass it via stdin)'
106+
exit 1
107+
fi
108+
if (($# == 4)); then
109+
echo -n "$4" | secret-tool store --label="$3" "$1" "$2"
110+
else
111+
secret-tool store --label="$3" "$1" "$2"
112+
fi
113+
}
114+
115+
function promptForSecret() {
116+
if (($# != 2)); then
117+
logError "promptForSecret requires exactly 2 arguments, given \033[0;36m%s\033[0m\nFollowing a description of the parameters:\n" "$#"
118+
echo >&2 '1: prompt the text used in the prompt'
119+
echo >&2 '2: outVar variable name to which the secret shall be assigned'
120+
echo "bla1"
121+
exit 1
122+
fi
123+
124+
exitIfVariablesNotDeclared "$2"
125+
126+
# shellcheck disable=SC2059 # we want to be able to use newline in the $prompt, hence OK
127+
printf "$1"
128+
129+
local promptForSecret_password=''
130+
131+
while IFS= read -r -s -n 1 promptForSecret_char; do
132+
if [[ $promptForSecret_char == $'\0' || $promptForSecret_char == $'\n' ]]; then
133+
printf "break"
134+
break
135+
fi
136+
137+
if [[ $promptForSecret_char == $'\177' ]]; then
138+
if [[ -n $promptForSecret_password ]]; then
139+
promptForSecret_password="${promptForSecret_password%?}"
140+
printf "\b \b" # move back, overwrite with space, move back again
141+
fi
142+
else
143+
promptForSecret_password+="$promptForSecret_char"
144+
printf "*"
145+
fi
146+
done
147+
148+
printf "\n"
149+
150+
if [[ -z $promptForSecret_password ]]; then
151+
die "looks like you pressed ENTER too early, secret was empty"
152+
fi
153+
assignToVariableInOuterScope "$2" "$promptForSecret_password"
154+
}

0 commit comments

Comments
 (0)