internal/store/revoke.go

e2a32d5f8d59e4213571c602bd9009b6c8fa86ed
gitbay/internal/store/revoke.go history · blame · raw

60 lines · 1545 bytes

 1package store
 2
 3import (
 4	"slices"
 5	"strings"
 6)
 7
 8// Revoked names SSH keys that stopped being valid: by id, or every key
 9// of an account. The SSH listener closes the connections they opened.
10type Revoked struct {
11	KeyIDs []int64
12	UserID int64 // every key of this account; 0 for none
13}
14
15// OnRevoke registers f to run after each revocation this process
16// commits. Revocations committed by another process (gitbayd admin on
17// the host) are not announced; the listener's sweep finds those.
18func (s *Store) OnRevoke(f func(Revoked)) {
19	s.revokeMu.Lock()
20	defer s.revokeMu.Unlock()
21	s.onRevoke = append(s.onRevoke, f)
22}
23
24// announce runs the subscribers. Call it after the commit, outside any
25// transaction.
26func (s *Store) announce(r Revoked) {
27	s.revokeMu.Lock()
28	fs := slices.Clone(s.onRevoke)
29	s.revokeMu.Unlock()
30	for _, f := range fs {
31		f(r)
32	}
33}
34
35// LiveSSHKeys reports which of ids still name a registered key on an
36// account that is not disabled.
37func (s *Store) LiveSSHKeys(ids []int64) (map[int64]bool, error) {
38	live := map[int64]bool{}
39	if len(ids) == 0 {
40		return live, nil
41	}
42	args := make([]any, len(ids))
43	for i, id := range ids {
44		args[i] = id
45	}
46	rows, err := s.DB.Query(`SELECT k.id FROM ssh_keys k JOIN users u ON u.id = k.user_id
47		WHERE u.disabled = 0 AND k.id IN (?`+strings.Repeat(", ?", len(ids)-1)+`)`, args...)
48	if err != nil {
49		return nil, err
50	}
51	defer rows.Close()
52	for rows.Next() {
53		var id int64
54		if err := rows.Scan(&id); err != nil {
55			return nil, err
56		}
57		live[id] = true
58	}
59	return live, rows.Err()
60}