mirror of
https://github.com/profullstack/agentbbs.git
synced 2026-08-13 14:27:27 +00:00
join@: let new members pick their own username
Onboarding hard-coded the account name to member-<fp8>, so everyone got an unmemorable handle like member-zafztqdk for ssh <name>@host and /~<name>. New keys are now prompted for a username during join@. auth.SanitizeUsername folds input to the hub/subdomain charset (lowercase [a-z0-9-], 3–20 chars, '_'/space -> '-', no doubled/edge dashes); auth.IsReservedName blocks route and infra labels (bbs/join/pod/domain/admin/agent/video/video-*/www/...). The name must be free (UserByName) or we re-prompt; pressing enter keeps the member-<fp8> default. Returning keys keep the name they already chose. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
31c00cd65a
commit
ac4b0873d9
3 changed files with 143 additions and 7 deletions
|
|
@ -40,3 +40,48 @@ func TestAdminsEmpty(t *testing.T) {
|
|||
t.Error("nobody is admin when allowlist is empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSanitizeUsername(t *testing.T) {
|
||||
cases := []struct {
|
||||
in string
|
||||
want string
|
||||
ok bool
|
||||
}{
|
||||
{"anthony", "anthony", true},
|
||||
{" Cool_Name 42 ", "cool-name-42", true},
|
||||
{"a--b__c", "a-b-c", true},
|
||||
{"-Edge--", "edge", true},
|
||||
{"MixedCASE", "mixedcase", true},
|
||||
{"ab", "ab", false}, // too short
|
||||
{"!!", "", false}, // nothing usable
|
||||
{"this-name-is-way-too-long-to-accept", "", false}, // >20 after... actually long
|
||||
{"admin", "admin", false}, // reserved (route/infra)
|
||||
{"pod", "pod", false}, // reserved route
|
||||
{"video-7f3a", "video-7f3a", false}, // reserved call route
|
||||
{"WWW", "www", false}, // reserved infra label
|
||||
}
|
||||
for _, c := range cases {
|
||||
got, ok := SanitizeUsername(c.in)
|
||||
if ok != c.ok {
|
||||
t.Errorf("SanitizeUsername(%q) ok=%v, want %v (got name %q)", c.in, ok, c.ok, got)
|
||||
}
|
||||
// For valid results the cleaned name must match; for invalid ones we
|
||||
// only assert the usability flag (the cleaned form is advisory).
|
||||
if c.ok && got != c.want {
|
||||
t.Errorf("SanitizeUsername(%q) = %q, want %q", c.in, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsReservedName(t *testing.T) {
|
||||
for _, n := range []string{"admin", "bbs", "pod", "join", "domain", "agent", "www", "video", "video-abc", "ROOT"} {
|
||||
if !IsReservedName(n) {
|
||||
t.Errorf("IsReservedName(%q) = false, want true", n)
|
||||
}
|
||||
}
|
||||
for _, n := range []string{"anthony", "cool-name-42", "member-zafztqdk"} {
|
||||
if IsReservedName(n) {
|
||||
t.Errorf("IsReservedName(%q) = true, want false", n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue