pwd bug fix
This commit is contained in:
@@ -105,7 +105,7 @@ A bar-style prompt showing current time, execution time of the last command
|
|||||||
| `finddead` | filefct | Find dead symbolic links in the given or current directory |
|
| `finddead` | filefct | Find dead symbolic links in the given or current directory |
|
||||||
| `findzero` | filefct | Find empty files in the given or current directory; `--delete` does not follow symlinks |
|
| `findzero` | filefct | Find empty files in the given or current directory; `--delete` does not follow symlinks |
|
||||||
| `gacp` | git | Add, commit and push changes; auto-pulls with rebase first if needed |
|
| `gacp` | git | Add, commit and push changes; auto-pulls with rebase first if needed |
|
||||||
| `genpwd` | pwd | Generate one or more random secure passwords with configurable constraints |
|
| `genpwd` | pwd | Generate one or more random passwords with configurable constraints, from the kernel's random generator (`$SRANDOM`, or `/dev/urandom`); only the passwords go to stdout |
|
||||||
| `ggraph` | git | Display a decorated git history graph |
|
| `ggraph` | git | Display a decorated git history graph |
|
||||||
| `gpid` | processes | Give the list of PIDs matching the given process name(s) |
|
| `gpid` | processes | Give the list of PIDs matching the given process name(s) |
|
||||||
| `gprune` | git | Delete local branches already merged into the main branch; `-D`/`--deep` also deletes (force) branches whose upstream branch was deleted on the remote, e.g. after a merge request |
|
| `gprune` | git | Delete local branches already merged into the main branch; `-D`/`--deep` also deletes (force) branches whose upstream branch was deleted on the remote, e.g. after a merge request |
|
||||||
@@ -268,7 +268,7 @@ change the default without having to pass flags every time.
|
|||||||
| Key | Default | Description |
|
| Key | Default | Description |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `GENPWD_DEFAULT_LENGTH` | `16` | Generated password length |
|
| `GENPWD_DEFAULT_LENGTH` | `16` | Generated password length |
|
||||||
| `GENPWD_DEFAULT_OCCURS` | `1` | Number of character class occurrences |
|
| `GENPWD_DEFAULT_OCCURS` | `2` | Maximum number of occurrences of the same character in a password |
|
||||||
| `GENPWD_DEFAULT_COUNT` | `1` | Number of passwords to generate |
|
| `GENPWD_DEFAULT_COUNT` | `1` | Number of passwords to generate |
|
||||||
| `GENPWD_DEFAULT_SYMBOLS` | `1` | Include symbols (0/1) |
|
| `GENPWD_DEFAULT_SYMBOLS` | `1` | Include symbols (0/1) |
|
||||||
| `GENPWD_DEFAULT_UPPERCASE` | `1` | Include uppercase letters (0/1) |
|
| `GENPWD_DEFAULT_UPPERCASE` | `1` | Include uppercase letters (0/1) |
|
||||||
|
|||||||
@@ -133,6 +133,13 @@ Versions follow `MAJOR.MINOR.PATCH-REVISION_STAGE_N` (e.g. `3.99.1-4_rc_1`).
|
|||||||
theme's colours; the prompt no longer forks `date` twice per command
|
theme's colours; the prompt no longer forks `date` twice per command
|
||||||
(`$EPOCHREALTIME`) and runs one `git status` instead of three git commands,
|
(`$EPOCHREALTIME`) and runs one `git status` instead of three git commands,
|
||||||
without taking the index lock.
|
without taking the index lock.
|
||||||
|
- `pwd.sh` (security): `genpwd` drew its characters from `$RANDOM` (15 bits,
|
||||||
|
predictable seed); it now uses `$SRANDOM` or `/dev/urandom` with unbiased
|
||||||
|
selection and shuffle. Its info message goes to stderr, so `pw=$(genpwd)`
|
||||||
|
captures only the password; the `GENPWD_DEFAULT_*` values are validated
|
||||||
|
(they were evaluated as arithmetic expressions); `pwdscore` classifies
|
||||||
|
characters with locale-proof classes; README default of
|
||||||
|
`GENPWD_DEFAULT_OCCURS` corrected.
|
||||||
- `compress.sh`: option flags and loop variables no longer leak into the
|
- `compress.sh`: option flags and loop variables no longer leak into the
|
||||||
interactive shell.
|
interactive shell.
|
||||||
|
|
||||||
|
|||||||
+70
-12
@@ -36,6 +36,42 @@
|
|||||||
|
|
||||||
load_conf "pwd"
|
load_conf "pwd"
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Internal helper: put in _PWD_RAND an integer uniformly distributed in
|
||||||
|
# [0, $1), for 1 <= $1 <= 2^32. $RANDOM is NOT usable for passwords: it only
|
||||||
|
# has 15 bits, a state seeded from the time and the PID, and is predictable.
|
||||||
|
# The source is $SRANDOM (bash >= 5.1, from the kernel's random generator), or
|
||||||
|
# else /dev/urandom read through od, 256 words at a time to limit the number
|
||||||
|
# of processes. Values above the largest multiple of $1 are rejected, so that
|
||||||
|
# "% $1" introduces no bias.
|
||||||
|
# Usage: _pwd_rand <max>
|
||||||
|
_pwd_rand()
|
||||||
|
{
|
||||||
|
local max="$1" limit r
|
||||||
|
limit=$(( 4294967296 - 4294967296 % max ))
|
||||||
|
while :; do
|
||||||
|
if [[ -n "${SRANDOM+x}" ]]; then
|
||||||
|
r="$SRANDOM"
|
||||||
|
else
|
||||||
|
if (( ${#_PWD_POOL[@]} == 0 )); then
|
||||||
|
# shellcheck disable=SC2207 # whitespace-separated numbers
|
||||||
|
_PWD_POOL=( $(od -An -v -N1024 -tu4 /dev/urandom 2>/dev/null) )
|
||||||
|
if (( ${#_PWD_POOL[@]} == 0 )); then
|
||||||
|
disp E "No source of random numbers available (/dev/urandom)."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
r="${_PWD_POOL[-1]}"
|
||||||
|
unset '_PWD_POOL[-1]'
|
||||||
|
fi
|
||||||
|
if (( r < limit )); then
|
||||||
|
_PWD_RAND=$(( r % max ))
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
_PWD_POOL=()
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# genpwd : generate a password with different criteria
|
# genpwd : generate a password with different criteria
|
||||||
# Usage: genpwd [options] [--extracars=<cars>] [--length=<n>] [nb_passwd]
|
# Usage: genpwd [options] [--extracars=<cars>] [--length=<n>] [nb_passwd]
|
||||||
@@ -68,10 +104,12 @@ genpwd()
|
|||||||
help,nosymbols,nonumbers,noup,nolow,extracars:,length:,occurences:,occurrences: \
|
help,nosymbols,nonumbers,noup,nolow,extracars:,length:,occurences:,occurrences: \
|
||||||
-n 'genpwd' -- "$@")
|
-n 'genpwd' -- "$@")
|
||||||
# shellcheck disable=SC2181 # getopt return code is checked immediately after
|
# shellcheck disable=SC2181 # getopt return code is checked immediately after
|
||||||
if [[ $? -ne 0 ]]; then return 1; fi
|
if [[ $? -ne 0 ]]; then
|
||||||
local -a _pargs=()
|
disp E "Invalid options, use \"genpwd --help\" to display usage."
|
||||||
readarray -td '' _pargs < <(printf '%s' "$PARSED" | xargs printf '%s\0')
|
return 1
|
||||||
set -- "${_pargs[@]}"
|
fi
|
||||||
|
# Restore the getopt-normalised (shell-quoted) argument list
|
||||||
|
eval set -- "$PARSED"
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@@ -150,6 +188,21 @@ genpwd()
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
local carset=""
|
local carset=""
|
||||||
|
# The defaults may come from the configuration file: bash evaluates a
|
||||||
|
# non-numeric string inside (( )) as an expression, so check them first.
|
||||||
|
local _v
|
||||||
|
for _v in "$symb" "$numb" "$maj" "$min"; do
|
||||||
|
if [[ $_v != 0 && $_v != 1 ]]; then
|
||||||
|
disp E "Invalid GENPWD_DEFAULT_* value '$_v': the character class switches must be 0 or 1."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
for _v in "$length" "$occurs" "$nbpwd"; do
|
||||||
|
if ! [[ $_v =~ ^[1-9][0-9]*$ ]]; then
|
||||||
|
disp E "Invalid GENPWD_DEFAULT_* value '$_v': length, occurrences and count must be positive integers."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
local unique_carset=""
|
local unique_carset=""
|
||||||
local ch=""
|
local ch=""
|
||||||
local i=0
|
local i=0
|
||||||
@@ -210,7 +263,9 @@ genpwd()
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
disp I "Generating $nbpwd password(s), please wait..."
|
# On stderr: stdout carries the passwords only, so that "pw=$(genpwd)" or
|
||||||
|
# "genpwd | xclip" do not capture this message.
|
||||||
|
disp I "Generating $nbpwd password(s), please wait..." >&2
|
||||||
for (( n=1; n<=nbpwd; n++ )); do
|
for (( n=1; n<=nbpwd; n++ )); do
|
||||||
local -a password_chars=()
|
local -a password_chars=()
|
||||||
local -A char_count=()
|
local -A char_count=()
|
||||||
@@ -224,7 +279,8 @@ genpwd()
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
idx=$(( RANDOM % ${#set} ))
|
_pwd_rand "${#set}" || return 1
|
||||||
|
idx=$_PWD_RAND
|
||||||
char=${set:idx:1}
|
char=${set:idx:1}
|
||||||
count=${char_count["$char"]:-0}
|
count=${char_count["$char"]:-0}
|
||||||
|
|
||||||
@@ -246,7 +302,8 @@ genpwd()
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
idx=$(( RANDOM % ${#carset} ))
|
_pwd_rand "${#carset}" || return 1
|
||||||
|
idx=$_PWD_RAND
|
||||||
char=${carset:idx:1}
|
char=${carset:idx:1}
|
||||||
count=${char_count["$char"]:-0}
|
count=${char_count["$char"]:-0}
|
||||||
|
|
||||||
@@ -261,7 +318,8 @@ genpwd()
|
|||||||
done
|
done
|
||||||
|
|
||||||
for (( i=${#password_chars[@]} - 1; i>0; i-- )); do
|
for (( i=${#password_chars[@]} - 1; i>0; i-- )); do
|
||||||
idx=$(( RANDOM % (i + 1) ))
|
_pwd_rand "$(( i + 1 ))" || return 1
|
||||||
|
idx=$_PWD_RAND
|
||||||
char=${password_chars[i]}
|
char=${password_chars[i]}
|
||||||
password_chars[i]=${password_chars[idx]}
|
password_chars[i]=${password_chars[idx]}
|
||||||
password_chars[idx]=$char
|
password_chars[idx]=$char
|
||||||
@@ -312,7 +370,7 @@ pwdscore()
|
|||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
-*)
|
-*)
|
||||||
disp E "Invalid option '$1'. Use \"pwdscore --help\" to display usage."
|
disp E "Invalid option '$1'. Use \"pwdscore --help\" to display usage (a password starting with '-' must follow '--')."
|
||||||
return 1
|
return 1
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -373,17 +431,17 @@ pwdscore()
|
|||||||
score=$(( length * 2 ))
|
score=$(( length * 2 ))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $password =~ [a-z] ]]; then
|
if [[ $password =~ [[:lower:]] ]]; then
|
||||||
has_lower=1
|
has_lower=1
|
||||||
pool_size=$(( pool_size + 26 ))
|
pool_size=$(( pool_size + 26 ))
|
||||||
score=$(( score + 12 ))
|
score=$(( score + 12 ))
|
||||||
fi
|
fi
|
||||||
if [[ $password =~ [A-Z] ]]; then
|
if [[ $password =~ [[:upper:]] ]]; then
|
||||||
has_upper=1
|
has_upper=1
|
||||||
pool_size=$(( pool_size + 26 ))
|
pool_size=$(( pool_size + 26 ))
|
||||||
score=$(( score + 12 ))
|
score=$(( score + 12 ))
|
||||||
fi
|
fi
|
||||||
if [[ $password =~ [0-9] ]]; then
|
if [[ $password =~ [[:digit:]] ]]; then
|
||||||
has_digit=1
|
has_digit=1
|
||||||
pool_size=$(( pool_size + 10 ))
|
pool_size=$(( pool_size + 10 ))
|
||||||
score=$(( score + 12 ))
|
score=$(( score + 12 ))
|
||||||
|
|||||||
Reference in New Issue
Block a user