diff options
| -rwxr-xr-x | archsetup | 100 | ||||
| -rw-r--r-- | todo.org | 8 |
2 files changed, 85 insertions, 23 deletions
@@ -122,8 +122,82 @@ load_config() { [[ -n "$DESKTOP_ENV" ]] && desktop_env="$DESKTOP_ENV" } -# Load config if specified -[[ -n "$config_file" ]] && load_config "$config_file" +# Validate a candidate primary-account username: lowercase, starts with a +# letter, only [a-z0-9_], and not a reserved system account. Pre-flight style +# (prints to stderr and exits) since the logging helpers aren't defined yet at +# the points this gets called. +validate_username() { + local name="$1" + if [[ -z "$name" ]]; then + echo "ERROR: Username cannot be empty" >&2 + exit 1 + fi + if [[ ! "$name" =~ ^[a-z][a-z0-9_]*$ ]]; then + echo "ERROR: Invalid username: '$name'" >&2 + echo " Must start with a lowercase letter and contain only lowercase letters, numbers, and underscores." >&2 + exit 1 + fi + local reserved_users="root bin daemon sys sync games man lp mail news uucp proxy www-data backup list irc gnats nobody systemd-network systemd-resolve messagebus polkitd sshd" + local reserved + for reserved in $reserved_users; do + if [[ "$name" == "$reserved" ]]; then + echo "ERROR: '$name' is a reserved system username" >&2 + exit 1 + fi + done +} + +# Validate values pulled from --config-file, before anything is installed, so a +# typo (DESKTOP_ENV=hyperland) fails immediately instead of partway through the +# install. NOT a security boundary: load_config sources the config as bash, so a +# hostile config can already run arbitrary code -- this just saves users from +# their own mistakes. +validate_config() { + [[ -n "$username" ]] && validate_username "$username" + + if [[ -n "$desktop_env" && "$desktop_env" != "dwm" && "$desktop_env" != "hyprland" && "$desktop_env" != "none" ]]; then + echo "ERROR: DESKTOP_ENV must be one of: dwm, hyprland, none. Got: '$desktop_env'" >&2 + exit 1 + fi + + if [[ -n "$AUTOLOGIN" && "$AUTOLOGIN" != "yes" && "$AUTOLOGIN" != "no" ]]; then + echo "ERROR: AUTOLOGIN must be 'yes' or 'no'. Got: '$AUTOLOGIN'" >&2 + exit 1 + fi + if [[ -n "$NO_GPU_DRIVERS" && "$NO_GPU_DRIVERS" != "yes" && "$NO_GPU_DRIVERS" != "no" ]]; then + echo "ERROR: NO_GPU_DRIVERS must be 'yes' or 'no'. Got: '$NO_GPU_DRIVERS'" >&2 + exit 1 + fi + + if [[ -n "$locale" && ! "$locale" =~ ^[a-z]{2,3}(_[A-Z]{2})?(\.[A-Za-z0-9-]+)?(@[A-Za-z]+)?$ ]]; then + echo "ERROR: LOCALE looks malformed: '$locale'. Expected e.g. en_US.UTF-8" >&2 + exit 1 + fi + + local repo + for repo in "$dwm_repo" "$dmenu_repo" "$st_repo" "$slock_repo" "$dotemacs_repo" "$archsetup_repo"; do + [[ -z "$repo" ]] && continue + case "$repo" in + http://*|https://*|git://*|ssh://*) ;; + *@*:*) ;; + *) + echo "ERROR: Repository URL looks unsupported: '$repo'" >&2 + echo " Expected http(s)://, git://, ssh://, or user@host:path." >&2 + exit 1 + ;; + esac + if [[ "$repo" =~ [[:space:]] || "$repo" == -* ]]; then + echo "ERROR: Repository URL contains whitespace or starts with '-': '$repo'" >&2 + exit 1 + fi + done +} + +# Load config if specified, then validate what it set +if [[ -n "$config_file" ]]; then + load_config "$config_file" + validate_config +fi ### Configuration Defaults # These can be overridden via --config-file @@ -315,30 +389,14 @@ preflight_checks() { echo " [OK] Locale: $locale (selected)" fi - # Prompt for username if not set + # Prompt for username if not set; validate either way if [[ -z "$username" ]]; then echo "" read -r -p "Enter username for primary account: " username - if [[ -z "$username" ]]; then - echo "ERROR: Username cannot be empty" - exit 1 - fi - # Validate username (lowercase, starts with letter, alphanumeric + underscore) - if [[ ! "$username" =~ ^[a-z][a-z0-9_]*$ ]]; then - echo "ERROR: Invalid username" - echo " Must start with lowercase letter, contain only lowercase letters, numbers, underscores" - exit 1 - fi - # Reject reserved system usernames - local reserved_users="root bin daemon sys sync games man lp mail news uucp proxy www-data backup list irc gnats nobody systemd-network systemd-resolve messagebus polkitd sshd" - for reserved in $reserved_users; do - if [[ "$username" == "$reserved" ]]; then - echo "ERROR: '$username' is a reserved system username" - exit 1 - fi - done + validate_username "$username" echo " [OK] Username: $username" else + validate_username "$username" echo " [OK] Username: $username (from config)" fi @@ -96,12 +96,16 @@ May have licensing issues for redistribution. Line 1781: =curl | sh= from claude.ai — should be behind a config flag. Not all users want AI tooling; curl-pipe-bash is a red flag for reviewers. -*** TODO [#B] Add input validation for username and paths +*** DOING [#B] Add input validation for username and paths Variables like ~$username~, ~$source_dir~, and paths are not validated. Special characters or malicious input could break the script or cause security issues. Should validate inputs match expected patterns (alphanumeric, valid paths, etc.). -cj: you can probably do this one on your own +**** 2026-05-11 Mon @ 18:20:49 -0500 AI Response: validate_config + validate_username added +Added two pre-flight validators to =archsetup= (right after =load_config=, before any install step): +- =validate_username()= — the lowercase / starts-with-letter / =[a-z0-9_]= / not-reserved check, extracted from the inline block in =preflight_checks()=. Fixes an existing gap: the inline check only ran on the *prompted* path, so a config with =USERNAME=root= (or =USERNAME=foo bar=) slipped through unvalidated. Now both =preflight_checks= and =validate_config= call it. +- =validate_config()= — runs whenever =--config-file= is used: rejects unknown =DESKTOP_ENV= (must be dwm/hyprland/none) early instead of dying in step 7-9; rejects =AUTOLOGIN=/=NO_GPU_DRIVERS= values that aren't =yes=/=no= (currently silently ignored); basic shape check on =LOCALE=; and a scheme + no-whitespace/no-leading-dash check on the six =*_REPO= URLs that get passed to =git clone= (rejects e.g. =--upload-pack=…= injection). Plain =echo …>&2; exit 1= (the logging helpers aren't defined that early). =$source_dir= needs no separate check — it's =/home/$username/.local/src=, derived from the now-always-validated =$username=. +Not a security boundary (=load_config= sources the config as bash; a hostile config can already run anything) — it's typo-catching. Verified with =bash -n= and a smoke-test matrix of good/bad inputs through both functions. The next =make test= run confirms valid configs still install. Leaving as DOING for review. *** TODO [#B] Move battery out of waybar sysmonitor group Battery module is inside =group/sysmonitor= which bundles cpu, temp, memory, disk, and battery together. Battery should be a standalone module in =modules-right= so it's visible on laptops without the full sysmonitor group. |
