From 0c5b9b27b77da5c44b1b0404d9fcaf92a77c35a0 Mon Sep 17 00:00:00 2001 From: lark Date: Wed, 10 Jun 2026 01:12:51 -0700 Subject: [PATCH] charsets --- .DS_Store | Bin 6148 -> 6148 bytes README.md | 7 ++++++- config.sh | 3 ++- himi | 59 +++++++++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/.DS_Store b/.DS_Store index 814b35fd98e8efa1e32a2acdba6b6ce72536ea5d..b3d90f3500e7375f554554231944099b873f85a5 100644 GIT binary patch delta 16 XcmZoMXffE}%QRVuNqKVt(-ctvE(iq> delta 18 ZcmZoMXffE}%f!eyxq(S(a{<#7Q2;g91#bWV diff --git a/README.md b/README.md index 74b5a0b..aaeceb1 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,11 @@ TEMPLATES=( | `{num:N}` | N digits | ~3.3 bits/char | | `{special:N}` | N from `!?@#%~=+` | ~3.0 bits/char | | `{NAME:N-M}` | N to M chars from charset NAME | log2(Σ size^L) | +| `{hex:N}` | `3f9a` | 4.0 bits/char | +| `{b58:N}` | `Vk2x` (Base58, no 0OIl) | ~5.9 bits/char | +| `{b64:N}` | `hG_4` (URL-safe base64) | 6.0 bits/char | +| `{alnum:N}` | `xR4x` | ~6.0 bits/char | +| `{ascii:N}` | `p/(!` (all printable, no space) | ~6.5 bits/char | \* Word entropy depends on pool size. Values shown assume all built-in lists enabled (~14k words, ~13.8 bits/word). @@ -109,7 +114,7 @@ CHARSETS=( ) ``` -Names must match `[a-z][a-z0-9_]*` and override the built-in four (alpha, safe, num, special). Avoid duplicate characters; himi warns if it sees them, since they skew the distribution and overstate entropy. +Names must match `[a-z][a-z0-9_]*` and override any built-in of the same name (alpha, safe, num, special, hex, b58, b64, alnum, ascii). Avoid duplicate characters; himi warns if it sees them, since they skew the distribution and overstate entropy. Range tokens pick the length weighted by `size^L`, so every possible output is equally likely. `{num:1-2}` covers 0-99 plus 0-9 (110 outcomes, ~6.8 bits), not a 50/50 coin flip on length, which would tank min-entropy. diff --git a/config.sh b/config.sh index f00247d..5c756d2 100644 --- a/config.sh +++ b/config.sh @@ -42,7 +42,8 @@ WORD_MAX_LENGTH=9 # {Word} — random word (Title Case) # {word!} — random lower or UPPER (+1 bit entropy) # {Word!} — random lower/Title/UPPER (+1.58 bits entropy) -# {NAME:N} — N chars from charset NAME (alpha/safe/num/special/custom) +# {NAME:N} — N chars from charset NAME +# built-in: alpha safe num special hex b58 b64 alnum ascii # {NAME:N-M} — N to M chars, weighted so every output is equally likely # (entropy = log2 of total outcomes, e.g. {num:1-2} ≈ 6.8 bits) # ------------------------------------------------------------------------------ diff --git a/himi b/himi index 0de2918..055765d 100644 --- a/himi +++ b/himi @@ -28,6 +28,9 @@ readonly CONFIG_SCHEMA_VERSION=2 # Generic charset token: {name:N} or {name:N-M} readonly TOKEN_RE='\{([a-z][a-z0-9_]*):([0-9]+)(-([0-9]+))?\}' +# Anything that still looks like a token after expansion (typo'd or unknown). +# Shape-based so charsets containing { } (e.g. ascii) don't false-positive. +readonly LEFTOVER_RE='\{[A-Za-z][A-Za-z0-9_]*(!|:[0-9]+(-[0-9]+)?)?\}' # ------------------------------------------------------------------------------ @@ -37,6 +40,11 @@ ALPHA_CHARSET='0123456789ABCDEFGHJKMNPQRSTVWXYZ' # Crockford Base32 (32 chars, SAFE_CHARSET='ACDEFGHJKMNPQRTWXY234679' # Ultra-safe (24 chars, 4.6 bits) - no B/8, 0/O, 1/I/L, 5/S NUM_CHARSET='0123456789' SPECIAL_CHARSET='!?@#%~=+' +HEX_CHARSET='0123456789abcdef' # 16 chars, 4.0 bits +B58_CHARSET='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' # Base58: no 0OIl (58 chars, 5.86 bits) +B64_CHARSET='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_' # URL-safe base64 (64 chars, 6.0 bits) +ALNUM_CHARSET='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' # 62 chars, 5.95 bits +ASCII_CHARSET='!"#$%&'\''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~' # all printable, no space (94 chars, 6.55 bits) WORD_MIN_LENGTH=4 WORD_MAX_LENGTH=8 @@ -200,6 +208,11 @@ get_charset() { safe) printf '%s' "$SAFE_CHARSET" ;; num) printf '%s' "$NUM_CHARSET" ;; special) printf '%s' "$SPECIAL_CHARSET" ;; + hex) printf '%s' "$HEX_CHARSET" ;; + b58) printf '%s' "$B58_CHARSET" ;; + b64) printf '%s' "$B64_CHARSET" ;; + alnum) printf '%s' "$ALNUM_CHARSET" ;; + ascii) printf '%s' "$ASCII_CHARSET" ;; *) return 1 ;; esac } @@ -521,6 +534,9 @@ cmd_list() { # Uninstall: remove himi and all data # ------------------------------------------------------------------------------ cmd_uninstall() { + local purge="false" + [[ "${1:-}" == "--purge" ]] && purge="true" + read -p "Are you sure you want to remove himi and all custom wordlists? (y/N) " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then @@ -543,23 +559,43 @@ cmd_uninstall() { # Linux/GNU sed -i.bak "/$start_marker/,/$end_marker/d" "$HOME/$p" fi - ok "Cleaned up $p (backup created as $p.bak)" + if [[ "$purge" == "true" ]]; then + rm -f "$HOME/$p.bak" + ok "Cleaned up $p (no backup, --purge)" + else + ok "Cleaned up $p (backup created as $p.bak)" + fi fi fi done - # 2. Remove completions + # 2. Remove completions (and the .zfunc dir if we leave it empty) rm -f "${HOME}/.zfunc/_himi" + rmdir "${HOME}/.zfunc" 2>/dev/null || true rm -f "${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion/completions/himi" # 3. Remove data and binary rm -rf "$CONFIG_DIR" ok "Removed configuration and wordlists." - # Final step: Binary deletes itself - local self - self=$(command -v himi) - rm -f "$self" + # Final step: binary deletes itself. Prefer the file actually running + # (works for ./himi too); fall back to PATH lookup without tripping set -e. + local self="${BASH_SOURCE[0]}" + if [[ ! -f "$self" ]]; then + self=$(command -v himi) || self="" + fi + [[ -n "$self" ]] && rm -f "$self" + + # Flag any other copies still lurking in PATH + local leftover + if leftover=$(command -v himi 2>/dev/null) && [[ -n "$leftover" ]]; then + warn "another himi remains at: $leftover — remove it manually" + fi + + if [[ "$purge" != "true" ]]; then + dim "Profile backups (*.bak) were kept; use 'himi uninstall --purge' for none." + printf "\n" + fi ok "himi has been uninstalled." } @@ -953,7 +989,7 @@ cmd_test() { local example leftovers="" for ((i = 0; i < 5; i++)); do example=$(expand_template "$pattern") - [[ "$example" == *'{'* && "$example" == *'}'* ]] && leftovers="true" + [[ "$example" =~ $LEFTOVER_RE ]] && leftovers="true" printf " %s\n" "$example" done printf "\n" @@ -1012,7 +1048,7 @@ cmd_generate() { secrets+=$(expand_template "$pattern") done - if [[ "$secrets" == *'{'* && "$secrets" == *'}'* ]]; then + if [[ "$secrets" =~ $LEFTOVER_RE ]]; then warn "output contains unexpanded {token}s — check the template ('himi test' helps)" fi @@ -1054,7 +1090,7 @@ Usage: himi entropy [name] Show entropy for template(s) himi test '{pattern}' Test a custom pattern himi config Edit config in \$EDITOR - himi uninstall Remove himi and all data + himi uninstall Remove himi and all data (--purge: no profile backups) himi -h, --help Show this help Templates (configure in $CONFIG_FILE): @@ -1082,6 +1118,11 @@ EOF printf " %-12s %s\n" "safe" "$SAFE_CHARSET" printf " %-12s %s\n" "num" "$NUM_CHARSET" printf " %-12s %s\n" "special" "$SPECIAL_CHARSET" + printf " %-12s %s\n" "hex" "$HEX_CHARSET" + printf " %-12s %s\n" "b58" "$B58_CHARSET" + printf " %-12s %s\n" "b64" "$B64_CHARSET" + printf " %-12s %s\n" "alnum" "$ALNUM_CHARSET" + printf " %-12s %s\n" "ascii" "$ASCII_CHARSET" for entry in ${CHARSETS[@]+"${CHARSETS[@]}"}; do IFS='|' read -r name pattern <<< "$entry" printf " %-12s %s\n" "$name" "$pattern"