diff --git a/ugenpass b/ugenpass new file mode 100755 index 0000000..0e647c5 --- /dev/null +++ b/ugenpass @@ -0,0 +1,134 @@ +#!/bin/bash +# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 +source "$(dirname "$0")/ulib/ulib" || exit 1; urequire DEFAULTS + +function display_help() { + uecho "$scriptname: générer un mot de passe au hasard + +USAGE + $scriptname [options] + +OPTIONS + -l, --len LEN + Spécifier le nombre de caractères du mot de passe généré + -U, --upper COUNT + -L, --lower COUNT + -A, --alpha COUNT + -N, --number COUNT + -S, --symbol COUNT + -B, --special COUNT + Spécifier le nombre minimum de chaque classe de caractère" +} + +UPPER="AZERTYUIOPQSDFGHJKLMWXCVBN" +LOWER="azertyuiopqsdfghjklmwxcvbn" +NUMBERS="1234567890" +SYMBOLS="&\"'(-_)=^\$*!:;,?./%+#{[|\\]}" +LEN=10 +SECTIONS=("$UPPER" "$LOWER" "$UPPER$LOWER" "$NUMBERS" "$SYMBOLS" "$NUMBERS$SYMBOLS") +COUNTS=(0 0 4 0 0 1) + +function random_index() { + [ -n "$1" ] || return + local -a __rn_array; array_copy __rn_array "$1" + [ ${#__rn_array[*]} -gt 0 ] || return + echo $(($RANDOM % ${#__rn_array[*]})) +} + +function random_value() { + local __rv_index="$(random_index "$1")" + [ -n "$__rv_index" ] || return + eval "echo \${$1[$__rv_index]}" +} + +function random_char() { + local section="$1" + [ ${#section} -gt 0 ] || return + local index=$(($RANDOM % ${#section})) + echo "${section:$index:1}" +} + +len= +upper= +lower= +alpha= +number= +symbol= +special= +parse_opts "${PRETTYOPTS[@]}" \ + --help '$exit_with display_help' \ + -l:,--len: len= \ + -U:,--upper: upper= \ + -L:,--lower: lower= \ + -A:,--alpha: alpha= \ + -N:,--number: number= \ + -S:,--symbol: symbol= \ + -B:,--special: special= \ + @ args -- "$@" && set -- "${args[@]}" || die "$args" + +[ -n "$len" ] || len="$LEN" +[ -n "$upper" ] || upper="${COUNTS[0]}" +[ -n "$lower" ] || lower="${COUNTS[1]}" +[ -n "$alpha" ] || alpha="${COUNTS[2]}" +[ -n "$number" ] || number="${COUNTS[3]}" +[ -n "$symbol" ] || symbol="${COUNTS[4]}" +[ -n "$special" ] || special="${COUNTS[5]}" + +# counts contient le nombre minimum de caractères de chaque section. ce tableau +# doit être de la même taille que le tableau SECTIONS +counts=("$upper" "$lower" "$alpha" "$number" "$symbol" "$special") +[ "${#SECTIONS[*]}" -eq "${#counts[*]}" ] || die "SECTIONS et counts doivent être de même taille" + +# indexes contient les indexes dans le tableau SECTIONS, avec comme poids le +# nombre de caractères minimum de chaque sections +indexes=() +index=0 +for count in "${counts[@]}"; do + while [ $count -ge 0 ]; do + array_add indexes "$index" + count=$(($count - 1)) + done + index=$(($index + 1)) +done + +# générer chaque caractère du mot de passe au hasard +parts=() +while true; do + # vérifier s'il reste encore des sections avec un nombre minimum + hasmincount= + for mincount in "${counts[@]}"; do + [ "$mincount" -gt 0 ] && { + hasmincount=1 + break + } + done + [ -n "$hasmincount" ] || break + # calculer la prochaine section à générer + while true; do + index=$(random_index SECTIONS) + [ ${counts[$index]} -gt 0 ] && break + done + # générer un caractère au hasard + part="$(random_char "${SECTIONS[$index]}")" + array_add parts "$part" + counts[$index]=$((${counts[$index]} - 1)) +done +# générer le reste du mot de passe +while [ "${#parts[*]}" -lt "$len" ]; do + index=$(random_value indexes) + part="$(random_char "${SECTIONS[$index]}")" + array_add parts "$part" +done + +# puis générer le mot de passe en prenant chaquer partie au hasard +password= +while [ ${#parts[*]} -gt 0 ]; do + index=$(random_index parts) + password="$password${parts[$index]}" + before=() + [ $index -gt 0 ] && before=("${parts[@]:0:$index}") + after=("${parts[@]:$((index + 1))}") + parts=("${before[@]}" "${after[@]}") +done + +echo "$password"