1 package database
2
3 import (
4 "context"
5 "crypto/rand"
6 "encoding/base64"
7 "log"
8 "time"
9
10 . "codeberg.org/tslocum/sriracha/model"
11 "github.com/jackc/pgx/v5"
12 )
13
14 func (db *DB) AddCAPTCHA(c *CAPTCHA) {
15 _, err := db.conn.Exec(context.Background(), "INSERT INTO captcha VALUES ($1, $2, $3, $4, $5)",
16 c.IP,
17 c.Timestamp,
18 c.Refresh,
19 c.Image,
20 c.Text,
21 )
22 if err != nil {
23 log.Fatalf("failed to insert captcha: %s", err)
24 }
25 }
26
27 func (db *DB) GetCAPTCHA(ip string) *CAPTCHA {
28 c := &CAPTCHA{}
29 err := scanCAPTCHA(c, db.conn.QueryRow(context.Background(), "SELECT * FROM captcha WHERE ip = $1", ip))
30 if err == pgx.ErrNoRows {
31 return nil
32 } else if err != nil {
33 log.Fatalf("failed to select captcha: %s", err)
34 }
35 return c
36 }
37
38 func (db *DB) UpdateCAPTCHA(c *CAPTCHA) {
39 _, err := db.conn.Exec(context.Background(), "UPDATE captcha SET refresh = $1, image = $2, text = $3 WHERE ip = $4", c.Refresh, c.Image, c.Text, c.IP)
40 if err != nil {
41 log.Fatal(err)
42 }
43 }
44
45 func (db *DB) ExpiredCAPTCHAs() []*CAPTCHA {
46 const oneDay = 60 * 60 * 24
47 rows, err := db.conn.Query(context.Background(), "SELECT * FROM captcha WHERE timestamp <= $1", time.Now().Unix()-oneDay)
48 if err != nil {
49 log.Fatalf("failed to select expired captchas: %s", err)
50 }
51 var captchas []*CAPTCHA
52 for rows.Next() {
53 c := &CAPTCHA{}
54 err := scanCAPTCHA(c, rows)
55 if err != nil {
56 log.Fatalf("failed to select expired captchas: %s", err)
57 }
58 captchas = append(captchas, c)
59 }
60 return captchas
61 }
62
63 func (db *DB) DeleteCAPTCHA(ip string) {
64 if ip == "" {
65 return
66 }
67
68 _, err := db.conn.Exec(context.Background(), "DELETE FROM captcha WHERE ip = $1", ip)
69 if err != nil {
70 log.Fatalf("failed to delete captcha: %s", err)
71 }
72 }
73
74 func (db *DB) NewCAPTCHAImage() string {
75 const keyLength = 48
76 buf := make([]byte, keyLength)
77 for {
78 _, err := rand.Read(buf)
79 if err != nil {
80 panic(err)
81 }
82 imageName := base64.URLEncoding.EncodeToString(buf)
83
84 var count int
85 err = db.conn.QueryRow(context.Background(), "SELECT COUNT(*) FROM captcha WHERE image = $1", imageName).Scan(&count)
86 if err != nil {
87 log.Fatalf("failed to select number of accounts with session key: %s", err)
88 } else if count == 0 {
89 return imageName
90 }
91 }
92 }
93
94 func scanCAPTCHA(c *CAPTCHA, row pgx.Row) error {
95 return row.Scan(
96 &c.IP,
97 &c.Timestamp,
98 &c.Refresh,
99 &c.Image,
100 &c.Text,
101 )
102 }
103
View as plain text