-217
appview/auth/auth.go
-217
appview/auth/auth.go
···
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
-
"tangled.sh/tangled.sh/core/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(secret string) (*Auth, error) {
31
-
store := sessions.NewCookieStore([]byte(secret))
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) ClearSession(r *http.Request, w http.ResponseWriter) error {
131
-
clientSession, err := a.Store.Get(r, appview.SessionName)
132
-
if err != nil {
133
-
return fmt.Errorf("invalid session", err)
134
-
}
135
-
if clientSession.IsNew {
136
-
return fmt.Errorf("invalid session")
137
-
}
138
-
clientSession.Options.MaxAge = -1
139
-
return clientSession.Save(r, w)
140
-
}
141
-
142
-
func (a *Auth) StoreSession(r *http.Request, w http.ResponseWriter, atSessionish Sessionish, pdsEndpoint string) error {
143
-
clientSession, _ := a.Store.Get(r, appview.SessionName)
144
-
clientSession.Values[appview.SessionHandle] = atSessionish.GetHandle()
145
-
clientSession.Values[appview.SessionDid] = atSessionish.GetDid()
146
-
clientSession.Values[appview.SessionPds] = pdsEndpoint
147
-
clientSession.Values[appview.SessionAccessJwt] = atSessionish.GetAccessJwt()
148
-
clientSession.Values[appview.SessionRefreshJwt] = atSessionish.GetRefreshJwt()
149
-
clientSession.Values[appview.SessionExpiry] = time.Now().Add(time.Minute * 15).Format(time.RFC3339)
150
-
clientSession.Values[appview.SessionAuthenticated] = true
151
-
return clientSession.Save(r, w)
152
-
}
153
-
154
-
func (a *Auth) AuthorizedClient(r *http.Request) (*xrpc.Client, error) {
155
-
clientSession, err := a.Store.Get(r, "appview-session")
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
-
177
-
func (a *Auth) GetSession(r *http.Request) (*sessions.Session, error) {
178
-
return a.Store.Get(r, appview.SessionName)
179
-
}
180
-
181
-
func (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
-
190
-
func (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
-
199
-
type User struct {
200
-
Handle string
201
-
Did string
202
-
Pds string
203
-
}
204
-
205
-
func (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
-
}
-8
appview/state/state.go
-8
appview/state/state.go
···
19
19
"github.com/go-chi/chi/v5"
20
20
"tangled.sh/tangled.sh/core/api/tangled"
21
21
"tangled.sh/tangled.sh/core/appview"
22
-
"tangled.sh/tangled.sh/core/appview/auth"
23
22
"tangled.sh/tangled.sh/core/appview/db"
24
23
"tangled.sh/tangled.sh/core/appview/oauth"
25
24
"tangled.sh/tangled.sh/core/appview/pages"
···
29
28
30
29
type State struct {
31
30
db *db.DB
32
-
auth *auth.Auth
33
31
oauth *oauth.OAuth
34
32
enforcer *rbac.Enforcer
35
33
tidClock syntax.TIDClock
···
41
39
42
40
func Make(config *appview.Config) (*State, error) {
43
41
d, err := db.Make(config.Core.DbPath)
44
-
if err != nil {
45
-
return nil, err
46
-
}
47
-
48
-
auth, err := auth.Make(config.Core.CookieSecret)
49
42
if err != nil {
50
43
return nil, err
51
44
}
···
89
82
90
83
state := &State{
91
84
d,
92
-
auth,
93
85
oauth,
94
86
enforcer,
95
87
clock,