Signed-off-by: Anirudh Oppiliappan anirudh@tangled.sh
+6
-5
appview/config/config.go
+6
-5
appview/config/config.go
···
10
10
)
11
11
12
12
type CoreConfig struct {
13
-
CookieSecret string `env:"COOKIE_SECRET, default=00000000000000000000000000000000"`
14
-
DbPath string `env:"DB_PATH, default=appview.db"`
15
-
ListenAddr string `env:"LISTEN_ADDR, default=0.0.0.0:3000"`
16
-
AppviewHost string `env:"APPVIEW_HOST, default=https://tangled.sh"`
17
-
Dev bool `env:"DEV, default=false"`
13
+
CookieSecret string `env:"COOKIE_SECRET, default=00000000000000000000000000000000"`
14
+
DbPath string `env:"DB_PATH, default=appview.db"`
15
+
ListenAddr string `env:"LISTEN_ADDR, default=0.0.0.0:3000"`
16
+
AppviewHost string `env:"APPVIEW_HOST, default=https://tangled.sh"`
17
+
Dev bool `env:"DEV, default=false"`
18
+
DisallowedNicknamesFile string `env:"DISALLOWED_NICKNAMES_FILE"`
18
19
}
19
20
20
21
type OAuthConfig struct {
+1
-1
appview/pages/templates/user/completeSignup.html
+1
-1
appview/pages/templates/user/completeSignup.html
+73
-15
appview/signup/signup.go
+73
-15
appview/signup/signup.go
···
1
1
package signup
2
2
3
3
import (
4
+
"bufio"
4
5
"fmt"
5
6
"log/slog"
6
7
"net/http"
8
+
"os"
9
+
"strings"
7
10
8
11
"github.com/go-chi/chi/v5"
9
12
"github.com/posthog/posthog-go"
···
18
21
)
19
22
20
23
type 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
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
29
33
}
30
34
31
35
func New(cfg *config.Config, database *db.DB, pc posthog.Client, idResolver *idresolver.Resolver, pages *pages.Pages, l *slog.Logger) *Signup {
···
38
42
}
39
43
}
40
44
45
+
disallowedNicknames := loadDisallowedNicknames(cfg.Core.DisallowedNicknamesFile, l)
46
+
41
47
return &Signup{
42
-
config: cfg,
43
-
db: database,
44
-
posthog: pc,
45
-
idResolver: idResolver,
46
-
cf: cf,
47
-
pages: pages,
48
-
l: l,
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
+
}
58
+
59
+
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
+
}
49
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)]
50
103
}
51
104
52
105
func (s *Signup) Router() http.Handler {
···
131
184
return
132
185
}
133
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
+
134
192
email, err := db.GetEmailForCode(s.db, code)
135
193
if err != nil {
136
194
s.l.Error("failed to get email for code", "error", err)