1 package server
2
3 import (
4 "fmt"
5 "io"
6 "log"
7 "net/http"
8 "regexp"
9 "strings"
10
11 "codeberg.org/tslocum/sriracha/internal/database"
12 . "codeberg.org/tslocum/sriracha/model"
13 . "codeberg.org/tslocum/sriracha/util"
14 )
15
16 func (s *Server) loadBanForm(db *database.DB, r *http.Request, b *Ban) {
17 b.Expire = FormInt64(r, "expire")
18 b.Reason = FormString(r, "reason")
19 }
20
21 func (s *Server) serveBan(data *templateData, db *database.DB, w http.ResponseWriter, r *http.Request) {
22 data.Template = "manage_ban"
23 data.Boards = db.AllBoards()
24
25 deleteBanID := PathInt(r, "/sriracha/ban/delete/")
26 if deleteBanID > 0 {
27 if s.forbidden(w, data, "ban.delete") {
28 return
29 }
30 b := db.BanByID(deleteBanID)
31 if b == nil {
32 data.ManageError("Invalid ban.")
33 return
34 }
35 db.DeleteBan(b.ID)
36
37 if strings.HasPrefix(b.IP, "r ") {
38 s.reloadBans(db)
39 }
40
41 var changes string
42 liftReason := FormString(r, "reason")
43 if strings.TrimSpace(liftReason) != "" {
44 changes = "Reason: " + liftReason
45 }
46
47 s.log(db, data.Account, nil, fmt.Sprintf("Lifted ban #%d", b.ID), changes)
48
49 http.Redirect(w, r, "/sriracha/ban/", http.StatusFound)
50 return
51 }
52
53 banID := PathInt(r, "/sriracha/ban/")
54 if banID > 0 {
55 data.Manage.Ban = db.BanByID(banID)
56
57 if data.Manage.Ban != nil && r.Method == http.MethodPost {
58 oldBan := *data.Manage.Ban
59 s.loadBanForm(db, r, data.Manage.Ban)
60
61 shorter := data.Manage.Ban.Expire != 0 && (oldBan.Expire == 0 || data.Manage.Ban.Expire < oldBan.Expire)
62 if shorter && s.forbidden(w, data, "ban.shorten") {
63 return
64 } else if !shorter && s.forbidden(w, data, "ban.lengthen") {
65 return
66 }
67
68 err := data.Manage.Ban.Validate()
69 if err != nil {
70 data.ManageError(err.Error())
71 return
72 }
73
74 db.UpdateBan(data.Manage.Ban)
75
76 if strings.HasPrefix(data.Manage.Ban.IP, "r ") {
77 s.reloadBans(db)
78 }
79
80 changes := printChanges(oldBan, *data.Manage.Ban)
81 s.log(db, data.Account, nil, fmt.Sprintf("Updated >>/ban/%d", data.Manage.Ban.ID), changes)
82
83 http.Redirect(w, r, "/sriracha/ban/", http.StatusFound)
84 return
85 }
86 return
87 }
88
89 if r.Method == http.MethodPost {
90 r.ParseForm()
91 f, _, err := r.FormFile("liftfile")
92 if err == nil && f != nil {
93 if s.forbidden(w, data, "banfile.delete") {
94 return
95 }
96 buf, err := io.ReadAll(f)
97 if err != nil {
98 log.Fatal(err)
99 }
100 hash := calculateFileHash(buf)
101 if db.FileBanned(hash) {
102 db.LiftFileBan(hash)
103 data.Info = "Lifted file ban."
104 s.log(db, data.Account, nil, "Lifted file ban", "")
105 } else {
106 data.ManageError("File is not banned.")
107 }
108 return
109 } else if s.forbidden(w, data, "ban.add") {
110 return
111 }
112
113 b := &Ban{}
114 s.loadBanForm(db, r, b)
115
116 ip := FormString(r, "ip")
117 if strings.ContainsRune(ip, '*') {
118 pattern := strings.ReplaceAll(strings.ReplaceAll(ip, ".", `\.`), "*", ".*")
119 _, err := regexp.Compile(pattern)
120 if err != nil {
121 data.ManageError(fmt.Sprintf("failed to compile ban `%s` as regular expression: %s", pattern, err))
122 return
123 }
124 b.IP = "r " + pattern
125 } else if ip != "" {
126 b.IP = s._hashIP(ip)
127 }
128
129 err = b.Validate()
130 if err != nil {
131 data.ManageError(err.Error())
132 return
133 }
134
135 match := db.BanByIP(b.IP)
136 if match != nil {
137 data.ManageError("A ban for that IP address or range already exists.")
138 return
139 }
140
141 db.AddBan(b)
142
143 if strings.HasPrefix(b.IP, "r ") {
144 s.reloadBans(db)
145 }
146
147 s.log(db, data.Account, nil, fmt.Sprintf("Added >>/ban/%d", b.ID), b.Info())
148
149 http.Redirect(w, r, "/sriracha/ban/", http.StatusFound)
150 return
151 }
152
153 data.Manage.Bans = db.AllBans(false)
154 }
155
View as plain text