aboutsummaryrefslogtreecommitdiff
path: root/templates/settings.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/settings.html
downloadgit-forge-master.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/settings.html')
-rw-r--r--templates/settings.html126
1 files changed, 126 insertions, 0 deletions
diff --git a/templates/settings.html b/templates/settings.html
new file mode 100644
index 0000000..8b2f0f1
--- /dev/null
+++ b/templates/settings.html
@@ -0,0 +1,126 @@
+{{define "title"}}Settings - {{.Site}}{{end}}
+{{define "main"}}
+<h2>Account</h2>
+<p>
+Signed in as {{template "who" .User}}{{if .Admin}}, a global admin{{end}}.
+</p>
+
+<h3>Email and notifications</h3>
+{{if .MailOff}}
+<p class="dim">
+Mail is turned off on this instance, so nothing is sent. The address below is
+still what commits made through the web are attributed to.
+</p>
+{{else}}
+<p class="dim">
+An address receives nothing until a link sent to it has been followed. Notices
+about your own account ignore the toggle below, because they are security facts
+rather than activity.
+</p>
+{{end}}
+<form method="post" action="/settings/email">
+<input type="hidden" name="csrf" value="{{.CSRF}}">
+<p>
+<label for="email">Email address</label>
+<input id="email" name="email" type="email" value="{{.Data.Email}}">
+{{if .Data.Email}}{{if not .Data.EmailConfirmed}}<span class="dim">unconfirmed</span>{{end}}{{end}}
+</p>
+<p>
+<label for="notify">
+<input id="notify" name="notify" type="checkbox" value="yes" {{if .Data.Notify}}checked{{end}}>
+Send me issue and repository notifications
+</label>
+</p>
+<p><button type="submit">Save</button></p>
+</form>
+
+{{if .Data.Local}}
+<h3>Change password</h3>
+<form method="post" action="/settings/password">
+<input type="hidden" name="csrf" value="{{.CSRF}}">
+<p>
+<label for="current">Current password</label>
+<input id="current" name="current" type="password" autocomplete="current-password" required>
+</p>
+<p>
+<label for="new">New password</label>
+<input id="new" name="new" type="password" autocomplete="new-password" required>
+</p>
+<p>
+<label for="again">New password again</label>
+<input id="again" name="again" type="password" autocomplete="new-password" required>
+</p>
+<p><button type="submit">Change password</button></p>
+</form>
+{{else}}
+<h3>Password</h3>
+<p>This account signs in through an external provider, so there is no password here.</p>
+{{end}}
+
+<h3>Push tokens</h3>
+<p class="dim">
+Git over HTTP takes a token, never your password. A token is scoped to one
+repository and carries the access you already have there: clone if you can read
+it, push if you can write it, the wiki if you may edit it. It carries no second
+factor, and it can be revoked on its own without touching anything else.
+</p>
+<pre>git clone {{.Base}}/section/repo.git
+Username: {{.User}}
+Password: the token</pre>
+{{with .Data.Secret}}
+<div class="notice">Token for {{$.User}}, shown once:</div>
+<pre id="token">{{.}}</pre>
+{{end}}
+<table summary="push tokens" class="list nowrap">
+<tr class="nohover">
+<th class="left">Id</th><th class="left">Repository</th>
+<th class="left">Made</th><th class="left">Last used</th><th class="left"></th>
+</tr>
+{{range .Data.Tokens}}
+<tr>
+<td>{{.ID}}</td>
+<td><a href="/{{.Repo}}/">{{.Repo}}</a></td>
+<td class="dim">{{if .Created}}{{.Created}}{{else}}unknown{{end}}</td>
+<td class="dim">{{if .Used}}{{.Used}}{{else}}never{{end}}</td>
+<td>
+<form method="post" action="/settings/tokens/revoke">
+<input type="hidden" name="csrf" value="{{$.CSRF}}">
+<input type="hidden" name="id" value="{{.ID}}">
+<button type="submit">revoke</button>
+</form>
+</td>
+</tr>
+{{else}}
+<tr><td colspan="5" class="dim">None. Mint one below to push over HTTP.</td></tr>
+{{end}}
+</table>
+<p class="dim">
+Dates are days, not times: a write on every request git makes would be a write
+on every request git makes. A token that has never been used, or was last used
+a long time ago, is one worth revoking.
+</p>
+<form method="post" action="/settings/tokens">
+<input type="hidden" name="csrf" value="{{.CSRF}}">
+<p>
+<label for="repo">Repository you can reach</label>
+<input id="repo" name="repo" placeholder="section/repo" autocapitalize="none" required>
+</p>
+<p><button type="submit">Mint a token</button></p>
+</form>
+
+<h3>Authenticator</h3>
+<p>
+<a href="/settings/totp">Second factor</a>. An account with the global admin
+flag has to have one before it can administer anything.
+</p>
+
+<h3>Sessions</h3>
+<p>
+Signing out everywhere invalidates every session cookie ever issued for this
+account, including this browser's.
+</p>
+<form method="post" action="/settings/sessions">
+<input type="hidden" name="csrf" value="{{.CSRF}}">
+<p><button type="submit">Sign out everywhere</button></p>
+</form>
+{{end}}