diff --git a/CHANGELOG.md b/CHANGELOG.md index 6764147..497a6ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,17 @@ current as you land changes. ### Changed +- **The documented install is two lines, not a pipe.** `scripts/install.sh` has + always been interactive — components on a fresh machine, + upgrade/reinstall/uninstall on one that already has dezhban, and an offer to + run the setup wizard — but it can only ask when it is run from a file. Piped + into `bash`, stdin *is* the script text, so nobody following the README had + ever seen a prompt. The docs now lead with `curl … -o /tmp/dezhban-install.sh` + then `sudo bash /tmp/dezhban-install.sh`, which also lets you read the script + before running it as root. The piped one-liner is unchanged, still supported, + and still documented for unattended installs — its "never prompts" guarantee + is untouched. The script's "run as root" hint now names the actual file when + there is one instead of always suggesting the pipe. - **The setup wizard is two steps.** Blocked countries, then one "Use automatic VPN detection?" tickbox with the manual fields — tunnel interfaces, self-hosted config files, endpoints — revealed underneath it when you untick it. The diff --git a/README.md b/README.md index 9c33383..52683d7 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,21 @@ rough edges. ## Install (macOS) +```sh +curl -fsSL https://raw.githubusercontent.com/Behnam-RK/dezhban/main/scripts/install.sh -o /tmp/dezhban-install.sh +sudo bash /tmp/dezhban-install.sh +``` + +Two lines rather than one, on purpose. The installer asks a few +questions — which components to install, whether to register the service, +whether to run the setup wizard — and it can only ask when it is run from a +file. Piped straight into `bash`, stdin *is* the script text, so there is +nowhere to read an answer from and it silently takes the defaults. The +two-line form also lets you read the script before running it as root, which +is the right habit for a kill switch. For an unattended install (a +provisioner, CI, a second machine you have already decided about), the +one-liner still works and takes today's defaults with no prompt: + ```sh curl -fsSL https://raw.githubusercontent.com/Behnam-RK/dezhban/main/scripts/install.sh | sudo bash ``` @@ -58,7 +73,7 @@ Then open **Dezhban** from Applications (or Spotlight). That's the only terminal step, ever — not because the app can't be double-clicked, but because there's no Apple Developer certificate to sign it with yet, so Gatekeeper would otherwise block it. `curl` genuinely doesn't trip that check (it's documented -Apple behavior, not a workaround), so this line installs the app with **zero +Apple behavior, not a workaround), so either form installs the app with **zero Gatekeeper friction** and asks for your password exactly once. Details, the `.pkg` alternative, and Linux/Windows installers: [docs/usage/install.md](docs/usage/install.md). diff --git a/docs/usage/install.md b/docs/usage/install.md index 243ba3f..3f90888 100644 --- a/docs/usage/install.md +++ b/docs/usage/install.md @@ -5,7 +5,8 @@ **macOS or Linux:** ```sh -curl -fsSL https://raw.githubusercontent.com/Behnam-RK/dezhban/main/scripts/install.sh | sudo bash +curl -fsSL https://raw.githubusercontent.com/Behnam-RK/dezhban/main/scripts/install.sh -o /tmp/dezhban-install.sh +sudo bash /tmp/dezhban-install.sh ``` **Windows** (elevated PowerShell): @@ -15,22 +16,46 @@ irm https://raw.githubusercontent.com/Behnam-RK/dezhban/main/scripts/install.ps1 ``` Either installs the CLI, the menubar app on macOS, and registers the -background service — **without starting it**. Finish with: +background service — **without starting it**. + +### Why two lines instead of a pipe + +Because run from a file, the installer can **ask**, and piped it cannot. + +At a real terminal it walks you through it: which components to install on a +fresh machine (CLI, the menubar app, the service); on a machine that already +has dezhban, whether to upgrade, reinstall, or **uninstall** — the last with a +typed confirmation and a "keep your config?" question before anything is +removed; and finally whether to run `dezhban setup` there and then, so you +finish with a configured guard rather than a set of instructions. + +Piped into `bash`, none of that can happen: stdin *is* the script text, so +there is nowhere to read an answer from. It takes today's defaults silently — +which is exactly right for a provisioner or a CI job, and exactly wrong for +someone installing this for the first time. + +The two-line form also lets you read the script before running it as root. +That is the right habit for anything that installs a kill switch, and this +one is worth the thirty seconds. + +**Unattended** is still one line, and still supported: + +```sh +curl -fsSL https://raw.githubusercontent.com/Behnam-RK/dezhban/main/scripts/install.sh | sudo bash +``` + +`DEZHBAN_ASSUME_YES=1` forces that same no-prompt behaviour even at a real +terminal, for a script that wants the defaults deliberately. + +### Finishing by hand + +If you skipped the wizard (or used the unattended form): ```sh sudo dezhban setup # choose your settings sudo dezhban start # arm it ``` -Piped like that, `scripts/install.sh` never prompts — stdin is the script -text itself, so there's nowhere to read a question from, and it takes exactly -the defaults above. Save it to a file and run it directly at a real terminal -(`sudo bash install.sh`, not piped) and it asks a few questions instead: which -components to install on a fresh machine, and — on a machine that already has -dezhban — upgrade, reinstall, or **uninstall**, with a typed confirmation -before anything is removed. `DEZHBAN_ASSUME_YES=1` forces the non-interactive -defaults even at a real terminal. - Everything below is why this is the recommended path, what else exists, and how to verify what you downloaded. diff --git a/scripts/install.sh b/scripts/install.sh index 72874ae..db07d27 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -10,15 +10,24 @@ # same; that needs a $99/yr Apple Developer ID (see # packaging/macos/build-pkg.sh's dormant INSTALLER_SIGN_IDENTITY seam). # -# curl -fsSL https://raw.githubusercontent.com/Behnam-RK/dezhban/main/scripts/install.sh | sudo bash +# The DOCUMENTED path is two lines, and that is deliberate — see +# docs/usage/install.md. Run from a file, this script can ask; piped, it cannot, +# because stdin is then the script text itself and there is nowhere to read an +# answer from: +# +# curl -fsSL https://raw.githubusercontent.com/Behnam-RK/dezhban/main/scripts/install.sh -o /tmp/dezhban-install.sh +# sudo bash /tmp/dezhban-install.sh +# +# The piped form remains supported and unchanged, for provisioners and CI: +# +# curl -fsSL .../install.sh | sudo bash # curl -fsSL .../install.sh | sudo VERSION=0.2.0 bash # pin an exact version # -# On a real terminal (curl saved to a file, then run — NOT piped, since piping -# makes stdin the script text itself) this asks a few questions: which -# components to install on a fresh machine, and upgrade/reinstall/uninstall on -# a machine that already has dezhban. Piped or non-interactive, it takes -# today's exact defaults with no prompt at all — DEZHBAN_ASSUME_YES=1 forces -# that behavior even on a real terminal. +# On a real terminal this asks a few questions: which components to install on a +# fresh machine, upgrade/reinstall/uninstall on a machine that already has +# dezhban, and whether to run the setup wizard. Piped or non-interactive, it +# takes today's exact defaults with no prompt at all — DEZHBAN_ASSUME_YES=1 +# forces that behavior even on a real terminal. # # Must run as root: it installs to /usr/local and /etc, and registers a system # service. Written for bash 3.2 — that is what macOS ships at /bin/bash with no @@ -32,7 +41,14 @@ GH="https://github.com/$REPO" die() { echo "error: $*" >&2; exit 1; } note() { echo "==> $*"; } -[ "$(id -u)" -eq 0 ] || die "run as root — e.g. curl -fsSL .../install.sh | sudo bash" +# $0 is "bash" when this was piped, so name the actual file only when there is +# one. A hint that reads "sudo bash bash" is worse than no hint. +if [ "$(id -u)" -ne 0 ]; then + if [ -f "$0" ]; then + die "run as root — e.g. sudo bash $0" + fi + die "run as root — e.g. curl -fsSL .../install.sh | sudo bash" +fi # --- interactive discipline ----------------------------------------------- # stdin IS the script text itself when piped (`curl | sudo bash`), so any