this repo has no description
1package auth
2
3import (
4 "context"
5 "fmt"
6 "net/http"
7 "time"
8
9 comatproto "github.com/bluesky-social/indigo/api/atproto"
10 "github.com/bluesky-social/indigo/atproto/identity"
11 "github.com/bluesky-social/indigo/xrpc"
12 "github.com/gorilla/sessions"
13 "github.com/sotangled/tangled/appview"
14)
15
16type Auth struct {
17 Store *sessions.CookieStore
18}
19
20type AtSessionCreate struct {
21 comatproto.ServerCreateSession_Output
22 PDSEndpoint string
23}
24
25type AtSessionRefresh struct {
26 comatproto.ServerRefreshSession_Output
27 PDSEndpoint string
28}
29
30func Make() (*Auth, error) {
31 store := sessions.NewCookieStore([]byte(appview.SessionCookieSecret))
32 return &Auth{store}, nil
33}
34
35func (a *Auth) CreateInitialSession(ctx context.Context, resolved *identity.Identity, appPassword string) (*comatproto.ServerCreateSession_Output, error) {
36
37 pdsUrl := resolved.PDSEndpoint()
38 client := xrpc.Client{
39 Host: pdsUrl,
40 }
41
42 atSession, err := comatproto.ServerCreateSession(ctx, &client, &comatproto.ServerCreateSession_Input{
43 Identifier: resolved.DID.String(),
44 Password: appPassword,
45 })
46 if err != nil {
47 return nil, fmt.Errorf("invalid app password")
48 }
49
50 return atSession, nil
51}
52
53// Sessionish is an interface that provides access to the common fields of both types.
54type Sessionish interface {
55 GetAccessJwt() string
56 GetActive() *bool
57 GetDid() string
58 GetDidDoc() *interface{}
59 GetHandle() string
60 GetRefreshJwt() string
61 GetStatus() *string
62}
63
64// Create a wrapper type for ServerRefreshSession_Output
65type RefreshSessionWrapper struct {
66 *comatproto.ServerRefreshSession_Output
67}
68
69func (s *RefreshSessionWrapper) GetAccessJwt() string {
70 return s.AccessJwt
71}
72
73func (s *RefreshSessionWrapper) GetActive() *bool {
74 return s.Active
75}
76
77func (s *RefreshSessionWrapper) GetDid() string {
78 return s.Did
79}
80
81func (s *RefreshSessionWrapper) GetDidDoc() *interface{} {
82 return s.DidDoc
83}
84
85func (s *RefreshSessionWrapper) GetHandle() string {
86 return s.Handle
87}
88
89func (s *RefreshSessionWrapper) GetRefreshJwt() string {
90 return s.RefreshJwt
91}
92
93func (s *RefreshSessionWrapper) GetStatus() *string {
94 return s.Status
95}
96
97// Create a wrapper type for ServerRefreshSession_Output
98type CreateSessionWrapper struct {
99 *comatproto.ServerCreateSession_Output
100}
101
102func (s *CreateSessionWrapper) GetAccessJwt() string {
103 return s.AccessJwt
104}
105
106func (s *CreateSessionWrapper) GetActive() *bool {
107 return s.Active
108}
109
110func (s *CreateSessionWrapper) GetDid() string {
111 return s.Did
112}
113
114func (s *CreateSessionWrapper) GetDidDoc() *interface{} {
115 return s.DidDoc
116}
117
118func (s *CreateSessionWrapper) GetHandle() string {
119 return s.Handle
120}
121
122func (s *CreateSessionWrapper) GetRefreshJwt() string {
123 return s.RefreshJwt
124}
125
126func (s *CreateSessionWrapper) GetStatus() *string {
127 return s.Status
128}
129
130func (a *Auth) StoreSession(r *http.Request, w http.ResponseWriter, atSessionish Sessionish, pdsEndpoint string) error {
131 clientSession, _ := a.Store.Get(r, appview.SessionName)
132 clientSession.Values[appview.SessionHandle] = atSessionish.GetHandle()
133 clientSession.Values[appview.SessionDid] = atSessionish.GetDid()
134 clientSession.Values[appview.SessionPds] = pdsEndpoint
135 clientSession.Values[appview.SessionAccessJwt] = atSessionish.GetAccessJwt()
136 clientSession.Values[appview.SessionRefreshJwt] = atSessionish.GetRefreshJwt()
137 clientSession.Values[appview.SessionExpiry] = time.Now().Add(time.Hour).Format(time.RFC3339)
138 clientSession.Values[appview.SessionAuthenticated] = true
139 return clientSession.Save(r, w)
140}
141
142func (a *Auth) AuthorizedClient(r *http.Request) (*xrpc.Client, error) {
143 clientSession, err := a.Store.Get(r, "appview-session")
144
145 if err != nil || clientSession.IsNew {
146 return nil, err
147 }
148
149 did := clientSession.Values["did"].(string)
150 pdsUrl := clientSession.Values["pds"].(string)
151 accessJwt := clientSession.Values["accessJwt"].(string)
152 refreshJwt := clientSession.Values["refreshJwt"].(string)
153
154 client := &xrpc.Client{
155 Host: pdsUrl,
156 Auth: &xrpc.AuthInfo{
157 AccessJwt: accessJwt,
158 RefreshJwt: refreshJwt,
159 Did: did,
160 },
161 }
162
163 return client, nil
164}
165
166func (a *Auth) GetSession(r *http.Request) (*sessions.Session, error) {
167 return a.Store.Get(r, appview.SessionName)
168}
169
170func (a *Auth) GetDid(r *http.Request) string {
171 clientSession, err := a.Store.Get(r, appview.SessionName)
172 if err != nil || clientSession.IsNew {
173 return ""
174 }
175
176 return clientSession.Values[appview.SessionDid].(string)
177}
178
179func (a *Auth) GetHandle(r *http.Request) string {
180 clientSession, err := a.Store.Get(r, appview.SessionName)
181 if err != nil || clientSession.IsNew {
182 return ""
183 }
184
185 return clientSession.Values[appview.SessionHandle].(string)
186}
187
188type User struct {
189 Handle string
190 Did string
191 Pds string
192}
193
194func (a *Auth) GetUser(r *http.Request) *User {
195 clientSession, err := a.Store.Get(r, appview.SessionName)
196
197 if err != nil || clientSession.IsNew {
198 return nil
199 }
200
201 return &User{
202 Handle: clientSession.Values[appview.SessionHandle].(string),
203 Did: clientSession.Values[appview.SessionDid].(string),
204 Pds: clientSession.Values[appview.SessionPds].(string),
205 }
206}