···51 name="code"
52 tabindex="1"
53 required
54- placeholder="pds-tngl-sh-foo-bar"
55 />
56 <span class="text-sm text-gray-500 mt-1">
57 Enter the code sent to your email.
···51 name="code"
52 tabindex="1"
53 required
54+ placeholder="tngl-sh-foo-bar"
55 />
56 <span class="text-sm text-gray-500 mt-1">
57 Enter the code sent to your email.
+73-15
appview/signup/signup.go
···1package signup
23import (
04 "fmt"
5 "log/slog"
6 "net/http"
0078 "github.com/go-chi/chi/v5"
9 "github.com/posthog/posthog-go"
···18)
1920type Signup struct {
21- config *config.Config
22- db *db.DB
23- cf *dns.Cloudflare
24- posthog posthog.Client
25- xrpc *xrpcclient.Client
26- idResolver *idresolver.Resolver
27- pages *pages.Pages
28- l *slog.Logger
029}
3031func New(cfg *config.Config, database *db.DB, pc posthog.Client, idResolver *idresolver.Resolver, pages *pages.Pages, l *slog.Logger) *Signup {
···37 l.Warn("failed to create cloudflare client, signup will be disabled", "error", err)
38 }
39 }
004041 return &Signup{
42- config: cfg,
43- db: database,
44- posthog: pc,
45- idResolver: idResolver,
46- cf: cf,
47- pages: pages,
48- l: l,
049 }
50}
51000000000000000000000000000000000000000000000052func (s *Signup) Router() http.Handler {
53 r := chi.NewRouter()
54 r.Post("/", s.signup)
···128129 if !userutil.IsValidSubdomain(username) {
130 s.pages.Notice(w, "signup-error", "Invalid username. Username must be 4–63 characters, lowercase letters, digits, or hyphens, and can't start or end with a hyphen.")
00000131 return
132 }
133
···1package signup
23import (
4+ "bufio"
5 "fmt"
6 "log/slog"
7 "net/http"
8+ "os"
9+ "strings"
1011 "github.com/go-chi/chi/v5"
12 "github.com/posthog/posthog-go"
···21)
2223type Signup struct {
24+ config *config.Config
25+ db *db.DB
26+ cf *dns.Cloudflare
27+ posthog posthog.Client
28+ xrpc *xrpcclient.Client
29+ idResolver *idresolver.Resolver
30+ pages *pages.Pages
31+ l *slog.Logger
32+ disallowedNicknames map[string]bool
33}
3435func New(cfg *config.Config, database *db.DB, pc posthog.Client, idResolver *idresolver.Resolver, pages *pages.Pages, l *slog.Logger) *Signup {
···41 l.Warn("failed to create cloudflare client, signup will be disabled", "error", err)
42 }
43 }
44+45+ disallowedNicknames := loadDisallowedNicknames(cfg.Core.DisallowedNicknamesFile, l)
4647 return &Signup{
48+ config: cfg,
49+ db: database,
50+ posthog: pc,
51+ idResolver: idResolver,
52+ cf: cf,
53+ pages: pages,
54+ l: l,
55+ disallowedNicknames: disallowedNicknames,
56 }
57}
5859+func loadDisallowedNicknames(filepath string, logger *slog.Logger) map[string]bool {
60+ disallowed := make(map[string]bool)
61+62+ if filepath == "" {
63+ logger.Debug("no disallowed nicknames file configured")
64+ return disallowed
65+ }
66+67+ file, err := os.Open(filepath)
68+ if err != nil {
69+ logger.Warn("failed to open disallowed nicknames file", "file", filepath, "error", err)
70+ return disallowed
71+ }
72+ defer file.Close()
73+74+ scanner := bufio.NewScanner(file)
75+ lineNum := 0
76+ for scanner.Scan() {
77+ lineNum++
78+ line := strings.TrimSpace(scanner.Text())
79+ if line == "" || strings.HasPrefix(line, "#") {
80+ continue // skip empty lines and comments
81+ }
82+83+ nickname := strings.ToLower(line)
84+ if userutil.IsValidSubdomain(nickname) {
85+ disallowed[nickname] = true
86+ } else {
87+ logger.Warn("invalid nickname format in disallowed nicknames file",
88+ "file", filepath, "line", lineNum, "nickname", nickname)
89+ }
90+ }
91+92+ if err := scanner.Err(); err != nil {
93+ logger.Error("error reading disallowed nicknames file", "file", filepath, "error", err)
94+ }
95+96+ logger.Info("loaded disallowed nicknames", "count", len(disallowed), "file", filepath)
97+ return disallowed
98+}
99+100+// isNicknameAllowed checks if a nickname is allowed (not in the disallowed list)
101+func (s *Signup) isNicknameAllowed(nickname string) bool {
102+ return !s.disallowedNicknames[strings.ToLower(nickname)]
103+}
104+105func (s *Signup) Router() http.Handler {
106 r := chi.NewRouter()
107 r.Post("/", s.signup)
···181182 if !userutil.IsValidSubdomain(username) {
183 s.pages.Notice(w, "signup-error", "Invalid username. Username must be 4–63 characters, lowercase letters, digits, or hyphens, and can't start or end with a hyphen.")
184+ return
185+ }
186+187+ if !s.isNicknameAllowed(username) {
188+ s.pages.Notice(w, "signup-error", "This username is not available. Please choose a different one.")
189 return
190 }
191