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