this repo has no description
1package auth
2
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "net/http"
8 "time"
9
10 comatproto "github.com/bluesky-social/indigo/api/atproto"
11 "github.com/bluesky-social/indigo/atproto/identity"
12 "github.com/bluesky-social/indigo/atproto/syntax"
13 "github.com/bluesky-social/indigo/xrpc"
14 "github.com/gorilla/sessions"
15 "github.com/icyphox/bild/appview"
16)
17
18type Auth struct {
19 Store *sessions.CookieStore
20}
21
22type AtSessionCreate struct {
23 comatproto.ServerCreateSession_Output
24 PDSEndpoint string
25}
26
27type AtSessionRefresh struct {
28 comatproto.ServerRefreshSession_Output
29 PDSEndpoint string
30}
31
32func Make() (*Auth, error) {
33 store := sessions.NewCookieStore([]byte(appview.SESSION_COOKIE_SECRET))
34 return &Auth{store}, nil
35}
36
37func ResolveIdent(ctx context.Context, arg string) (*identity.Identity, error) {
38 id, err := syntax.ParseAtIdentifier(arg)
39 if err != nil {
40 return nil, err
41 }
42
43 dir := identity.DefaultDirectory()
44 return dir.Lookup(ctx, *id)
45}
46
47func (a *Auth) CreateInitialSession(ctx context.Context, username, appPassword string) (*comatproto.ServerCreateSession_Output, error) {
48 resolved, err := ResolveIdent(ctx, username)
49 if err != nil {
50 return nil, fmt.Errorf("invalid handle: %s", err)
51 }
52
53 pdsUrl := resolved.PDSEndpoint()
54 client := xrpc.Client{
55 Host: pdsUrl,
56 }
57
58 atSession, err := comatproto.ServerCreateSession(ctx, &client, &comatproto.ServerCreateSession_Input{
59 Identifier: resolved.DID.String(),
60 Password: appPassword,
61 })
62 if err != nil {
63 return nil, fmt.Errorf("invalid app password")
64 }
65
66 return atSession, nil
67}
68
69// Sessionish is an interface that provides access to the common fields of both types.
70type Sessionish interface {
71 GetAccessJwt() string
72 GetActive() *bool
73 GetDid() string
74 GetDidDoc() *interface{}
75 GetHandle() string
76 GetRefreshJwt() string
77 GetStatus() *string
78}
79
80// Create a wrapper type for ServerRefreshSession_Output
81type RefreshSessionWrapper struct {
82 *comatproto.ServerRefreshSession_Output
83}
84
85func (s *RefreshSessionWrapper) GetAccessJwt() string {
86 return s.AccessJwt
87}
88
89func (s *RefreshSessionWrapper) GetActive() *bool {
90 return s.Active
91}
92
93func (s *RefreshSessionWrapper) GetDid() string {
94 return s.Did
95}
96
97func (s *RefreshSessionWrapper) GetDidDoc() *interface{} {
98 return s.DidDoc
99}
100
101func (s *RefreshSessionWrapper) GetHandle() string {
102 return s.Handle
103}
104
105func (s *RefreshSessionWrapper) GetRefreshJwt() string {
106 return s.RefreshJwt
107}
108
109func (s *RefreshSessionWrapper) GetStatus() *string {
110 return s.Status
111}
112
113// Create a wrapper type for ServerRefreshSession_Output
114type CreateSessionWrapper struct {
115 *comatproto.ServerCreateSession_Output
116}
117
118func (s *CreateSessionWrapper) GetAccessJwt() string {
119 return s.AccessJwt
120}
121
122func (s *CreateSessionWrapper) GetActive() *bool {
123 return s.Active
124}
125
126func (s *CreateSessionWrapper) GetDid() string {
127 return s.Did
128}
129
130func (s *CreateSessionWrapper) GetDidDoc() *interface{} {
131 return s.DidDoc
132}
133
134func (s *CreateSessionWrapper) GetHandle() string {
135 return s.Handle
136}
137
138func (s *CreateSessionWrapper) GetRefreshJwt() string {
139 return s.RefreshJwt
140}
141
142func (s *CreateSessionWrapper) GetStatus() *string {
143 return s.Status
144}
145
146func (a *Auth) StoreSession(r *http.Request, w http.ResponseWriter, atSessionish Sessionish) error {
147 var didDoc identity.DIDDocument
148
149 bytes, _ := json.Marshal(atSessionish.GetDidDoc())
150 err := json.Unmarshal(bytes, &didDoc)
151 if err != nil {
152 return fmt.Errorf("invalid did document for session")
153 }
154
155 identity := identity.ParseIdentity(&didDoc)
156 pdsEndpoint := identity.PDSEndpoint()
157
158 if pdsEndpoint == "" {
159 return fmt.Errorf("no pds endpoint found")
160 }
161
162 clientSession, _ := a.Store.Get(r, appview.SESSION_NAME)
163 clientSession.Values[appview.SESSION_HANDLE] = atSessionish.GetHandle()
164 clientSession.Values[appview.SESSION_DID] = atSessionish.GetDid()
165 clientSession.Values[appview.SESSION_PDS] = pdsEndpoint
166 clientSession.Values[appview.SESSION_ACCESSJWT] = atSessionish.GetAccessJwt()
167 clientSession.Values[appview.SESSION_REFRESHJWT] = atSessionish.GetRefreshJwt()
168 clientSession.Values[appview.SESSION_EXPIRY] = time.Now().Add(time.Hour).Format(appview.TIME_LAYOUT)
169 clientSession.Values[appview.SESSION_AUTHENTICATED] = true
170
171 return clientSession.Save(r, w)
172}