@@ -0,0 +1,51 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"gardomatic.kleiax.de/internal/auth"
|
||||
)
|
||||
|
||||
// TokenModel stores scoped authentication token hashes in PostgreSQL.
|
||||
// TokenModel persists only token hashes; plaintext tokens are returned once to
|
||||
// the caller and never stored.
|
||||
type TokenModel struct {
|
||||
DB *sql.DB
|
||||
}
|
||||
|
||||
// New creates a token and persists only its hash.
|
||||
func (m TokenModel) New(userID int, ttl time.Duration, scope string) (auth.Token, error) {
|
||||
token := auth.NewToken(userID, ttl, scope)
|
||||
|
||||
err := m.insert(token)
|
||||
return token, err
|
||||
}
|
||||
|
||||
func (m TokenModel) insert(token auth.Token) error {
|
||||
query := `
|
||||
INSERT INTO tokens (hash, user_id, expiry, scope)
|
||||
VALUES ($1, $2, $3, $4)`
|
||||
|
||||
args := []any{token.Hash, token.UserID, token.Expiry, token.Scope}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
_, err := m.DB.ExecContext(ctx, query, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteAllForUser revokes every token for one user and scope.
|
||||
func (m TokenModel) DeleteAllForUser(scope string, userID int) error {
|
||||
query := `
|
||||
DELETE FROM tokens
|
||||
WHERE scope = $1 AND user_id = $2`
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
_, err := m.DB.ExecContext(ctx, query, scope, userID)
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user