-
Notifications
You must be signed in to change notification settings - Fork 1
/
auth.go
93 lines (85 loc) · 2.72 KB
/
auth.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package main
import (
"encoding/json"
"fmt"
"sync"
"github.com/google/uuid"
"github.com/vocdoni/vote-frame/farcasterauth"
"go.vocdoni.io/dvote/httprouter"
"go.vocdoni.io/dvote/httprouter/apirest"
"go.vocdoni.io/dvote/log"
)
// authChannels is a map of existing authentication channels.
var authChannels sync.Map
// authLinkHandler creates an authentication channel and returns the URL and ID.
func (v *vocdoniHandler) authLinkHandler(msg *apirest.APIdata, ctx *httprouter.HTTPContext) error {
c := farcasterauth.New()
resp, err := c.CreateChannel(serverURL)
if err != nil {
return fmt.Errorf("could not create authentication channel: %v", err)
}
data, err := json.Marshal(
map[string]string{
"url": resp.URL,
"id": resp.Nonce,
},
)
if err != nil {
return fmt.Errorf("could not marshal response: %v", err)
}
if _, ok := authChannels.Load(resp.Nonce); ok {
return fmt.Errorf("channel already exists")
}
authChannels.Store(resp.Nonce, c)
log.Debugw("authentication channel created", "id", resp.Nonce, "url", resp.URL)
return ctx.Send(data, apirest.HTTPstatusOK)
}
// authVerifyHandler verifies the authentication channel and returns the auth token.
func (v *vocdoniHandler) authVerifyHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) error {
nonce := ctx.URLParam("id")
if nonce == "" {
return fmt.Errorf("missing id parameter")
}
c, ok := authChannels.Load(nonce)
if !ok {
return ctx.Send(nil, apirest.HTTPstatusNotFound)
}
resp, err := c.(*farcasterauth.Client).CheckStatus()
if err != nil {
return ctx.Send(nil, apirest.HTTPstatusNoContent)
}
defer authChannels.Delete(nonce)
token, err := uuid.NewRandom()
if err != nil {
return fmt.Errorf("could not generate token: %v", err)
}
// Remove unnecessary fields
resp.State = ""
resp.Nonce = ""
resp.Message = ""
resp.Signature = ""
// Marshal the response
data, err := json.Marshal(map[string]any{
"profile": resp,
"authToken": token.String(),
})
if err != nil {
return fmt.Errorf("could not marshal response: %v", err)
}
v.addAuthTokenFunc(resp.Fid, token.String())
log.Infow("authentication completed", "username", resp.Username, "fid", resp.Fid, "reputation")
return ctx.Send(data, apirest.HTTPstatusOK)
}
// authCheckHandler checks if the auth token is valid and updates the activity time.
func (v *vocdoniHandler) authCheckHandler(msg *apirest.APIdata, ctx *httprouter.HTTPContext) error {
token := msg.AuthToken
if token == "" {
return fmt.Errorf("missing auth token header")
}
auth, err := v.db.UpdateActivityAndGetData(token)
if err != nil {
return ctx.Send([]byte(err.Error()), apirest.HTTPstatusNotFound)
}
log.Infow("authentication check completed", "fid", auth.UserID)
return ctx.Send([]byte("ok"), apirest.HTTPstatusOK)
}