server: tie regex filters to db_insert_ban
[rb-79.git] / config.def.h
blobed136c387d3e0d49e97c345fb713bf261280c044
1 /*
2 * Configure your site here
3 */
5 /*
6 * Where is the directory full of static files that we'll be
7 * modifying? (absolute path to a folder, please)
8 */
9 static const char *static_www_folder = "/var/www/rb79";
12 * So, we have to have databases and lockfiles and stuff. Where
13 * do they go? Probably somewhere far away from network access, and
14 * regularly backed-up, I'd guess. (absolute path to a folder,
15 * please)
17 static const char *work_path = "/opt/rb79";
20 * When we convert files (stripping EXIF out of jpegs, etc.) they
21 * go to a temporary directory, which is created through mkdtemp.
22 * What is the template for that directory name? It should end in
23 * "XXXXXX", and it should be somewhere that isn't automatically
24 * destroyed (e.g. by a cleanup cronjob).
26 static const char *temp_dir_template = "/tmp/rb79_conv_XXXXXX";
29 * The boards: each name should just be a folder inside static_www_folder.
30 * You should probably avoid names starting with underscores since
31 * I reserve those names to put templates and stuff in.
33 static const struct board boards[] = {
34 /* */
35 { .name = "m", .title = "Mecha", /* */
36 .text_cooldown = 40, .blank_cooldown = 20, /* */
37 .threads_per_page = 10, .num_pages = 20, /* */
38 .appears_in_recent = 1 }, /* */
39 { .name = "b", .title = "Random", /* */
40 .text_cooldown = 20, .blank_cooldown = 10, /* */
41 .threads_per_page = 10, .num_pages = 10, /* */
42 .appears_in_recent = 0 }, /* */
43 { .name = "sf", .title = "General SF", /* */
44 .text_cooldown = 40, .blank_cooldown = 20, /* */
45 .threads_per_page = 10, .num_pages = 20, /* */
46 .appears_in_recent = 1 }, /* */
50 * What's the tripcode salt?
52 static const char *trip_salt =
53 "The color of television, tuned to a dead channel";
56 * Here are some error messages. They will be fed into fprintf, so
57 * they are kept as #defines so that the compiler can provide some
58 * surety against misuse.
62 * Here's the generic HTTP 400 template. For things like using the
63 * wrong method, uploading a file with the wrong mime type, etc.
64 * This should be a format suitable for feeding to printf with
65 * EXACTLY one %s, which is a brief explanation of the problem.
67 #define BAD_REQUEST_FMT \
68 "Status: 400\r\n" \
69 "Content-type: text/html\r\n\r\n" \
70 "<!DOCTYPE html>" \
71 "<html>" \
72 "<head>" \
73 "<meta http-equiv=\"Content-Type\" content=\"text/html; " \
74 "charset=utf-8\" />" \
75 "<title>Kiteo. His eyes closed.</title>" \
76 "<link rel=\"stylesheet\" type=\"text/css\" " \
77 "href=\"/css/futaba.css\" />" \
78 "<link rel=\"icon\" type=\"image/png\" href=\"/icon.png\" />" \
79 "</head>" \
80 "<body>" \
81 "<div class=\"center-wrapper\">" \
82 "<div class=\"notice-box\">" \
83 "<p class=\"notice-title\">Malformed request</p>" \
84 "<p>%s</p>" \
85 "</div>" \
86 "</div>" \
87 "</body>" \
88 "</html>\n"
91 * And here's the ban message template. This time there should be
92 * EXACTLY TWO %s format specifier. The first one gives ban reason,
93 * the second gives ban expiry. If you want to reorder them, you
94 * can use %2$s and %1$s.
96 #define BAN_FMT \
97 "Status: 403\r\n" \
98 "Content-type: text/html\r\n\r\n" \
99 "<!DOCTYPE html>" \
100 "<html>" \
101 "<head>" \
102 "<meta http-equiv=\"Content-Type\" content=\"text/html; " \
103 "charset=utf-8\" />" \
104 "<title>\u515c\u7532\u5150\u3001\u30de\u30b0\u30de\u306b" \
105 "\u6b7b\u3059!</title>" \
106 "<link rel=\"stylesheet\" type=\"text/css\" " \
107 "href=\"/css/futaba.css\" />" \
108 "<link rel=\"icon\" type=\"image/png\" href=\"/icon.png\" />" \
109 "</head>" \
110 "<body>" \
111 "<div class=\"center-wrapper\">" \
112 "<div class=\"notice-box\">" \
113 "<p class=\"notice-title\">You are banned! Σ(゚Д゚ )</p>" \
114 "<ul><li>Expiry: %s</li>" \
115 "<li>Reason: %s</li></ul>" \
116 "</div>" \
117 "</div>" \
118 "</body>" \
119 "</html>\n"
122 * Here's what they get if they fail a challenge (see below). No %s at all.
124 #define BAD_CHALLENGE_FMT \
125 "Status: 403\r\n" \
126 "Content-type: text/html\r\n\r\n" \
127 "<!DOCTYPE html>" \
128 "<html>" \
129 "<head>" \
130 "<meta http-equiv=\"Content-Type\" content=\"text/html; " \
131 "charset=utf-8\" />" \
132 "<title>(It's not “swordfish”)</title>" \
133 "<link rel=\"stylesheet\" type=\"text/css\" " \
134 "href=\"/css/futaba.css\" />" \
135 "<link rel=\"icon\" type=\"image/png\" href=\"/icon.png\" />" \
136 "</head>" \
137 "<body>" \
138 "<div class=\"center-wrapper\">" \
139 "<div class=\"notice-box\">" \
140 "<p class=\"notice-title\">You gotta answer the challenge!</p>" \
141 "<p>It's for your own good, you know.</p>" \
142 "</div>" \
143 "</div>" \
144 "</body>" \
145 "</html>\n"
148 * Here's what they get if they use the wrong HTTP method on /action.
149 * No %s at all.
151 #define BAD_METHOD_FMT \
152 "Status: 405\r\n" \
153 "Content-type: text/html\r\n\r\n" \
154 "<!DOCTYPE html>" \
155 "<html>" \
156 "<head>" \
157 "<meta http-equiv=\"Content-Type\" content=\"text/html; " \
158 "charset=utf-8\" />" \
159 "<title>This is highly unorthodox</title>" \
160 "<link rel=\"stylesheet\" type=\"text/css\" " \
161 "href=\"/css/futaba.css\" />" \
162 "<link rel=\"icon\" type=\"image/png\" href=\"/icon.png\" />" \
163 "</head>" \
164 "<body>" \
165 "<div class=\"center-wrapper\">" \
166 "<div class=\"notice-box\">" \
167 "<p class=\"notice-title\">That wasn't a POST</p>" \
168 "<p>We only take POSTs here.</p>" \
169 "</div>" \
170 "</div>" \
171 "</body>" \
172 "</html>\n"
175 * Upload was large enough for the server to accept it, but overflowed
176 * some other bound. This should be a template suitable for feeding
177 * into printf, with EXACTLY one %s, which will be something like
178 * "file" or "subject" or "comment".
180 #define TOO_LARGE_FMT \
181 "Status: 413\r\n" \
182 "Content-type: text/html\r\n\r\n" \
183 "<!DOCTYPE html>" \
184 "<html>" \
185 "<head>" \
186 "<meta http-equiv=\"Content-Type\" content=\"text/html; " \
187 "charset=utf-8\" />" \
188 "<title>Once the Big Zam is uploaded...</title>" \
189 "<link rel=\"stylesheet\" type=\"text/css\" " \
190 "href=\"/css/futaba.css\" />" \
191 "<link rel=\"icon\" type=\"image/png\" href=\"/icon.png\" />" \
192 "</head>" \
193 "<body>" \
194 "<div class=\"center-wrapper\">" \
195 "<div class=\"notice-box\">" \
196 "<p class=\"notice-title\">Too large!</p>" \
197 "<p>%s too large.</p>" \
198 "</div>" \
199 "</div>" \
200 "</body>" \
201 "</html>\n"
204 * User is posting when they've posted too recently. This should
205 * be a template suitable for feeding into printf, with EXACTLY one
206 * %s, which will be replaced with something like "25 seconds".
208 #define COOLDOWN_FMT \
209 "Status: 429\r\n" \
210 "Content-type: text/html\r\n\r\n" \
211 "<!DOCTYPE html>" \
212 "<html>" \
213 "<head>" \
214 "<meta http-equiv=\"Content-Type\" content=\"text/html; " \
215 "charset=utf-8\" />" \
216 "<title>This sensation, is it Char!?</title>" \
217 "<link rel=\"stylesheet\" type=\"text/css\" " \
218 "href=\"/css/futaba.css\" />" \
219 "<link rel=\"icon\" type=\"image/png\" href=\"/icon.png\" />" \
220 "</head>" \
221 "<body>" \
222 "<div class=\"center-wrapper\">" \
223 "<div class=\"notice-box\">" \
224 "<p class=\"notice-title\">Slow down!</p>" \
225 "<p>You're posting too fast! Try again in %s.</p>" \
226 "</div>" \
227 "</div>" \
228 "</body>" \
229 "</html>\n"
232 * Some kind of server error occured: out of memory, invalid UTF-8
233 * generated, somewhere, etc. Apologize profusely.
235 #define INTERNAL_ERROR_FMT \
236 "Status: 500\r\n" \
237 "Content-type: text/html\r\n\r\n" \
238 "<!DOCTYPE html>" \
239 "<html>" \
240 "<head>" \
241 "<meta http-equiv=\"Content-Type\" content=\"text/html; " \
242 "charset=utf-8\" />" \
243 "<title>Bitter failure</title>" \
244 "<link rel=\"stylesheet\" type=\"text/css\" " \
245 "href=\"/css/futaba.css\" />" \
246 "<link rel=\"icon\" type=\"image/png\" href=\"/icon.png\" />" \
247 "</head>" \
248 "<body>" \
249 "<div class=\"center-wrapper\">" \
250 "<div class=\"notice-box\">" \
251 "<p class=\"notice-title\">Internal error</p>" \
252 "<p>Please accept our apologies. " \
253 "Something unexpected has happened.</p>" \
254 "</div>" \
255 "</div>" \
256 "</body>" \
257 "</html>\n"
260 * Here's the "Post successful" screen. There's one %s, which is
261 * the page to redirect back to.
263 #define POST_SUCCESSFUL_FMT \
264 "Status: 200\r\n" \
265 "Content-type: text/html\r\n\r\n" \
266 "<!DOCTYPE html>" \
267 "<html>" \
268 "<head>" \
269 "<meta http-equiv=\"Content-Type\" content=\"text/html; " \
270 "charset=utf-8\" />" \
271 "<meta http-equiv=\"refresh\" content=\"3;URL='%s'\" />" \
272 "<title>\u9280\u6cb3\u306e\u6b74\u53f2\u304c\u307e\u305f1\u30da" \
273 "\u30fc\u30b8</title>" \
274 "<link rel=\"stylesheet\" type=\"text/css\" " \
275 "href=\"/css/futaba.css\" />" \
276 "<link rel=\"icon\" type=\"image/png\" href=\"/icon.png\" />" \
277 "</head>" \
278 "<body>" \
279 "<div class=\"center-wrapper\">" \
280 "<div class=\"notice-box\">" \
281 "<p class=\"notice-title\">Post successful</p>" \
282 "<p>Returning you in 3\u20262\u20261\u2026</p>" \
283 "</div>" \
284 "</div>" \
285 "</body>" \
286 "</html>\n"
289 * How large of a multipart/form-data (in bytes) should we listen
290 * to before throwing 413? This should be a bit larger than the
291 * max file size, but not large enough to cause DoS by malloc().
293 * This is separate from any upper limit configured in the web
294 * server. The web server's limit should be well above this value.
296 static const size_t max_form_data_size = (5 * (1 << 20));
299 * How large of a file (in bytes) should we accept?
301 static const size_t max_file_size = (4 * (1 << 20));
304 * How long of a comment (in bytes) should we accept?
306 static const size_t max_text_len = (3 << 10);
309 * What mimetypes are allowed? Which ones should be thumbnailed (by
310 * what external command?), and which ones should simply have a
311 * fixed thumbnail (and where is it on the server?)
313 * This is handled by libmagic(3), in case you're wondering about
314 * that. We don't trust the Content-Type of the upload (but we do
315 * trust libmagic, and we trust libmagic to trust things... ugh).
317 * Please note that all format strings should take two arguments
318 * (%s). The first is the source, the latter is destination. If
319 * they need to be used multiple times, %1$s and %2$s will work.
321 static const struct filetype filetypes[] = {
322 /* */
323 { .mime_type = "image/jpeg", /* */
324 .ext = "jpg", /* */
325 .install_command = "jhead -purejpg %1$s >/dev/null" /* */
326 " 2>/dev/null && cp %1$s %2$s", /* */
327 .thumb_creation_command = "convert %s -thumbnail" /* */
328 " 150x150 %s" }, /* */
329 { .mime_type = "image/gif", /* */
330 .ext = "gif", /* */
331 .install_command = "mv %s %s", /* */
332 .thumb_creation_command = "convert %s[0] -thumbnail" /* */
333 " 150x150 %s" }, /* */
334 { .mime_type = "image/png", /* */
335 .ext = "png", /* */
336 .install_command = "mv %s %s", /* */
337 .thumb_creation_command = "convert %s -thumbnail" /* */
338 " 150x150 %s" }, /* */
339 { .mime_type = "video/webm", /* */
340 .ext = "webm", /* */
341 .install_command = "ffmpeg -y -i %s -an -c:v copy %s" /* */
342 " >/dev/null 2>/dev/null", /* */
343 .thumb_creation_command =
344 "ffmpeg -y -i %s -c:v mjpeg -ss 0 -vframes 1" /* */
345 " -an -vf scale=w=150:h=150:force_original" /* */
346 "_aspect_ratio=decrease -f rawvideo %s" /* */
347 " >/dev/null 2>/dev/null" }, /* */
348 { .mime_type = "application/epub+zip", /* */
349 .ext = "epub", .install_command = "mv %s %s", /* */
350 .static_thumbnail = "/_icons/book.jpg" },
354 * Information about a file should be displayed: something like
355 * "webm, 201KB, 00:36". Where is the program which prints this
356 * information?
358 * The script will be passed two arguments. The first is the mimetype
359 * of the file, a string like "image/jpeg" or "application/epub+zip".
360 * The second will be an absolute path to the file itself.
362 * A decent starting point is located at tools/describe-file.sh of
363 * the source repository. The Makefile installs this to something
364 * like /usr/bin/rb79-describe-file, so that's what the default
365 * configuration uses.
367 static const char *file_description_prog = "/usr/bin/rb79-describe-file";
369 /* A list of all possible header images, randomly selected from */
370 static const char *headers[] = {
371 /* */
372 "/_banners/1.png", /* */
373 "/_banners/2.png", /* */
374 "/_banners/3.png", /* */
375 "/_banners/4.png", /* */
379 * Spambot traps (you can give up to 5 answers for each question,
380 * case insensitive)
382 static const struct challenge challenges[] = {
383 /* */
384 { .question = "<img src=\"/_hints/1.png\" alt=\"B__L\" />" /* */
385 "What is the more common name of the RB-79?", /* */
386 .answers = { "ball", 0 } }, /* */
387 { .question = "<img src=\"/_hints/2.png\" alt=\"H___\" />" /* */
388 " Which spherical toy did Amuro build?", /* */
389 .answers = { "haro", "ball", 0 } }, /* */
390 { .question = "<img src=\"/_hints/3.png\" " /* */
391 "alt=\"Is______\"/> Where did the Fifth " /* */
392 "Battle of Iserlohn happen? ", /* */
393 .answers = { "iserlohn", 0 } }, /* */
394 { .question = "<img src=\"/_hints/4.png\" " /* */
395 "alt=\"J______\"/> Which planet is the " /* */
396 "source of all evil? ", /* */
397 .answers = { "jupiter", 0 } }, /* */
398 { .question = "<img src=\"/_hints/5.png\" " /* */
399 "alt=\"B_s____l\"/> What is Sisko's " /* */
400 "favorite sport?", /* */
401 .answers = { "baseball", 0 } },
405 * What are the wordfilters? pattern will be compiled by pcre2 with
406 * only the UTF compatible option, replace will be what the whole
407 * match gets replaced with.
409 * If you want case-insensitive, put (?i) at the start. If you want
410 * fancy backreferences, send a patch. If you want to replace with
411 * unicode, use \u1234 (this happens before HTML-escaping). If you
412 * want to use this to implement [spoiler], please don't.
414 static const struct wordfilter_input wordfilter_inputs[] = {
415 /* */
416 { .pattern = "(?i)nina purpleton", .replacement = "worst girl" },
417 { .pattern = "(?i)\\bkes\\b", .replacement = "Quess" },
418 { .pattern = "(?i)\\bquess\\b", .replacement = "Kes" },
419 { .pattern = "(?i).*?\\b(smh|fam|tbh|succ|thicc)\\b.*",
420 .replacement = "( \u0361\u00b0 \u035c\u0296 \u0361\u00b0)" },
424 * What are some phrases that can't be posted? As with wordfilters,
425 * pattern will be compiled with pcre2, only with the UTF compatible
426 * option. ban_duration is (if non-zero) the amount of time they'll be
427 * banned for, with reason ban_reason (secret if empty)
429 static const struct forbidden_input forbidden_inputs[] = {
430 /* */
431 { .pattern = "Actually [Ss][Ee][Ee][Dd] Destiny was good",
432 .ban_duration = 43200, .ban_reason = "I disagree" },
433 { .pattern = "dick pills", .ban_duration = 31536000,
434 .ban_reason = 0 },