handle-auth.go raw
1 package app
2
3 import (
4 "next.orly.dev/pkg/lol/chk"
5 "next.orly.dev/pkg/lol/log"
6 "next.orly.dev/pkg/nostr/encoders/envelopes/authenvelope"
7 "next.orly.dev/pkg/nostr/encoders/envelopes/okenvelope"
8 "next.orly.dev/pkg/nostr/encoders/reason"
9 "next.orly.dev/pkg/nostr/protocol/auth"
10 )
11
12 // zeroEventID is used for OK responses when we cannot parse the event ID
13 var zeroEventID = make([]byte, 32)
14
15 func (l *Listener) HandleAuth(b []byte) (err error) {
16 var rem []byte
17 env := authenvelope.NewResponse()
18 if rem, err = env.Unmarshal(b); chk.E(err) {
19 // NIP-42: AUTH messages MUST be answered with an OK message
20 // For parse failures, use zero event ID
21 log.E.F("%s AUTH unmarshal failed: %v", l.remote, err)
22 if writeErr := okenvelope.NewFrom(
23 zeroEventID, false, reason.Error.F("failed to parse auth event: %s", err),
24 ).Write(l); chk.E(writeErr) {
25 return writeErr
26 }
27 return
28 }
29 defer func() {
30 if env != nil && env.Event != nil {
31 env.Event.Free()
32 }
33 }()
34 if len(rem) > 0 {
35 log.T.F("extra '%s'", rem)
36 }
37 var valid bool
38 if valid, err = auth.Validate(
39 env.Event, l.challenge.Load(),
40 l.WebSocketURL(l.req),
41 ); err != nil {
42 e := err.Error()
43 if err = Ok.Error(l, env, e); chk.E(err) {
44 return
45 }
46 return
47 } else if !valid {
48 if err = Ok.Error(
49 l, env, "auth response event is invalid",
50 ); chk.E(err) {
51 return
52 }
53 return
54 } else {
55 if err = okenvelope.NewFrom(
56 env.Event.ID, true,
57 ).Write(l); chk.E(err) {
58 return
59 }
60 log.D.F(
61 "%s authed to pubkey %0x", l.remote,
62 env.Event.Pubkey,
63 )
64 l.authedPubkey.Store(env.Event.Pubkey)
65
66 // Check if this is a first-time user and create welcome note
67 go l.handleFirstTimeUser(env.Event.Pubkey)
68 }
69 return
70 }
71
72 // handleFirstTimeUser checks if user is logging in for first time and creates welcome note
73 func (l *Listener) handleFirstTimeUser(pubkey []byte) {
74 // Check if this is a first-time user
75 isFirstTime, err := l.Server.DB.IsFirstTimeUser(pubkey)
76 if err != nil {
77 log.E.F("failed to check first-time user status: %v", err)
78 return
79 }
80
81 if !isFirstTime {
82 return // Not a first-time user
83 }
84
85 // Get payment processor to create welcome note
86 if l.Server.paymentProcessor != nil {
87 // Set the dashboard URL based on the current HTTP request
88 dashboardURL := l.Server.DashboardURL(l.req)
89 l.Server.paymentProcessor.SetDashboardURL(dashboardURL)
90
91 if err := l.Server.paymentProcessor.CreateWelcomeNote(pubkey); err != nil {
92 log.E.F("failed to create welcome note for first-time user: %v", err)
93 }
94 }
95 }
96