A vibe coded tangled fork which supports pijul.
at 2993b9e27c8ee399789340f6b1c393e2636e52a3 160 lines 3.6 kB view raw
1package oauth 2 3import ( 4 "encoding/json" 5 "errors" 6 "net/http" 7 "time" 8) 9 10const MaxAccounts = 20 11 12var ErrMaxAccountsReached = errors.New("maximum number of linked accounts reached") 13 14type AccountInfo struct { 15 Did string `json:"did"` 16 SessionId string `json:"session_id"` 17 AddedAt int64 `json:"added_at"` 18} 19 20type AccountRegistry struct { 21 Accounts []AccountInfo `json:"accounts"` 22} 23 24type MultiAccountUser struct { 25 Active User 26 Accounts []AccountInfo 27} 28 29func (m *MultiAccountUser) Did() string { 30 return m.Active.Did 31} 32 33func (o *OAuth) GetAccounts(r *http.Request) *AccountRegistry { 34 session, err := o.SessStore.Get(r, AccountsName) 35 if err != nil || session.IsNew { 36 return &AccountRegistry{Accounts: []AccountInfo{}} 37 } 38 39 data, ok := session.Values["accounts"].(string) 40 if !ok { 41 return &AccountRegistry{Accounts: []AccountInfo{}} 42 } 43 44 var registry AccountRegistry 45 if err := json.Unmarshal([]byte(data), &registry); err != nil { 46 return &AccountRegistry{Accounts: []AccountInfo{}} 47 } 48 49 return &registry 50} 51 52func (o *OAuth) saveAccounts(w http.ResponseWriter, r *http.Request, registry *AccountRegistry) error { 53 session, err := o.SessStore.Get(r, AccountsName) 54 if err != nil { 55 o.Logger.Warn("failed to decode existing accounts cookie, will create new", "err", err) 56 } 57 58 data, err := json.Marshal(registry) 59 if err != nil { 60 return err 61 } 62 63 session.Values["accounts"] = string(data) 64 session.Options.MaxAge = 60 * 60 * 24 * 365 65 session.Options.HttpOnly = true 66 session.Options.Secure = !o.Config.Core.Dev 67 session.Options.SameSite = http.SameSiteLaxMode 68 69 return session.Save(r, w) 70} 71 72func (r *AccountRegistry) AddAccount(did, handle, sessionId string) error { 73 for i, acc := range r.Accounts { 74 if acc.Did == did { 75 r.Accounts[i].SessionId = sessionId 76 return nil 77 } 78 } 79 80 if len(r.Accounts) >= MaxAccounts { 81 return ErrMaxAccountsReached 82 } 83 84 r.Accounts = append(r.Accounts, AccountInfo{ 85 Did: did, 86 SessionId: sessionId, 87 AddedAt: time.Now().Unix(), 88 }) 89 return nil 90} 91 92func (r *AccountRegistry) RemoveAccount(did string) { 93 filtered := make([]AccountInfo, 0, len(r.Accounts)) 94 for _, acc := range r.Accounts { 95 if acc.Did != did { 96 filtered = append(filtered, acc) 97 } 98 } 99 r.Accounts = filtered 100} 101 102func (r *AccountRegistry) FindAccount(did string) *AccountInfo { 103 for i := range r.Accounts { 104 if r.Accounts[i].Did == did { 105 return &r.Accounts[i] 106 } 107 } 108 return nil 109} 110 111func (o *OAuth) GetMultiAccountUser(r *http.Request) *MultiAccountUser { 112 sess, err := o.ResumeSession(r) 113 if err != nil { 114 return nil 115 } 116 117 registry := o.GetAccounts(r) 118 return &MultiAccountUser{ 119 Active: User{ 120 Did: sess.Data.AccountDID.String(), 121 }, 122 Accounts: registry.Accounts, 123 } 124} 125 126func (o *OAuth) SetAuthReturn(w http.ResponseWriter, r *http.Request, returnURL string) error { 127 session, err := o.SessStore.Get(r, AuthReturnName) 128 if err != nil { 129 return err 130 } 131 132 session.Values[AuthReturnURL] = returnURL 133 session.Options.MaxAge = 60 * 30 134 session.Options.HttpOnly = true 135 session.Options.Secure = !o.Config.Core.Dev 136 session.Options.SameSite = http.SameSiteLaxMode 137 138 return session.Save(r, w) 139} 140 141func (o *OAuth) GetAuthReturn(r *http.Request) string { 142 session, err := o.SessStore.Get(r, AuthReturnName) 143 if err != nil || session.IsNew { 144 return "" 145 } 146 147 returnURL, _ := session.Values[AuthReturnURL].(string) 148 149 return returnURL 150} 151 152func (o *OAuth) ClearAuthReturn(w http.ResponseWriter, r *http.Request) error { 153 session, err := o.SessStore.Get(r, AuthReturnName) 154 if err != nil { 155 return err 156 } 157 158 session.Options.MaxAge = -1 159 return session.Save(r, w) 160}