vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Blame · server/web/templates/admin_users.html
Line attribution on main · 166 line(s)
|
43e681d8
Keenan Nemetz
4d ago
|
1 | {{define "accounts_body"}} |
|
395554f4
Keenan Nemetz
15d ago
|
2 | {{if .Error}}<div class="flash bad">{{.Error}}</div>{{end}} |
| 3 | ||
|
ed03b3d1
Keenan Nemetz
2h ago
|
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> |
|
9579c1f9
Keenan Nemetz
14d ago
|
5 | |
|
8c72543b
Keenan Nemetz
4d ago
|
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> | |
|
ed03b3d1
Keenan Nemetz
2h ago
|
8 | <form method="post" action="/-/users" class="form-block"> |
|
9579c1f9
Keenan Nemetz
14d ago
|
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> | |
|
5b814e99
Keenan Nemetz
14d ago
|
14 | {{template "role-picker" (rolePicker "role" "none" "Instance role" "Instance roles apply to public repositories; admin applies everywhere." "instance" false)}} |
|
9579c1f9
Keenan Nemetz
14d ago
|
15 | </div> |
|
ab326d3a
Keenan Nemetz
14d ago
|
16 | <div class="form-actions"><button type="submit">{{icon "user"}}Create account</button></div> |
|
9579c1f9
Keenan Nemetz
14d ago
|
17 | </form> |
|
8c72543b
Keenan Nemetz
4d ago
|
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> | |
|
ed03b3d1
Keenan Nemetz
2h ago
|
21 | <form method="post" action="/-/users/bots" class="form-block"> |
|
8c72543b
Keenan Nemetz
4d ago
|
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> | |
|
395554f4
Keenan Nemetz
15d ago
|
33 | {{end}} |
| 34 | ||
| 35 | {{define "admin_user"}} | |
| 36 | {{template "header" .}} | |
|
9579c1f9
Keenan Nemetz
14d ago
|
37 | <div class="page-head"> |
|
395554f4
Keenan Nemetz
15d ago
|
38 | <div class="page-head-main"> |
|
8c72543b
Keenan Nemetz
4d ago
|
39 | <h1>{{.Account.Name}}{{if .Account.Bot}} <span class="state">bot</span>{{end}}</h1> |
|
395554f4
Keenan Nemetz
15d ago
|
40 | <p class="page-sub"> |
|
62576fa8
Keenan Nemetz
14d ago
|
41 | <span class="state {{.Account.Status}}">{{.Account.Status}}</span> |
|
5b814e99
Keenan Nemetz
14d ago
|
42 | · instance role {{.Account.Role}} |
|
395554f4
Keenan Nemetz
15d ago
|
43 | · created {{since .Account.Created.Unix}} |
| 44 | </p> | |
| 45 | </div> | |
|
8c72543b
Keenan Nemetz
4d ago
|
46 | {{if not .Account.Bot}} |
|
9579c1f9
Keenan Nemetz
14d ago
|
47 | <div class="page-head-actions"> |
|
ed03b3d1
Keenan Nemetz
2h ago
|
48 | <form class="inline" method="post" action="/-/users/{{.Account.Name}}/invite"> |
|
395554f4
Keenan Nemetz
15d ago
|
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> | |
|
8c72543b
Keenan Nemetz
4d ago
|
53 | {{end}} |
|
395554f4
Keenan Nemetz
15d ago
|
54 | </div> |
| 55 | ||
|
9579c1f9
Keenan Nemetz
14d ago
|
56 | {{if .Error}}<div class="flash bad">{{.Error}}</div>{{end}} |
| 57 | ||
|
5b814e99
Keenan Nemetz
14d ago
|
58 | <h2>Instance role</h2> |
| 59 | {{$role := .Account.Role.String}} | |
|
ed03b3d1
Keenan Nemetz
2h ago
|
60 | <form method="post" action="/-/users/{{.Account.Name}}/role" class="form-block"> |
|
5b814e99
Keenan Nemetz
14d ago
|
61 | <input type="hidden" name="csrf" value="{{.CSRF}}"> |
| 62 | <div class="card form-card"> | |
|
8c72543b
Keenan Nemetz
4d ago
|
63 | {{template "role-picker" (rolePicker "role" $role (printf "Role for %s" .Account.Name) .RoleHelp .RoleScope false)}} |
|
5b814e99
Keenan Nemetz
14d ago
|
64 | </div> |
| 65 | <div class="form-actions"> | |
| 66 | <button type="submit">{{icon "check"}}Save role</button> | |
| 67 | </div> | |
| 68 | </form> | |
| 69 | ||
|
395554f4
Keenan Nemetz
15d ago
|
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> | |
|
ed03b3d1
Keenan Nemetz
2h ago
|
82 | <form class="inline" method="post" action="/-/users/{{$.Account.Name}}/keys/remove"> |
|
395554f4
Keenan Nemetz
15d ago
|
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> | |
|
8c72543b
Keenan Nemetz
4d ago
|
93 | {{else if .Account.Bot}} |
|
c7b9094f
Keenan Nemetz
1d ago
|
94 | <div class="empty-state"><p>No SSH keys. This bot cannot act until a key is added.</p></div> |
|
395554f4
Keenan Nemetz
15d ago
|
95 | {{else}} |
|
c7b9094f
Keenan Nemetz
1d ago
|
96 | <div class="empty-state"><p>No SSH keys. This account can sign in with a passkey only.</p></div> |
|
395554f4
Keenan Nemetz
15d ago
|
97 | {{end}} |
| 98 | ||
|
9579c1f9
Keenan Nemetz
14d ago
|
99 | <div class="with-more"> |
| 100 | <h2>Sessions</h2> | |
| 101 | {{if .Sessions}} | |
|
ed03b3d1
Keenan Nemetz
2h ago
|
102 | <form class="inline" method="post" action="/-/users/{{.Account.Name}}/sessions/revoke"> |
|
9579c1f9
Keenan Nemetz
14d ago
|
103 | <input type="hidden" name="csrf" value="{{.CSRF}}"> |
| 104 | <button type="submit" class="link">Revoke all sessions</button> | |
| 105 | </form> | |
| 106 | {{end}} | |
| 107 | </div> | |
|
395554f4
Keenan Nemetz
15d ago
|
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}} | |
|
c7b9094f
Keenan Nemetz
1d ago
|
125 | <div class="empty-state"><p>No browser sessions.</p></div> |
|
395554f4
Keenan Nemetz
15d ago
|
126 | {{end}} |
| 127 | ||
| 128 | <h2>Danger zone</h2> | |
|
ed03b3d1
Keenan Nemetz
2h ago
|
129 | <form method="post" action="/-/users/{{.Account.Name}}/retire" class="form-block"> |
|
9579c1f9
Keenan Nemetz
14d ago
|
130 | <input type="hidden" name="csrf" value="{{.CSRF}}"> |
| 131 | <div class="card form-card danger-zone"> | |
|
395554f4
Keenan Nemetz
15d ago
|
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> | |
|
9579c1f9
Keenan Nemetz
14d ago
|
137 | </div> |
| 138 | <div class="form-actions"><button type="submit" class="danger">{{icon "circle-x"}}Retire account</button></div> | |
| 139 | </form> | |
|
395554f4
Keenan Nemetz
15d ago
|
140 | {{template "footer" .}} |
| 141 | {{end}} | |
| 142 | ||
| 143 | {{define "admin_invite"}} | |
| 144 | {{template "header" .}} | |
|
9579c1f9
Keenan Nemetz
14d ago
|
145 | <div class="page-head"> |
|
395554f4
Keenan Nemetz
15d ago
|
146 | <div class="page-head-main"> |
| 147 | <h1>Enrollment link</h1> | |
|
62576fa8
Keenan Nemetz
14d ago
|
148 | <p class="page-sub">For <strong>{{.Account.Name}}</strong> · expires {{.Expires.UTC.Format "2006-01-02 15:04 UTC"}}</p> |
|
395554f4
Keenan Nemetz
15d ago
|
149 | </div> |
| 150 | </div> | |
| 151 | ||
| 152 | {{if not .BrowserLogin}} | |
|
ab326d3a
Keenan Nemetz
14d ago
|
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> |
|
395554f4
Keenan Nemetz
15d ago
|
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"> | |
|
ed03b3d1
Keenan Nemetz
2h ago
|
163 | <a class="button secondary" href="/-/users/{{.Account.Name}}">{{icon "user"}}Back to account</a> |
|
395554f4
Keenan Nemetz
15d ago
|
164 | </div> |
| 165 | {{template "footer" .}} | |
| 166 | {{end}} |