mercury/internal/database/token.go

86 lines
2 KiB
Go

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
}