8 cred - Credentials and secrets management in command line
12 cred I<SUBCOMMAND> I<SITE> [I<ARGUMENTS>]
14 cred site I<SITE> I<SUBCOMMAND> [I<ARGUMENTS>]
18 I<SITE>, most often a website name, is a container of one or more properties.
19 But it can be anything you want to tie properties to,
20 typically passwords, keys, pin codes, API tokens as secrets and
21 username, email address, etc. as ordinary properties.
23 I<SITE> is represented in a directory in the credentials base dir.
24 You may also enter a directory path on the filesystem for I<SITE>.
25 You don't need to create a I<SITE>: it's created automatically when you write in it.
27 For websites and other services you have more than one account or identity for,
28 recommended to organize them into subdirectories like: I<SITE>/I<IDENTITY>,
29 eg: C<mail.example.net/joe@example.net> and C<mail.example.net/jane@example.net>.
37 Output a bash script to setup tab-completion for the C<cred> command.
38 Use it by eg: C<eval "$(cred compscript)">
42 =item dump [reveal-secrets | mask-secrets | hash-secrets]
44 Display all properties (and their values) of a given site.
45 Optional parameter is how secrets are displayed:
46 B<mask-secrets> is the default and replaces a secret string with 5 asterisks (C<*****>) uniformly (so number of chars are not leaked).
47 B<hash-secrets> replaces secrets by a hash and the checksum algorithm' name
48 is appended to the hash with a tab, like: <TAB>B<hash-algo=>I<NAME>.
49 Finally B<reveal-secrets> displays secret strings in clear text just like ordinary properties.
51 Those properies are considered to be secret at the moment which contain at least one of these words (case insensitive) :
52 B<pass>, B<key>, B<cvc>, B<secret>, B<pin>, B<code>, B<token>.
54 =item generate-password
56 Generate a new password and put in B<PASSWORD> property;
57 append its old value to the B<OLDPASSWORDS> property;
58 copy the new one to the clipboard.
62 =item prop I<PROPERTY> [set I<NEW-VALUE> | edit | read | del | show | reveal | clip]
64 Manage properties of a given site.
65 See individual instruction descriptions at the subcommands below which are aliases to these B<prop ...> commands.
67 =item set I<PROPERTY> I<NEW-VALUE>
69 =item edit I<PROPERTY>
71 Open up the B<$EDITOR> (falling back to B<$VISUAL>) to edit the given property's value.
72 =item read I<PROPERTY>
74 Read the new value from the STDIN (readline is supported if bash does support it, see C<help read> in bash(1)).
75 Secrets are read in no-echo mode.
79 =item show I<PROPERTY>
81 =item reveal I<PROPERTY>
83 Subcommand B<show> shows only non-secrets.
84 Enter B<reveal> to show secrets as well.
86 =item clip I<PROPERTY>
88 By B<clip> you may copy the value to the clipboard.
89 If you use CopyQ(1), secrets are prevented to get to CopyQ's clipboard items history.
91 =item fill-form I<PROPERTY> [I<PROPERTY> [...]]
93 Takes one or more property names and types their values to the window accessible by pressing Alt+Tab on your desktop.
94 Also presses <TAB> after each string, but does not press <RETURN>.
95 A single dot (C<.>) is a pseudo I<PROPERTY> name: if it's given, nothing will be typed in its place,
96 but <TAB> is still pressed after it.
97 Use it if the form has fields which you don't want to fill in.
98 Obviously it's useful only with a B<$DESKTOP>.
99 Depends on xdotool(1).
105 Credentials directory is hardcoded to F<~/cred>.
119 # need to set these shell options before they are relied upon when bash parses the big { ... } block later down.
121 shopt -s expand_aliases
122 # aliases in non-interactive bash script are not evaluated in the same scope where they are defined,
123 # but they are in the big { ... } block below.
124 alias set_site
='if [ -z "${site:-}" ]; then set_site_func "${1:-}"; shift; fi;'
131 .
/usr
/lib
/tool
/bash-utils
135 if [ -n "${NO_COLOR:-}" ]; then return 1; fi
136 if [ -n "${CLICOLOR_FORCE:-}" ]; then return 0; fi
139 if colors_supported
; then .
/usr
/lib
/tool
/ansi-codes
; fi
145 local i stack_size
=${#FUNCNAME[@]}
146 for (( i
=1; i
<stack_size
; i
++ )); do
147 local func
="${FUNCNAME[$i]}"
148 [[ $func = "" ]] && func
=MAIN
149 local linen
="${BASH_LINENO[$(( i - 1 ))]}"
150 local src
="${BASH_SOURCE[$i]}"
151 [[ "$src" = "" ]] && src
=non_file_source
153 echo -n "${ANSI_bold:-}${ANSI_fg_black:-}"
154 echo " function: $func"
155 echo " file: $src (line $linen)"
156 echo -n "${ANSI_reset:-}"
158 local line_number_text_sep
='| '
159 nl -ba -w ${#linen} -s " $line_number_text_sep" "$src" |
grep -C 2 -E "^\s*$linen " |\
161 sed -e "s/^\(\s*$linen\) \(.\{${#line_number_text_sep}\}\)\(.*\)/\1-\2${ANSI_italic:-}\3${ANSI_normal:-}/" |\
162 sd
'^' "${ANSI_bold:-}${ANSI_fg_black:-}" | sd '$' "${ANSI_reset:-}"
166 trap 'print_traceback >&2' ERR
173 errx
1 "Enter site name or directory!"
176 site
=`basename "$param"`
184 [[ $1 =~ pass|key|cvc|secret|pin|code|token
]]
190 if type copyq
1>/dev
/null
2>&1 && is_secret
"$prop"
192 copyq_monitoring
=`copyq monitoring`
193 if [ "$copyq_monitoring" = true
]
198 if [ "$copyq_monitoring" = true
]
203 xclip
-i -selection clipboard
209 local prop
=${1:?'enter property name!'}
211 local instruct
=${1:?enter an instruction: set, edit, read, del, show, reveal, clip}
215 [ $# -gt 0 ] # 'prop ... set' needs at least 1 argument
217 mkdir
-p "$basedir/$site"
218 printf '%s' "$val" > "$basedir/$site/$prop"
221 mkdir
-p "$basedir/$site"
222 "${EDITOR:-$VISUAL}" "$basedir/$site/$prop"
227 read -s -p "$site/$prop: " -e val
229 read -p "$site/$prop: " -e val
231 mkdir
-p "$basedir/$site"
232 printf '%s' "$val" > "$basedir/$site/$prop"
235 rm "$basedir/$site/$prop"
240 false
# this property is deemed to be a secret
242 cat "$basedir/$site/$prop"
246 cat "$basedir/$site/$prop"
249 cat "$basedir/$site/$prop" | do_clip
"$prop"
252 false
# invalid instruction given
262 if [ "${1:-}" = site
]
280 GLOBIGNORE
=${GLOBIGNORE:-}${GLOBIGNORE:+:}".:..:.[!/.]*:..[!/]*:-*"
289 if in_list reveal-secrets
"${options[@]}"
292 elif in_list hash-secrets
"${options[@]}"
294 hash=`cat "$file" | md5sum | cut -c 1-32`
295 echo "$file$TAB$hash$TAB""hash-algo=md5"
298 echo "$file"$
'\t'"*****"
303 grep .
"$file" | prefixlines
"$file"$
'\t' || true
310 cred dump
"$parent" "${options[@]}"
315 find -L "$basedir" -path "$basedir/${1:-}*" -type d
-printf "%P\n"
321 (set|edit|
read|del|show|reveal|clip
)
325 prop
"$prop" "$subcmd" "$@"
338 val
=`cat "$basedir/$site/$prop"`
340 strings="$strings$val"$
'\t'
342 xdotool key Alt
+Tab
type "$strings"
344 errx
1 "Enter property names in order to fill the form on the window brought to focus by Alt+Tab."
349 if [ -e "$basedir/$site" ]
351 find "$basedir/$site" -type f
-printf "%P\n"
356 newpwd
=$
(pwgen
-y 8 1)$
(pwgen
-y 8 1)
358 pwdfile
=$basedir/$site/PASSWORD
359 mkdir
-p "$basedir/$site"
362 cur_pwd
=`cat "$pwdfile"`
363 atime
=`stat -c %x "$pwdfile"`
364 now
=`date +'%F %T.%N %z'`
365 echo "$atime $now $cur_pwd" >> "$basedir/$site/OLDPASSWORDS"
367 printf '%s' "$newpwd" > "$pwdfile"
368 printf '%s' "$newpwd" | do_clip PASSWORD
372 _autocomplete_cred() {
374 local curr_word=${COMP_WORDS[$COMP_CWORD]}
375 local prev_word=${COMP_WORDS[$[COMP_CWORD - 1]]}
376 # NOTE if change $prop_subcmds, align it with the switch case below!
377 local prop_subcmds="set edit read del show reveal clip"
378 local site_subcmds="list-sites dump generate-password list-props prop $prop_subcmds fill-form"
382 compreply="compscript site $site_subcmds"
385 local site=$curr_word; site=${site/#'~/'/$HOME/}
386 compreply=`cred list-sites "$site"`
389 local subcmd=${COMP_WORDS[1]}
390 local site=${COMP_WORDS[2]}; site=${site/#'~/'/$HOME/}
391 local cword_idx=$COMP_CWORD
392 if [ "$subcmd" = site ]
394 if [ $COMP_CWORD = 3 ]
396 compreply="$site_subcmds"
398 subcmd=${COMP_WORDS[3]}
406 compreply=`cred list-props "$site"`
409 compreply=$prop_subcmds
413 # NOTE: align with $prop_subcmds!
414 (fill-form|set|edit|read|del|show|reveal|clip)
415 compreply=`cred list-props "$site"`
416 if [ "$subcmd" = set ]
418 common_properties="EMAIL USERNAME PASSWORD PIN KEY TOKEN"
419 compreply="$compreply $common_properties"
425 compreply="reveal-secrets mask-secrets hash-secrets"
431 COMPREPLY=($(compgen -W "$compreply" -- "${COMP_WORDS[$COMP_CWORD]}"))
434 complete -F _autocomplete_cred cred
435 # use this in your bash session by eg: eval "$(cred compscript)"
439 warnx
'Use tab-completion!'
440 warnx
'Example: eval "$(cred compscript)"'