Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Code

395 commit(s) on main

update readme Keenan Nemetz · 30m ago 32290114
history blame raw 6.3 KiB
1{{define "accounts_body"}}
2{{if .Error}}<div class="flash bad">{{.Error}}</div>{{end}}
3
4<p class="muted">To change a role, inspect keys or sessions, or retire an account, open it from the <a href="/-/u">users directory</a>.</p>
5
6<h2>Invite a person</h2>
7<p class="muted">Send them a one-time link: they choose a passkey, then can add an SSH key.</p>
8<form method="post" action="/-/users" class="form-block">
9 <input type="hidden" name="csrf" value="{{.CSRF}}">
10 <div class="card form-card">
11 <label>Account name
12 <input type="text" name="name" required maxlength="63" autocomplete="off" placeholder="lowercase-name">
13 </label>
14 {{template "role-picker" (rolePicker "role" "none" "Instance role" "Instance roles apply to public repositories; admin applies everywhere." "instance" false)}}
15 </div>
16 <div class="form-actions"><button type="submit">{{icon "user"}}Create account</button></div>
17</form>
18
19<h2>Create a bot account</h2>
20<p class="muted">For a runner or another automation. It acts with the SSH key you paste here and cannot sign in to the browser or become an instance admin.</p>
21<form method="post" action="/-/users/bots" class="form-block">
22 <input type="hidden" name="csrf" value="{{.CSRF}}">
23 <div class="card form-card">
24 <label>Account name
25 <input type="text" name="name" required maxlength="63" autocomplete="off" placeholder="lowercase-name">
26 </label>
27 <label for="bot-public-key">SSH public key</label>
28 <textarea id="bot-public-key" name="key" rows="3" placeholder="ssh-ed25519 AAAA... you@example.com" required></textarea>
29 {{template "role-picker" (rolePicker "role" "none" "Instance role" "Instance roles apply to public repositories. A bot cannot be an instance admin." "bot" false)}}
30 </div>
31 <div class="form-actions"><button type="submit">{{icon "terminal"}}Create bot</button></div>
32</form>
33{{end}}
34
35{{define "admin_user"}}
36{{template "header" .}}
37<div class="page-head">
38 <div class="page-head-main">
39 <h1>{{.Account.Name}}{{if .Account.Bot}} <span class="state">bot</span>{{end}}</h1>
40 <p class="page-sub">
41 <span class="state {{.Account.Status}}">{{.Account.Status}}</span>
42 · instance role {{.Account.Role}}
43 · created {{since .Account.Created.Unix}}
44 </p>
45 </div>
46 {{if not .Account.Bot}}
47 <div class="page-head-actions">
48 <form class="inline" method="post" action="/-/users/{{.Account.Name}}/invite">
49 <input type="hidden" name="csrf" value="{{.CSRF}}">
50 <button type="submit" class="secondary">{{icon "external-link"}}New enrollment link</button>
51 </form>
52 </div>
53 {{end}}
54</div>
55
56{{if .Error}}<div class="flash bad">{{.Error}}</div>{{end}}
57
58<h2>Instance role</h2>
59{{$role := .Account.Role.String}}
60<form method="post" action="/-/users/{{.Account.Name}}/role" class="form-block">
61 <input type="hidden" name="csrf" value="{{.CSRF}}">
62 <div class="card form-card">
63 {{template "role-picker" (rolePicker "role" $role (printf "Role for %s" .Account.Name) .RoleHelp .RoleScope false)}}
64 </div>
65 <div class="form-actions">
66 <button type="submit">{{icon "check"}}Save role</button>
67 </div>
68</form>
69
70<h2>SSH keys</h2>
71{{if .Account.Keys}}
72<div class="panel">
73 <table>
74 <thead><tr><th>Fingerprint</th><th>Type</th><th>Comment</th><th></th></tr></thead>
75 <tbody>
76 {{range .Account.Keys}}
77 <tr>
78 <td><code>{{.Fingerprint}}</code></td>
79 <td>{{.Type}}</td>
80 <td class="muted">{{.Comment}}</td>
81 <td>
82 <form class="inline" method="post" action="/-/users/{{$.Account.Name}}/keys/remove">
83 <input type="hidden" name="csrf" value="{{$.CSRF}}">
84 <input type="hidden" name="fingerprint" value="{{.Fingerprint}}">
85 <button type="submit" class="danger">Remove</button>
86 </form>
87 </td>
88 </tr>
89 {{end}}
90 </tbody>
91 </table>
92</div>
93{{else if .Account.Bot}}
94<div class="empty-state"><p>No SSH keys. This bot cannot act until a key is added.</p></div>
95{{else}}
96<div class="empty-state"><p>No SSH keys. This account can sign in with a passkey only.</p></div>
97{{end}}
98
99<div class="with-more">
100 <h2>Sessions</h2>
101 {{if .Sessions}}
102 <form class="inline" method="post" action="/-/users/{{.Account.Name}}/sessions/revoke">
103 <input type="hidden" name="csrf" value="{{.CSRF}}">
104 <button type="submit" class="link">Revoke all sessions</button>
105 </form>
106 {{end}}
107</div>
108{{if .Sessions}}
109<div class="panel">
110 <table>
111 <thead><tr><th>Created</th><th>Last seen</th><th>Expires</th><th>User agent</th></tr></thead>
112 <tbody>
113 {{range .Sessions}}
114 <tr>
115 <td class="nowrap">{{since .Created.Unix}}</td>
116 <td class="nowrap">{{since .LastSeen.Unix}}</td>
117 <td class="nowrap">{{.Expires.UTC.Format "2006-01-02 15:04"}}</td>
118 <td class="muted">{{.UserAgent}}</td>
119 </tr>
120 {{end}}
121 </tbody>
122 </table>
123</div>
124{{else}}
125<div class="empty-state"><p>No browser sessions.</p></div>
126{{end}}
127
128<h2>Danger zone</h2>
129<form method="post" action="/-/users/{{.Account.Name}}/retire" class="form-block">
130 <input type="hidden" name="csrf" value="{{.CSRF}}">
131 <div class="card form-card danger-zone">
132 <h3>Retire account</h3>
133 <p class="muted">Disables the account, ends its sessions, and closes any enrollment links. The name is never reissued.</p>
134 <label>Type <code>{{.Account.Name}}</code> to confirm
135 <input type="text" name="confirm" required autocomplete="off">
136 </label>
137 </div>
138 <div class="form-actions"><button type="submit" class="danger">{{icon "circle-x"}}Retire account</button></div>
139</form>
140{{template "footer" .}}
141{{end}}
142
143{{define "admin_invite"}}
144{{template "header" .}}
145<div class="page-head">
146 <div class="page-head-main">
147 <h1>Enrollment link</h1>
148 <p class="page-sub">For <strong>{{.Account.Name}}</strong> · expires {{.Expires.UTC.Format "2006-01-02 15:04 UTC"}}</p>
149 </div>
150</div>
151
152{{if not .BrowserLogin}}
153<div class="flash bad">Browser sign-in is disabled on this instance, so this link cannot be used until public_url is set to an HTTPS URL.</div>
154{{end}}
155
156<div class="card">
157 <p>Send this link to the account holder. It is shown once, and any earlier unused link for this account has been superseded.</p>
158 <p><code>{{.Link}}</code></p>
159 <p><button type="button" class="secondary" data-copy="{{.Link}}">{{icon "copy"}}Copy link</button></p>
160</div>
161
162<div class="form-actions">
163 <a class="button secondary" href="/-/users/{{.Account.Name}}">{{icon "user"}}Back to account</a>
164</div>
165{{template "footer" .}}
166{{end}}
167