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)
15
16type Auth struct {
17 s sessions.Store
18}
19
20func NewAuth(store sessions.Store) *Auth {
21 return &Auth{store}
22}
23
24func ResolveIdent(ctx context.Context, arg string) (*identity.Identity, error) {
25 id, err := syntax.ParseAtIdentifier(arg)
26 if err != nil {
27 return nil, err
28 }
29
30 dir := identity.DefaultDirectory()
31 return dir.Lookup(ctx, *id)
32}
33
34func (a *Auth) AuthorizedClient(r *http.Request) (*xrpc.Client, error) {
35 clientSession, err := a.s.Get(r, "bild-session")
36
37 if err != nil || clientSession.IsNew {
38 return nil, err
39 }
40
41 did := clientSession.Values["did"].(string)
42 pdsUrl := clientSession.Values["pds"].(string)
43 accessJwt := clientSession.Values["accessJwt"].(string)
44 refreshJwt := clientSession.Values["refreshJwt"].(string)
45
46 client := &xrpc.Client{
47 Host: pdsUrl,
48 Auth: &xrpc.AuthInfo{
49 AccessJwt: accessJwt,
50 RefreshJwt: refreshJwt,
51 Did: did,
52 },
53 }
54
55 return client, nil
56}
57
58func (a *Auth) CreateInitialSession(w http.ResponseWriter, r *http.Request, username, appPassword string) (AtSessionCreate, error) {
59 ctx := r.Context()
60 resolved, err := ResolveIdent(ctx, username)
61 if err != nil {
62 return AtSessionCreate{}, fmt.Errorf("invalid handle: %s", err)
63 }
64
65 pdsUrl := resolved.PDSEndpoint()
66 client := xrpc.Client{
67 Host: pdsUrl,
68 }
69
70 atSession, err := comatproto.ServerCreateSession(ctx, &client, &comatproto.ServerCreateSession_Input{
71 Identifier: resolved.DID.String(),
72 Password: appPassword,
73 })
74 if err != nil {
75 return AtSessionCreate{}, fmt.Errorf("invalid app password")
76 }
77
78 return AtSessionCreate{
79 ServerCreateSession_Output: *atSession,
80 PDSEndpoint: pdsUrl,
81 }, nil
82}
83
84func (a *Auth) StoreSession(r *http.Request, w http.ResponseWriter, atSessionCreate *AtSessionCreate, atSessionRefresh *AtSessionRefresh) error {
85 if atSessionCreate != nil {
86 atSession := atSessionCreate
87
88 clientSession, _ := a.s.Get(r, "bild-session")
89 clientSession.Values["handle"] = atSession.Handle
90 clientSession.Values["did"] = atSession.Did
91 clientSession.Values["accessJwt"] = atSession.AccessJwt
92 clientSession.Values["refreshJwt"] = atSession.RefreshJwt
93 clientSession.Values["expiry"] = time.Now().Add(time.Hour).String()
94 clientSession.Values["pds"] = atSession.PDSEndpoint
95 clientSession.Values["authenticated"] = true
96
97 return clientSession.Save(r, w)
98 } else {
99 atSession := atSessionRefresh
100
101 clientSession, _ := a.s.Get(r, "bild-session")
102 clientSession.Values["handle"] = atSession.Handle
103 clientSession.Values["did"] = atSession.Did
104 clientSession.Values["accessJwt"] = atSession.AccessJwt
105 clientSession.Values["refreshJwt"] = atSession.RefreshJwt
106 clientSession.Values["expiry"] = time.Now().Add(time.Hour).String()
107 clientSession.Values["pds"] = atSession.PDSEndpoint
108 clientSession.Values["authenticated"] = true
109
110 return clientSession.Save(r, w)
111 }
112}
113
114func (a *Auth) GetSessionUser(r *http.Request) (*identity.Identity, error) {
115 session, _ := a.s.Get(r, "bild-session")
116 did, ok := session.Values["did"].(string)
117 if !ok {
118 return nil, fmt.Errorf("user is not authenticated")
119 }
120
121 return ResolveIdent(r.Context(), did)
122}