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/whyrusleeping/go-did"
15)
16
17type Auth struct {
18 store sessions.Store
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("TODO_CHANGE_ME"))
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, username, appPassword string) (*comatproto.ServerCreateSession_Output, error) {
47 resolved, err := ResolveIdent(ctx, username)
48 if err != nil {
49 return nil, fmt.Errorf("invalid handle: %s", err)
50 }
51
52 pdsUrl := resolved.PDSEndpoint()
53 client := xrpc.Client{
54 Host: pdsUrl,
55 }
56
57 atSession, err := comatproto.ServerCreateSession(ctx, &client, &comatproto.ServerCreateSession_Input{
58 Identifier: resolved.DID.String(),
59 Password: appPassword,
60 })
61 if err != nil {
62 return nil, fmt.Errorf("invalid app password")
63 }
64
65 return atSession, nil
66}
67
68func (a *Auth) StoreSession(r *http.Request, w http.ResponseWriter, atSession *comatproto.ServerCreateSession_Output) error {
69 didDoc, ok := (*atSession.DidDoc).(did.Document)
70 if !ok {
71 return fmt.Errorf("invalid did document for session")
72 }
73
74 pdsEndpoint := getPdsEndpoint(&didDoc)
75
76 if pdsEndpoint == "" {
77 return fmt.Errorf("no pds endpoint found")
78 }
79
80 clientSession, _ := a.store.Get(r, "appview-session")
81 clientSession.Values["handle"] = atSession.Handle
82 clientSession.Values["did"] = atSession.Did
83 clientSession.Values["pds"] = pdsEndpoint
84 clientSession.Values["accessJwt"] = atSession.AccessJwt
85 clientSession.Values["refreshJwt"] = atSession.RefreshJwt
86 clientSession.Values["expiry"] = time.Now().Add(time.Hour).String()
87 clientSession.Values["authenticated"] = true
88
89 return clientSession.Save(r, w)
90}
91
92func getPdsEndpoint(didDoc *did.Document) string {
93 fullId := didDoc.ID.String()
94 id := "#atproto_pds"
95 type_ := "AtprotoPersonalDataServer"
96
97 for _, service := range didDoc.Service {
98 serviceId := service.ID.String()
99 if serviceId == id || serviceId == fullId+id || service.Type == type_ {
100 return service.ServiceEndpoint
101 }
102 }
103
104 return ""
105}