{{define "setup-page"}} Privatae bastion — set this machine up

Settings

Your code, connecting a Host, folders, the Host in charge and the owner name.

{{template "nav" "settings"}}
{{template "setup" .}}
{{end}} {{define "setup"}} {{if .Flash}}
{{.Flash}}
{{end}} {{if .ReadError}}
This machine's pairing records cannot be read: {{.ReadError}}. The panels below cannot be trusted until that is fixed.
{{end}} {{/* The state first, because every panel below reads differently depending on it — an anchor on a local box means nothing, and a folder needs a host. */}}
This computer
{{if .Networked}}A shared machine: several Hosts may be connected, and the Host in charge approves each new one. {{else}}Your own computer: one Host at most, chosen here.{{end}}
Host in charge
{{if .AnchorHost}}
{{.AnchorHost}}{{if .AnchorOwner}} (owner “{{.AnchorOwner}}”){{end}}
{{else if .AnchorRequired}}
none required Until one is chosen, this machine serves no Host.
{{else}}
not needed on your own computer
{{end}}
Owner name
{{if .Owner}}{{.Owner}}{{else}}not set{{end}}
Installed
{{if .Whole}}for the whole machine{{else}}in your own account agents running as you can stop it{{end}}
{{/* ── 1. pair ───────────────────────────────────────────────────────────── */}} {{/* ── 0. the owner's own code (stepup_machine.go) ─────────────────────── */}}

Your code

A six-digit code from an authenticator app on your phone. Stopping an agent, marking one as yours, and answering what is asked of this machine take it. An AI agent can click a button on this page if it can drive your browser; it cannot read your phone.

{{if and .Enrol .Enrol.Machine}}
QR code for your code on this machine

Point your authenticator app at the square. It will appear as Privatae bastion.

Nothing is written to this machine until that code matches.

{{else if .OwnerCode}}

set up Your code is set up on this machine.

{{if .Limited}}

To replace it, at a terminal: sudo -H privatae-bastion stepup-enroll --machine --rotate

{{else}}
{{end}} {{else if .Limited}}

Set it up once, at a terminal, as the machine's administrator, so no program running as you can set it up first: sudo -H privatae-bastion stepup-enroll --machine

{{else}}
{{end}}

Connected Hosts

{{range .Hosts}}
{{.Name}} {{.State}} {{if .IsAnchor}}in charge{{end}} {{if .Active}}{{if .Serving}}connected{{else}}not answering{{end}}{{end}} {{if .QuarantinedUntil}}quarantined until {{.QuarantinedUntil}}{{end}}

What it may do here

{{if $.Whole}} {{if .QuarantinedUntil}}
{{end}} {{if not .IsAnchor}}
{{end}} {{end}}
{{else}}

No Host is connected. That is fine: the bastion watches this machine on its own. To connect one, use a token from your Host below.

{{end}} {{if and .Hosts (not .Whole)}}

Disconnecting a Host or releasing one from quarantine needs the machine's administrator; this bastion runs in your own account.

{{end}}

Connect a Host

The token comes from your host's “Set up a bastion”. It is used once.

{{if .Limited}}

From your own account the console does not do this: it widens what reaches this machine and takes no code. The machine's administrator does it: sudo -H privatae-bastion ui

{{else}}
Pairing adds a host; it never replaces one. On an anchored machine a new host is written pending and starts nothing until the anchor host approves it. Nothing here needs the bastion restarted.
{{end}}
{{/* ── 2. second factor ──────────────────────────────────────────────────── */}} {{if .Hosts}}

A code for each Host

Once a factor is enrolled, your host can only reach a folder or move files here after you approve the request on this machine. Your host never sees the code.

{{if and .Enrol (not .Enrol.Machine)}}
{{/* The handle addresses the enrolment on the server. The secret is never in this page: it is in the pixels. */}} QR code for the second factor being enrolled on this machine

Point your authenticator app at the square. It will appear as Privatae NAC, for {{.Enrol.Host}}.

Nothing is written to this machine until that code matches.

{{else if and .Servable .Limited}}

From your own account the console does not do this: it widens what reaches this machine and takes no code. The machine's administrator does it: sudo -H privatae-bastion ui

{{else if .Servable}} {{/* .Servable, not .Hosts: a pending pairing gets no state on this machine at all, not even a directory (run.go:311), and a factor for it would gate ops it has no lanes to run. */}}
Replacing a factor stops the authenticator enrolled now from working.
{{else if .Hosts}}

No host here has its lanes open, and a second factor gates ops a pairing without lanes cannot run. Nothing is created for a pending host on this machine until the anchor host approves it.

{{end}}
{{end}} {{if .Hosts}} {{/* ── 3. folders ────────────────────────────────────────────────────────── */}}

Add a folder to your network

{{if and .Servable .Limited}}

From your own account the console does not do this: it widens what reaches this machine and takes no code. The machine's administrator does it: sudo -H privatae-bastion ui

{{else if .Servable}}

Your files stay on this machine. Your host keeps only the index, and the draft does nothing until you approve it there.

{{/* A browser cannot open a native folder picker without the user choosing a folder in it, and what it hands back is a file list, not a path this machine can name. So: a typed path, checked against the real filesystem as it is typed. */}}
{{if .Check}}{{template "folder-check" .}}{{end}}
{{if gt (len .Servable) 1}} {{else}} {{range .Servable}}

Proposed to {{.Name}}.

{{end}} {{end}}
{{else}}

No host on this machine has its lanes open, so there is nothing to propose a folder to yet.

{{end}}
{{end}} {{if or .Networked .AnchorHost .Hosts}} {{/* ── 4. the anchor ─────────────────────────────────────────────────────── */}}

Which Host is in charge (shared machines)

The anchor host is the one that approves every other host paired here. It is a choice among the hosts this machine already serves.

{{if and .Hosts .Limited}}

From your own account the console does not do this: it widens what reaches this machine and takes no code. The machine's administrator does it: sudo -H privatae-bastion ui

{{else if .Hosts}}
{{range .Hosts}} {{end}}
{{else}}

Pair a host first — the anchor is one of them.

{{end}}
{{if .Cmd}}{{template "anchor-cmd" .}}{{end}}
This page will not do it. Claiming the anchor needs machine authority — root on this box is what stands behind it — and it decides who approves every pairing made here from now on. A page you are signed into for twelve hours is not the right thing to hang that on, so the choice is here and the act stays at a terminal.
{{end}} {{/* ── 5. the owner name ─────────────────────────────────────────────────── */}}

Who owns this machine

A plain name, shown on this machine's card on every host it serves. It is optional and it grants nothing.

{{if and .Whole .OwnerCode}} {{else if not .Whole}} {{end}}
{{if and .Whole (not .OwnerCode)}}

Set up your code above, then set the name here.

{{end}}
{{if .Cmd}}{{template "owner-cmd" .}}{{end}}
Root-gated for the same reason as the anchor: there is no authority above this box to ask, so the ability to run root here is what the name stands on.
{{end}} {{/* ── fragments swapped on their own, so typing does not lose focus ─────── */}} {{define "folder-check"}} {{with .Check}}

{{.Line}} {{if .Resolved}}
{{.Resolved}}{{end}} {{if .Note}}
{{.Note}}{{end}}

{{end}} {{end}} {{define "stepup-key"}} {{if and .Enrol .Enrol.Key}}

Enter this key by hand, then type a code from the app:

{{.Enrol.Key}}

It is a secret. It is on screen because you asked for it, and it is gone from this page as soon as you reload.

{{else}}

That enrolment has expired — start it again.

{{end}} {{end}} {{define "anchor-cmd"}} {{with .Cmd}}
{{if .Command}}

{{.Command}}

{{end}} {{if .How}}

{{.How}}

{{end}} {{if .Why}}

{{.Why}}

{{end}}
{{end}} {{end}} {{define "owner-cmd"}} {{with .Cmd}}
{{if .Command}}

{{.Command}}

{{end}} {{if .How}}

{{.How}}

{{end}} {{if .Why}}

{{.Why}}

{{end}}
{{end}} {{end}}