diff --git a/scripts/setup/machine-setup/lib/base.sh b/scripts/setup/machine-setup/lib/base.sh index eaaab9c5..7812575c 100644 --- a/scripts/setup/machine-setup/lib/base.sh +++ b/scripts/setup/machine-setup/lib/base.sh @@ -145,18 +145,26 @@ prompt_value() { # # ASSUME_YES=1 answers all of them, for an unattended run. confirm() { - local message="${1:-Proceed?}" answer - [[ "${ASSUME_YES:-}" == "1" ]] && return 0 + local message="${1:-Proceed?}" + # Second argument flips the default. Most questions here are "do the thing you + # already asked for" and Enter should mean yes; a few are genuine extras, where + # defaulting to yes would have people agreeing to them by reflex. + local default="${2:-y}" answer prompt + + [[ "${ASSUME_YES:-}" == "1" ]] && { [[ "$default" == "y" ]] && return 0 || return 1; } + + if [[ "$default" == "y" ]]; then prompt="[Y/n]"; else prompt="[y/N]"; fi while true; do # EOF is not a yes. Without this an unattended run without ASSUME_YES would # spin here forever. - if ! read -rp " ${message} [Y/n]: " answer; then + if ! read -rp " ${message} ${prompt}: " answer; then echo "" fail "No answer. Set ASSUME_YES=1 to run without prompts." fi + [[ -z "$answer" ]] && answer="$default" case "$answer" in - "" | y | Y | yes | Yes) return 0 ;; + y | Y | yes | Yes) return 0 ;; n | N | no | No) return 1 ;; *) warn "Answer y or n." ;; esac diff --git a/scripts/setup/machine-setup/lib/packages.sh b/scripts/setup/machine-setup/lib/packages.sh index 4828a6f3..8ff1bf82 100644 --- a/scripts/setup/machine-setup/lib/packages.sh +++ b/scripts/setup/machine-setup/lib/packages.sh @@ -45,11 +45,11 @@ LAST_SKIPPED=() # that make a machine worth sitting at. # # The first six are load-bearing and each is used by a later step — curl fetches -# in nine of them, jq parses the lazygit release API, unzip opens ssh-keys.zip, -# gnupg dearmors the Docker keyring, git clones the Neovim config, and -# ca-certificates is what makes any of the fetching work. The rest are the -# environment: nothing calls them, they are here because a box you use should -# have them. +# in nine of them, jq parses the lazygit release API, gnupg dearmors the Docker +# keyring, git clones the Neovim config, unzip opens anything that arrives as an +# archive, and ca-certificates is what makes any of the fetching work. The rest +# are the environment: nothing calls them, they are here because a box you use +# should have them. # # build-essential is the one entry with any reach beyond itself: it is a # meta-package (gcc, g++, make, libc6-dev, dpkg-dev), so on a machine where a diff --git a/scripts/setup/machine-setup/machine-setup.sh b/scripts/setup/machine-setup/machine-setup.sh index b43a29ca..d48fc35c 100755 --- a/scripts/setup/machine-setup/machine-setup.sh +++ b/scripts/setup/machine-setup/machine-setup.sh @@ -849,10 +849,26 @@ if ! skip; then echo " root login: $(sshd_effective permitrootlogin)" # ── a key first ── + # + # The same menu whether or not there is already one, because "add another" is a + # real need — a second laptop, a rebuilt machine — and the original had no way + # to do it at all. What changes is whether the question can be declined: with no + # key, declining means the hardening below will refuse too, and the run says so. + ADD_KEY=false if ((KEY_COUNT == 0)); then echo "" warn "${USERNAME} has no authorised key. Password login cannot be turned off until it has one." - echo " [1] paste a public key (the contents of your ~/.ssh/id_ed25519.pub)" + ADD_KEY=true + else + fix_ssh_permissions + echo "" + ADD_KEY=false + confirm "Add another authorised key for ${USERNAME}?" n && ADD_KEY=true + fi + + if $ADD_KEY; then + echo "" + echo " [1] paste a public key (one line, from your own ~/.ssh/id_ed25519.pub)" echo " [2] generate a new keypair on this machine" echo " [3] leave it for now" echo "" @@ -866,6 +882,11 @@ if ! skip; then case "${SSH_KEY_CHOICE:-1}" in 1) read -rp " Paste the public key: " SSH_PASTED || fail "No answer." + # Trimmed: pasting from a terminal or a password manager routinely + # brings leading or trailing whitespace, and ssh-keygen will not parse + # a key with it attached. + SSH_PASTED="${SSH_PASTED#"${SSH_PASTED%%[![:space:]]*}"}" + SSH_PASTED="${SSH_PASTED%"${SSH_PASTED##*[![:space:]]}"}" add_authorized_key "$SSH_PASTED" && SSH_KEY_DONE=true ;; 2) @@ -883,8 +904,6 @@ if ! skip; then esac done KEY_COUNT="$(authorized_key_count)" - else - fix_ssh_permissions fi # ── then hardening, and only then ──