aboutsummaryrefslogtreecommitdiff
path: root/templates/totp-enroll.html
diff options
context:
space:
mode:
authorLena <lena@omega>2026-08-01 00:00:00 +0000
committerLena <lena@omega>2026-08-01 00:00:00 +0000
commitbb6bc2387d58c737dbf92e73f8544bf39319dbd8 (patch)
tree6d5eaf5dac213074cd832da50f64260fce728fed /templates/totp-enroll.html
downloadgit-forge-bb6bc2387d58c737dbf92e73f8544bf39319dbd8.tar.gz
Enter git-forgeHEADmaster
A small self-hosted git forge: HTTP push and pull, cgit browsing, local and OIDC accounts, TOTP, scoped push tokens, per-repo permissions, issues, a wiki, and outbound mail. It does not reimplement git. git-http-backend and cgit run as CGI behind its own listener, which authorises every request before exec'ing either. One binary, one data directory, one listener: no database, no JavaScript, and state is JSON in a git repo with a working tree.
Diffstat (limited to 'templates/totp-enroll.html')
-rw-r--r--templates/totp-enroll.html96
1 files changed, 96 insertions, 0 deletions
diff --git a/templates/totp-enroll.html b/templates/totp-enroll.html
new file mode 100644
index 0000000..da3d301
--- /dev/null
+++ b/templates/totp-enroll.html
@@ -0,0 +1,96 @@
+{{define "title"}}Authenticator - {{.Site}}{{end}}
+{{define "main"}}
+<h2>Authenticator</h2>
+
+{{with .Data.Codes}}
+<h3>Recovery codes</h3>
+<p>Each of these works once, in place of a code. They are not shown again.</p>
+<pre>{{range .}}{{.}}
+{{end}}</pre>
+{{end}}
+
+{{if .Data.Enrolled}}
+<p>
+This account has an authenticator, and {{.Data.Left}} recovery codes left.
+</p>
+
+<h3>New recovery codes</h3>
+<p>Making new ones stops the old ones working.</p>
+<form method="post" action="/settings/totp/codes">
+<input type="hidden" name="csrf" value="{{.CSRF}}">
+{{if .Data.Local}}
+<p>
+<label for="codes-current">Current password</label>
+<input id="codes-current" name="current" type="password" autocomplete="current-password" required>
+</p>
+{{else}}
+<p>
+<label for="codes-code">Code from the authenticator</label>
+<input id="codes-code" name="code" inputmode="numeric" autocomplete="one-time-code" required>
+</p>
+{{end}}
+<p><button type="submit">Make new recovery codes</button></p>
+</form>
+
+<h3>Remove</h3>
+{{if .Data.Required}}
+<p>
+This account holds the global admin flag, so it must keep an authenticator.
+Another admin has to take the flag away first.
+</p>
+{{else}}
+<p>Removing it signs out every session for this account.</p>
+<form method="post" action="/settings/totp/remove">
+<input type="hidden" name="csrf" value="{{.CSRF}}">
+{{if .Data.Local}}
+<p>
+<label for="current">Current password</label>
+<input id="current" name="current" type="password" autocomplete="current-password" required>
+</p>
+{{else}}
+<p>
+<label for="remove-code">Code from the authenticator</label>
+<input id="remove-code" name="code" inputmode="numeric" autocomplete="one-time-code" required>
+</p>
+{{end}}
+<p><button type="submit">Remove the authenticator</button></p>
+</form>
+{{end}}
+
+{{else}}
+<p>
+Type this secret into an authenticator, or give it the URI. There is no QR
+code: it would be useless in a terminal browser.
+</p>
+<pre>{{.Data.Secret}}
+
+{{.Data.URI}}</pre>
+<p>
+Then prove it took, which is what enrols it. Enrolling signs out every other
+session.
+{{if .Data.Local}}
+It takes the password as well: a stolen cookie must not be able to put a second
+factor on this account and lock its owner out.
+{{else}}
+This account signs in through an external provider and has no password here, so
+enrolling rests on this session alone. The address on file is told, and an admin
+can clear an authenticator you did not enrol.
+{{end}}
+</p>
+<form method="post" action="/settings/totp">
+<input type="hidden" name="csrf" value="{{.CSRF}}">
+<input type="hidden" name="secret" value="{{.Data.Secret}}">
+<p>
+<label for="code">Code from the authenticator</label>
+<input id="code" name="code" inputmode="numeric" autocomplete="one-time-code" required>
+</p>
+{{if .Data.Local}}
+<p>
+<label for="enrol-current">Current password</label>
+<input id="enrol-current" name="current" type="password" autocomplete="current-password" required>
+</p>
+{{end}}
+<p><button type="submit">Enroll</button></p>
+</form>
+{{end}}
+{{end}}