···9 "log/slog"
10 "net/http"
11 "slices"
012 "time"
1314 comatproto "github.com/bluesky-social/indigo/api/atproto"
···91 go o.addToDefaultKnot(sessData.AccountDID.String())
92 go o.addToDefaultSpindle(sessData.AccountDID.String())
93 go o.ensureTangledProfile(sessData)
09495 if !o.Config.Core.Dev {
96 err = o.Posthog.Enqueue(posthog.Capture{
···358 }
359360 return nil
000000000000000000000000000361}
362363// getAppPasswordSession returns a cached AppPasswordSession, creating one if needed.
···9 "log/slog"
10 "net/http"
11 "slices"
12+ "strings"
13 "time"
1415 comatproto "github.com/bluesky-social/indigo/api/atproto"
···92 go o.addToDefaultKnot(sessData.AccountDID.String())
93 go o.addToDefaultSpindle(sessData.AccountDID.String())
94 go o.ensureTangledProfile(sessData)
95+ go o.autoClaimTnglShDomain(sessData.AccountDID.String())
9697 if !o.Config.Core.Dev {
98 err = o.Posthog.Enqueue(posthog.Capture{
···360 }
361362 return nil
363+}
364+365+// autoClaimTnglShDomain checks if the user has a .tngl.sh handle and, if so,
366+// ensures their corresponding sites domain is claimed. This is idempotent —
367+// ClaimDomain is a no-op if the claim already exists.
368+func (o *OAuth) autoClaimTnglShDomain(did string) {
369+ l := o.Logger.With("did", did)
370+371+ pdsDomain := strings.TrimPrefix(o.Config.Pds.Host, "https://")
372+ pdsDomain = strings.TrimPrefix(pdsDomain, "http://")
373+374+ resolved, err := o.IdResolver.ResolveIdent(context.Background(), did)
375+ if err != nil {
376+ l.Error("autoClaimTnglShDomain: failed to resolve ident", "err", err)
377+ return
378+ }
379+380+ handle := resolved.Handle.String()
381+ if !strings.HasSuffix(handle, "."+pdsDomain) {
382+ return
383+ }
384+385+ if err := db.ClaimDomain(o.Db, did, handle); err != nil {
386+ l.Warn("autoClaimTnglShDomain: failed to claim domain", "domain", handle, "err", err)
387+ } else {
388+ l.Info("autoClaimTnglShDomain: claimed domain", "domain", handle)
389+ }
390}
391392// getAppPasswordSession returns a cached AppPasswordSession, creating one if needed.
+18
appview/signup/signup.go
···311 }
312 emailAdded = true
313000000000000000000314 // if we get here, we've successfully created the account and added the email
315 success = true
316
···311 }
312 emailAdded = true
313314+ // step 4: auto-claim <username>.<pds-domain> for this user.
315+ // All signups through this flow receive a <username>.tngl.sh handle
316+ // (or whatever the configured PDS host is), so we claim the matching
317+ // sites subdomain on their behalf. This is the only way to obtain a
318+ // *.tngl.sh sites domain; it cannot be claimed manually via settings.
319+ pdsDomain := strings.TrimPrefix(s.config.Pds.Host, "https://")
320+ pdsDomain = strings.TrimPrefix(pdsDomain, "http://")
321+ autoClaimDomain := username + "." + pdsDomain
322+ if err := db.ClaimDomain(s.db, did, autoClaimDomain); err != nil {
323+ s.l.Warn("failed to auto-claim sites domain at signup",
324+ "domain", autoClaimDomain,
325+ "did", did,
326+ "error", err,
327+ )
328+ } else {
329+ s.l.Info("auto-claimed sites domain at signup", "domain", autoClaimDomain, "did", did)
330+ }
331+332 // if we get here, we've successfully created the account and added the email
333 success = true
334