internal/store/pushtokens.go
52 lines · 1514 bytes
5 symbols in this file
1package store
2
3import (
4 "database/sql"
5 "errors"
6 "time"
7)
8
9// PushToken is the receive-pack a hook request speaks for.
10type PushToken struct {
11 RepoID int64
12 UserID int64
13 Scope string
14}
15
16// pushTokenTTL bounds a row whose receive-pack died before deleting it.
17const pushTokenTTL = 24 * time.Hour
18
19// CreatePushToken records a token for one receive-pack and returns it.
20func (s *Store) CreatePushToken(repoID, userID int64, scope string) (string, error) {
21 token, hash, err := NewToken()
22 if err != nil {
23 return "", err
24 }
25 _, err = s.DB.Exec(
26 "INSERT INTO push_tokens (token_hash, repo_id, user_id, scope, expires_at) VALUES (?, ?, ?, ?, ?)",
27 hash, repoID, userID, scope, fmtTime(time.Now().Add(pushTokenTTL)))
28 if err != nil {
29 return "", err
30 }
31 return token, nil
32}
33
34// PushTokenByHash looks up a live token by its stored hash. ErrNotFound
35// covers both an absent row and one that has expired.
36func (s *Store) PushTokenByHash(hash string) (PushToken, error) {
37 var t PushToken
38 err := s.DB.QueryRow(
39 "SELECT repo_id, user_id, scope FROM push_tokens WHERE token_hash = ? AND expires_at > ?",
40 hash, fmtTime(time.Now())).Scan(&t.RepoID, &t.UserID, &t.Scope)
41 if errors.Is(err, sql.ErrNoRows) {
42 return PushToken{}, ErrNotFound
43 }
44 return t, err
45}
46
47// DeletePushToken removes a token by its raw value, once its receive-pack
48// is done with it.
49func (s *Store) DeletePushToken(token string) error {
50 _, err := s.DB.Exec("DELETE FROM push_tokens WHERE token_hash = ?", HashToken(token))
51 return err
52}