package database import ( "time" "github.com/golang-jwt/jwt/v4" "github.com/oklog/ulid/v2" ) const InternalApplicationName = "mercury_internal" const TokenCookieName = "mercury_token" type Application struct { ID ulid.ULID Name string } type Token struct { ID ulid.ULID AppID ulid.ULID UserID ulid.ULID Scopes TokenScopes Expires time.Time } func (t Token) ToClaims() TokenClaims { createdAt := ulid.Time(t.ID.Time()) return TokenClaims{ TokenID: t.ID, UserID: t.UserID, RegisteredClaims: jwt.RegisteredClaims{ Issuer: "mercury", ExpiresAt: jwt.NewNumericDate(t.Expires), IssuedAt: jwt.NewNumericDate(createdAt), NotBefore: jwt.NewNumericDate(createdAt), }, } } type TokenClaims struct { TokenID ulid.ULID `json:"jti"` UserID ulid.ULID `json:"sub"` jwt.RegisteredClaims } type TokenScope string const ( // All scopes below TokenScopeAll TokenScope = "all" TokenScopeAccountsRead TokenScope = "accounts.read" // Controls whether tokens have access to sensitive account data, NOT if they can use `/accounts/@me` endpoints. TokenScopeAccountsMe TokenScope = "accounts.me" TokenScopeAccountsWrite TokenScope = "accounts.write" TokenScopeBlogsRead TokenScope = "blogs.read" TokenScopeBlogsWrite TokenScope = "blogs.write" TokenScopePostsRead TokenScope = "posts.read" TokenScopePostsWrite TokenScope = "posts.write" TokenScopeTimeline TokenScope = "timeline" TokenScopeStreaming TokenScope = "streaming" ) func (s TokenScope) IsValid() bool { switch s { case TokenScopeAccountsRead, TokenScopeAccountsMe, TokenScopeAccountsWrite, TokenScopeBlogsRead, TokenScopeBlogsWrite, TokenScopePostsRead, TokenScopePostsWrite, TokenScopeTimeline, TokenScopeStreaming: return true default: return false } } type TokenScopes []TokenScope func (s TokenScopes) Has(scope TokenScope) bool { for i := range s { if s[i] == scope || s[i] == TokenScopeAll { return true } } return false }