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