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/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.

Identify accounts by their registered name

62576fa8157d431dcf2d360f3ebe481de77bda03 · Keenan Nemetz · 14d ago · parent 642e5994

Identify accounts by their registered name

Drop the internal account id and display name. Users, keys, passkeys,
invites, sessions, ACL entries, approvals, locks and CI records now all
use the registered name as the single identity.

The roster migrates in place: old id-keyed tables are rebuilt around the
name, and access-rule/lock references are rewritten through the same
mapping. Display-name editing and whoami --id are removed.

server/admin_users_test.go +18−18

@@ -61,25 +61,25 @@ func TestAdminUsersLifecycle(t *testing.T) {
61 61 t.Fatalf("duplicate name = %d:\n%s", resp.StatusCode, page)
62 62 }
63 63
64 resp, body = f.browserGet(t, "/admin/users/"+acct.ID, cookie)
64 resp, body = f.browserGet(t, "/admin/users/"+acct.Name, cookie)
65 65 if resp.StatusCode != 200 || !strings.Contains(body, "No SSH keys") || !strings.Contains(body, "No browser sessions") {
66 66 t.Fatalf("account page = %d:\n%s", resp.StatusCode, body)
67 67 }
68 68
69 resp, _ = f.browserPost(t, "/admin/users/"+acct.ID+"/admin", cookie, url.Values{
69 resp, _ = f.browserPost(t, "/admin/users/"+acct.Name+"/admin", cookie, url.Values{
70 70 "csrf": {sess.CSRF}, "admin": {"true"},
71 71 })
72 if resp.StatusCode != 303 || !f.srv.Identity.IsAdmin(acct.ID) {
73 t.Fatalf("grant admin = %d, admin=%t", resp.StatusCode, f.srv.Identity.IsAdmin(acct.ID))
72 if resp.StatusCode != 303 || !f.srv.Identity.IsAdmin(acct.Name) {
73 t.Fatalf("grant admin = %d, admin=%t", resp.StatusCode, f.srv.Identity.IsAdmin(acct.Name))
74 74 }
75 resp, _ = f.browserPost(t, "/admin/users/"+acct.ID+"/admin", cookie, url.Values{
75 resp, _ = f.browserPost(t, "/admin/users/"+acct.Name+"/admin", cookie, url.Values{
76 76 "csrf": {sess.CSRF}, "admin": {"false"},
77 77 })
78 if resp.StatusCode != 303 || f.srv.Identity.IsAdmin(acct.ID) {
79 t.Fatalf("revoke admin = %d, admin=%t", resp.StatusCode, f.srv.Identity.IsAdmin(acct.ID))
78 if resp.StatusCode != 303 || f.srv.Identity.IsAdmin(acct.Name) {
79 t.Fatalf("revoke admin = %d, admin=%t", resp.StatusCode, f.srv.Identity.IsAdmin(acct.Name))
80 80 }
81 81
82 resp, body = f.browserPost(t, "/admin/users/"+acct.ID+"/invite", cookie, url.Values{"csrf": {sess.CSRF}})
82 resp, body = f.browserPost(t, "/admin/users/"+acct.Name+"/invite", cookie, url.Values{"csrf": {sess.CSRF}})
83 83 if resp.StatusCode != 200 || !strings.Contains(body, "Enrollment link") {
84 84 t.Fatalf("refresh invite = %d:\n%s", resp.StatusCode, body)
85 85 }
@@ -94,27 +94,27 @@ func TestAdminUsersLifecycle(t *testing.T) {
94 94 if len(writer.Keys) != 1 {
95 95 t.Fatalf("writer keys = %d", len(writer.Keys))
96 96 }
97 if _, err := f.srv.Sessions.Create(writer.ID, nil, "test-browser"); err != nil {
97 if _, err := f.srv.Sessions.Create(writer.Name, nil, "test-browser"); err != nil {
98 98 t.Fatal(err)
99 99 }
100 resp, body = f.browserGet(t, "/admin/users/"+writer.ID, cookie)
100 resp, body = f.browserGet(t, "/admin/users/"+writer.Name, cookie)
101 101 if resp.StatusCode != 200 || !strings.Contains(body, "ssh-ed25519") || !strings.Contains(body, "test-browser") {
102 102 t.Fatalf("account detail with key and session = %d:\n%s", resp.StatusCode, body)
103 103 }
104 resp, _ = f.browserPost(t, "/admin/users/"+writer.ID+"/sessions/revoke", cookie, url.Values{"csrf": {sess.CSRF}})
104 resp, _ = f.browserPost(t, "/admin/users/"+writer.Name+"/sessions/revoke", cookie, url.Values{"csrf": {sess.CSRF}})
105 105 if resp.StatusCode != 303 {
106 106 t.Fatalf("revoke sessions = %d", resp.StatusCode)
107 107 }
108 if list, err := f.srv.Sessions.List(writer.ID); err != nil || len(list) != 0 {
108 if list, err := f.srv.Sessions.List(writer.Name); err != nil || len(list) != 0 {
109 109 t.Fatalf("sessions after revoke = %d, %v", len(list), err)
110 110 }
111 resp, _ = f.browserPost(t, "/admin/users/"+writer.ID+"/keys/remove", cookie, url.Values{
111 resp, _ = f.browserPost(t, "/admin/users/"+writer.Name+"/keys/remove", cookie, url.Values{
112 112 "csrf": {sess.CSRF}, "fingerprint": {writer.Keys[0].Fingerprint},
113 113 })
114 114 if resp.StatusCode != 303 {
115 115 t.Fatalf("remove key = %d", resp.StatusCode)
116 116 }
117 writer, err = f.srv.Identity.Find(writer.ID)
117 writer, err = f.srv.Identity.Find(writer.Name)
118 118 if err != nil {
119 119 t.Fatal(err)
120 120 }
@@ -122,19 +122,19 @@ func TestAdminUsersLifecycle(t *testing.T) {
122 122 t.Fatalf("writer still has %d key(s)", len(writer.Keys))
123 123 }
124 124
125 resp, body = f.browserPost(t, "/admin/users/"+writer.ID+"/retire", cookie, url.Values{
125 resp, body = f.browserPost(t, "/admin/users/"+writer.Name+"/retire", cookie, url.Values{
126 126 "csrf": {sess.CSRF}, "confirm": {"wrong"},
127 127 })
128 128 if resp.StatusCode != 400 || !strings.Contains(body, "Type the account name") {
129 129 t.Fatalf("retire without confirmation = %d:\n%s", resp.StatusCode, body)
130 130 }
131 resp, _ = f.browserPost(t, "/admin/users/"+writer.ID+"/retire", cookie, url.Values{
131 resp, _ = f.browserPost(t, "/admin/users/"+writer.Name+"/retire", cookie, url.Values{
132 132 "csrf": {sess.CSRF}, "confirm": {"wilbur"},
133 133 })
134 134 if resp.StatusCode != 303 || resp.Header.Get("Location") != "/admin/users" {
135 135 t.Fatalf("retire = %d %q", resp.StatusCode, resp.Header.Get("Location"))
136 136 }
137 writer, err = f.srv.Identity.Find(writer.ID)
137 writer, err = f.srv.Identity.Find(writer.Name)
138 138 if err != nil {
139 139 t.Fatal(err)
140 140 }
@@ -143,7 +143,7 @@ func TestAdminUsersLifecycle(t *testing.T) {
143 143 }
144 144
145 145 // CSRF is checked before any mutation.
146 if resp, _ := f.browserPost(t, "/admin/users/"+acct.ID+"/admin", cookie, url.Values{"admin": {"true"}}); resp.StatusCode != 403 {
146 if resp, _ := f.browserPost(t, "/admin/users/"+acct.Name+"/admin", cookie, url.Values{"admin": {"true"}}); resp.StatusCode != 403 {
147 147 t.Fatalf("missing CSRF = %d, want 403", resp.StatusCode)
148 148 }
149 149 }