206 lines
5.0 kB
1
package auth
2
3
import (
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
16
type Auth struct {
17
Store *sessions.CookieStore
18
}
19
20
type AtSessionCreate struct {
21
comatproto.ServerCreateSession_Output
22
PDSEndpoint string
23
}
24
25
type AtSessionRefresh struct {
26
comatproto.ServerRefreshSession_Output
27
PDSEndpoint string
28
}
29
30
func Make() (*Auth, error) {
31
store := sessions.NewCookieStore([]byte(appview.SessionCookieSecret))
32
return &Auth{store}, nil
33
}
34
35
func (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.
54
type 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
65
type RefreshSessionWrapper struct {
66
*comatproto.ServerRefreshSession_Output
67
}
68
69
func (s *RefreshSessionWrapper) GetAccessJwt() string {
70
return s.AccessJwt
71
}
72
73
func (s *RefreshSessionWrapper) GetActive() *bool {
74
return s.Active
75
}
76
77
func (s *RefreshSessionWrapper) GetDid() string {
78
return s.Did
79
}
80
81
func (s *RefreshSessionWrapper) GetDidDoc() *interface{} {
82
return s.DidDoc
83
}
84
85
func (s *RefreshSessionWrapper) GetHandle() string {
86
return s.Handle
87
}
88
89
func (s *RefreshSessionWrapper) GetRefreshJwt() string {
90
return s.RefreshJwt
91
}
92
93
func (s *RefreshSessionWrapper) GetStatus() *string {
94
return s.Status
95
}
96
97
// Create a wrapper type for ServerRefreshSession_Output
98
type CreateSessionWrapper struct {
99
*comatproto.ServerCreateSession_Output
100
}
101
102
func (s *CreateSessionWrapper) GetAccessJwt() string {
103
return s.AccessJwt
104
}
105
106
func (s *CreateSessionWrapper) GetActive() *bool {
107
return s.Active
108
}
109
110
func (s *CreateSessionWrapper) GetDid() string {
111
return s.Did
112
}
113
114
func (s *CreateSessionWrapper) GetDidDoc() *interface{} {
115
return s.DidDoc
116
}
117
118
func (s *CreateSessionWrapper) GetHandle() string {
119
return s.Handle
120
}
121
122
func (s *CreateSessionWrapper) GetRefreshJwt() string {
123
return s.RefreshJwt
124
}
125
126
func (s *CreateSessionWrapper) GetStatus() *string {
127
return s.Status
128
}
129
130
func (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
142
func (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
166
func (a *Auth) GetSession(r *http.Request) (*sessions.Session, error) {
167
return a.Store.Get(r, appview.SessionName)
168
}
169
170
func (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
179
func (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
188
type User struct {
189
Handle string
190
Did string
191
Pds string
192
}
193
194
func (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
}
207