An atproto PDS written in Go

fix listing of active oauth sessions

Changed files
+48 -12
oauth
server
+32
oauth/helpers.go
··· 4 4 "errors" 5 5 "fmt" 6 6 "net/url" 7 + "time" 7 8 8 9 "github.com/haileyok/cocoon/internal/helpers" 9 10 "github.com/haileyok/cocoon/oauth/constants" 11 + "github.com/haileyok/cocoon/oauth/provider" 10 12 ) 11 13 12 14 func GenerateCode() string { ··· 46 48 47 49 return reqId, nil 48 50 } 51 + 52 + type SessionAgeResult struct { 53 + SessionAge time.Duration 54 + RefreshAge time.Duration 55 + SessionExpired bool 56 + RefreshExpired bool 57 + } 58 + 59 + func GetSessionAgeFromToken(t provider.OauthToken) SessionAgeResult { 60 + sessionLifetime := constants.PublicClientSessionLifetime 61 + refreshLifetime := constants.PublicClientRefreshLifetime 62 + if t.ClientAuth.Method != "none" { 63 + sessionLifetime = constants.ConfidentialClientSessionLifetime 64 + refreshLifetime = constants.ConfidentialClientRefreshLifetime 65 + } 66 + 67 + res := SessionAgeResult{} 68 + 69 + res.SessionAge = time.Since(t.CreatedAt) 70 + if res.SessionAge > sessionLifetime { 71 + res.SessionExpired = true 72 + } 73 + 74 + refreshAge := time.Since(t.UpdatedAt) 75 + if refreshAge > refreshLifetime { 76 + res.RefreshExpired = true 77 + } 78 + 79 + return res 80 + }
+13 -2
server/handle_account.go
··· 3 3 import ( 4 4 "time" 5 5 6 + "github.com/haileyok/cocoon/oauth" 7 + "github.com/haileyok/cocoon/oauth/constants" 6 8 "github.com/haileyok/cocoon/oauth/provider" 7 9 "github.com/labstack/echo/v4" 8 10 ) ··· 13 15 return e.Redirect(303, "/account/signin") 14 16 } 15 17 16 - now := time.Now() 18 + oldestPossibleSession := time.Now().Add(constants.ConfidentialClientSessionLifetime) 17 19 18 20 var tokens []provider.OauthToken 19 - if err := s.db.Raw("SELECT * FROM oauth_tokens WHERE sub = ? AND expires_at >= ? ORDER BY created_at ASC", nil, repo.Repo.Did, now).Scan(&tokens).Error; err != nil { 21 + if err := s.db.Raw("SELECT * FROM oauth_tokens WHERE sub = ? AND created_at < ? ORDER BY created_at ASC", nil, repo.Repo.Did, oldestPossibleSession).Scan(&tokens).Error; err != nil { 20 22 s.logger.Error("couldnt fetch oauth sessions for account", "did", repo.Repo.Did, "error", err) 21 23 sess.AddFlash("Unable to fetch sessions. See server logs for more details.", "error") 22 24 sess.Save(e.Request(), e.Response()) 23 25 return e.Render(200, "account.html", map[string]any{ 24 26 "flashes": getFlashesFromSession(e, sess), 25 27 }) 28 + } 29 + 30 + var filtered []provider.OauthToken 31 + for _, t := range tokens { 32 + ageRes := oauth.GetSessionAgeFromToken(t) 33 + if ageRes.SessionExpired { 34 + continue 35 + } 36 + filtered = append(filtered, t) 26 37 } 27 38 28 39 tokenInfo := []map[string]string{}
+3 -10
server/handle_oauth_token.go
··· 203 203 return helpers.InputError(e, to.StringPtr("dpop proof does not match expected jkt")) 204 204 } 205 205 206 - sessionLifetime := constants.PublicClientSessionLifetime 207 - refreshLifetime := constants.PublicClientRefreshLifetime 208 - if clientAuth.Method != "none" { 209 - sessionLifetime = constants.ConfidentialClientSessionLifetime 210 - refreshLifetime = constants.ConfidentialClientRefreshLifetime 211 - } 206 + ageRes := oauth.GetSessionAgeFromToken(oauthToken) 212 207 213 - sessionAge := time.Since(oauthToken.CreatedAt) 214 - if sessionAge > sessionLifetime { 208 + if ageRes.SessionExpired { 215 209 return helpers.InputError(e, to.StringPtr("Session expired")) 216 210 } 217 211 218 - refreshAge := time.Since(oauthToken.UpdatedAt) 219 - if refreshAge > refreshLifetime { 212 + if ageRes.RefreshExpired { 220 213 return helpers.InputError(e, to.StringPtr("Refresh token expired")) 221 214 } 222 215