Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand All @@ -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).
Expand Down
47 changes: 36 additions & 11 deletions docs/usage/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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.

Expand Down
32 changes: 24 additions & 8 deletions scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down