...
1 package server
2
3 import (
4 "fmt"
5 "image/color"
6 "log"
7 "net/http"
8 "os"
9 "path/filepath"
10 "strings"
11 "time"
12
13 "codeberg.org/tslocum/sriracha/internal/database"
14 . "codeberg.org/tslocum/sriracha/model"
15 . "codeberg.org/tslocum/sriracha/util"
16 "github.com/steambap/captcha"
17 )
18
19 var captchaPalette = []color.Color{
20 color.RGBA{0, 0, 0, 255},
21 }
22
23 func (s *Server) serveCAPTCHA(db *database.DB, w http.ResponseWriter, r *http.Request) {
24 const (
25 width, height = 225, 40
26 characters = "ABCDHKMNSTUVWXYZ"
27 refreshLimit = 3
28 )
29
30 ipHash := s.hashIP(r)
31
32 c := db.GetCAPTCHA(ipHash)
33 if c != nil {
34 queryValues := r.URL.Query()
35 if len(queryValues["new"]) == 0 || c.Refresh >= refreshLimit {
36 http.Redirect(w, r, fmt.Sprintf("/captcha/%s.png", c.Image), http.StatusFound)
37 return
38 }
39 }
40
41 challenge, err := captcha.New(width, height, func(options *captcha.Options) {
42 options.CharPreset = characters
43 options.TextLength = 5
44 options.Noise = 1
45 options.CurveNumber = 3
46 options.Palette = captchaPalette
47 options.BackgroundColor = color.Transparent
48 })
49 if err != nil {
50 log.Fatal(err)
51 }
52
53 var oldImage string
54 if c == nil {
55 c = &CAPTCHA{
56 IP: ipHash,
57 Timestamp: time.Now().Unix(),
58 }
59 } else {
60 oldImage = c.Image
61 c.Refresh++
62 }
63
64 c.Image = db.NewCAPTCHAImage()
65 c.Text = strings.ToLower(challenge.Text)
66
67 f, err := os.OpenFile(filepath.Join(s.config.Root, "captcha", c.Image+".png"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, NewFilePermission)
68 if err != nil {
69 log.Fatal(err)
70 }
71 challenge.WriteImage(f)
72 f.Close()
73
74 if oldImage != "" {
75 os.Remove(filepath.Join(s.config.Root, "captcha", oldImage+".png"))
76 }
77
78 if oldImage == "" {
79 db.AddCAPTCHA(c)
80 } else {
81 db.UpdateCAPTCHA(c)
82 }
83
84 http.Redirect(w, r, fmt.Sprintf("/captcha/%s.png", c.Image), http.StatusFound)
85 }
86
View as plain text