1package backend
2
3import (
4 "context"
5 "errors"
6 "time"
7
8 "github.com/charmbracelet/soft-serve/pkg/db"
9 "github.com/charmbracelet/soft-serve/pkg/proto"
10 "github.com/charmbracelet/soft-serve/pkg/utils"
11)
12
13// CreateAccessToken creates an access token for user.
14func (b *Backend) CreateAccessToken(ctx context.Context, user proto.User, name string, expiresAt time.Time) (string, error) {
15 token := GenerateToken()
16 tokenHash := HashToken(token)
17 name = utils.Sanitize(name)
18
19 if err := b.db.TransactionContext(ctx, func(tx *db.Tx) error {
20 _, err := b.store.CreateAccessToken(ctx, tx, name, user.ID(), tokenHash, expiresAt)
21 if err != nil {
22 return db.WrapError(err)
23 }
24
25 return nil
26 }); err != nil {
27 return "", err
28 }
29
30 return token, nil
31}
32
33// DeleteAccessToken deletes an access token for a user.
34func (b *Backend) DeleteAccessToken(ctx context.Context, user proto.User, id int64) error {
35 err := b.db.TransactionContext(ctx, func(tx *db.Tx) error {
36 _, err := b.store.GetAccessToken(ctx, tx, id)
37 if err != nil {
38 return db.WrapError(err)
39 }
40
41 if err := b.store.DeleteAccessTokenForUser(ctx, tx, user.ID(), id); err != nil {
42 return db.WrapError(err)
43 }
44 return nil
45 })
46 if err != nil {
47 if errors.Is(err, db.ErrRecordNotFound) {
48 return proto.ErrTokenNotFound
49 }
50 return err
51 }
52
53 return nil
54}
55
56// ListAccessTokens lists access tokens for a user.
57func (b *Backend) ListAccessTokens(ctx context.Context, user proto.User) ([]proto.AccessToken, error) {
58 accessTokens, err := b.store.GetAccessTokensByUserID(ctx, b.db, user.ID())
59 if err != nil {
60 return nil, db.WrapError(err)
61 }
62
63 var tokens []proto.AccessToken
64 for _, t := range accessTokens {
65 token := proto.AccessToken{
66 ID: t.ID,
67 Name: t.Name,
68 TokenHash: t.Token,
69 UserID: t.UserID,
70 CreatedAt: t.CreatedAt,
71 }
72 if t.ExpiresAt.Valid {
73 token.ExpiresAt = t.ExpiresAt.Time
74 }
75
76 tokens = append(tokens, token)
77 }
78
79 return tokens, nil
80}