1package storage
2
3import (
4 "context"
5 "database/sql"
6 "time"
7)
8
9func (s *Store) inAuditedTx(ctx context.Context, operation string, audits []AppendAuditInput, write func(tx *sql.Tx) error) error {
10 if err := s.checkOpen(operation); err != nil {
11 return err
12 }
13 tx, err := s.sql.BeginTx(ctx, nil)
14 if err != nil {
15 return classify("begin "+operation, err)
16 }
17 defer tx.Rollback()
18 if err := write(tx); err != nil {
19 return err
20 }
21 at := canonicalTime(s.now())
22 for _, audit := range audits {
23 if _, err := appendAudit(ctx, tx, operation+" audit", audit, at); err != nil {
24 return err
25 }
26 }
27 return classify("commit "+operation, tx.Commit())
28}
29
30func (s *Store) CreateForwardSessionAudited(ctx context.Context, input CreateForwardSessionInput, audits ...AppendAuditInput) (ForwardSession, error) {
31 var row ForwardSession
32 err := s.inAuditedTx(ctx, "create forward session", audits, func(tx *sql.Tx) error {
33 var err error
34 row, err = createForwardSession(ctx, tx, input)
35 return err
36 })
37 if err != nil {
38 return ForwardSession{}, err
39 }
40 return row, nil
41}
42
43func (s *Store) MarkReauthenticatedAudited(ctx context.Context, id string, at time.Time, audit AppendAuditInput) error {
44 return s.inAuditedTx(ctx, "mark forward session reauthenticated", []AppendAuditInput{audit}, func(tx *sql.Tx) error {
45 return markReauthenticated(ctx, tx, id, at)
46 })
47}
48
49func (s *Store) RecordLoginAudited(ctx context.Context, userID string, at time.Time, audit AppendAuditInput) error {
50 const operation = "record login"
51 return s.inAuditedTx(ctx, operation, []AppendAuditInput{audit}, func(tx *sql.Tx) error {
52 result, err := tx.ExecContext(ctx, `UPDATE users SET last_login_at = ? WHERE id = ?`, timeToInt(at), userID)
53 if err != nil {
54 return classify(operation, err)
55 }
56 return requireChanged(operation, result)
57 })
58}