Add CSRF tokens

This commit is contained in:
2025-08-17 18:59:13 +02:00
parent e67eb4175b
commit 2ee58c2b0a
35 changed files with 10241 additions and 10128 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ else
LFLAGS = LFLAGS =
endif endif
CFLAGS = -Wall -Wextra -O0 -g3 -I3p CFLAGS = -Wall -Wextra -O0 -g3 -I3p -fsanitize=address,undefined
HFILES = $(shell find src 3p -name "*.h") HFILES = $(shell find src 3p -name "*.h")
CFILES = $(filter-out 3p/sqlite3.c, $(shell find src 3p -name "*.c")) CFILES = $(filter-out 3p/sqlite3.c, $(shell find src 3p -name "*.c"))
+2 -3
View File
@@ -1,5 +1,4 @@
bcrypt passwords
session management using proper random tokens
CSRF protection
input validation to avoid XSS and injection input validation to avoid XSS and injection
only allow signup, login ecc over HTTPS only allow signup, login ecc over HTTPS
session expiration
mark cookies as secure
+2
View File
@@ -59,6 +59,8 @@ let style =
let main = let main =
<main> <main>
<form action="/api/post" method="POST"> <form action="/api/post" method="POST">
<input type="hidden" name="csrf" value=\'"'\$csrf\'"' />
<input type="text" id="title" name="title" placeholder="Title" required /> <input type="text" id="title" name="title" placeholder="Title" required />
<div class="checkbox-row"> <div class="checkbox-row">
+52 -160
View File
@@ -9,6 +9,7 @@
#include "sqlite3.h" #include "sqlite3.h"
#include "sqlite3utils.h" #include "sqlite3utils.h"
#include "template.h" #include "template.h"
#include "session.h"
#define WL_STR(X) ((WL_String) { (X), (int) sizeof(X)-1}) #define WL_STR(X) ((WL_String) { (X), (int) sizeof(X)-1})
@@ -313,134 +314,8 @@ int http_getparami(HTTP_String body, HTTP_String str, WL_Arena *arena)
return buf; return buf;
} }
#define SESSION_LIMIT 1024
#define USERNAME_LIMIT 64 #define USERNAME_LIMIT 64
#define RAW_SESSION_TOKEN_SIZE 32
#define RAW_CSRF_TOKEN_SIZE 32
#define SESSION_TOKEN_SIZE (2 * RAW_SESSION_TOKEN_SIZE)
#define CSRF_TOKEN_SIZE (2 * RAW_CSRF_TOKEN_SIZE)
typedef struct {
int user_id;
char raw_sess_token[RAW_SESSION_TOKEN_SIZE];
char raw_csrf_token[RAW_CSRF_TOKEN_SIZE];
} Session;
typedef struct {
Session sessions[SESSION_LIMIT];
int count;
} SessionSet;
#include "random.h"
void session_set_init(SessionSet *set)
{
set->count = 0;
}
typedef struct {
char data[SESSION_TOKEN_SIZE];
} SessionToken;
typedef struct {
char data[CSRF_TOKEN_SIZE];
} CSRFToken;
static void unpack_token(char *src, int srclen, char *dst, int dstlen)
{
assert(srclen == 2 * dstlen);
for (int i = 0; i < srclen; i++) {
static const char table[] = "0123456789abcdef";
int low = (src[i] & 0x0F) >> 0;
int high = (src[i] & 0xF0) >> 4;
dst[(i << 1) | 0] = table[high];
dst[(i << 1) | 1] = table[low];
}
}
static int pack_token(char *src, int srclen, char *dst, int dstlen)
{
if (srclen & 1)
return -1;
assert(2 * srclen == dstlen);
for (int i = 0; i < srclen; i += 2) {
int high = src[i+0];
int low = src[i+1];
if (!is_hex_digit(high) || !is_hex_digit(low))
return -1;
dst[i] = (hex_digit_to_int(high) << 4) | (hex_digit_to_int(low) << 0);
}
return 0;
}
int session_set_add(SessionSet *set, int user_id, SessionToken *sess_token, CSRFToken *csrf_token)
{
if (set->count == SESSION_LIMIT)
return -1;
Session *session = &set->sessions[set->count];
int ret;
ret = generate_random_bytes(session->raw_sess_token, (int) sizeof(session->raw_sess_token));
if (ret) return -1;
ret = generate_random_bytes(session->raw_csrf_token, (int) sizeof(session->raw_csrf_token));
if (ret) return -1;
session->user_id = user_id;
unpack_token(
session->raw_csrf_token, (int) sizeof(session->raw_csrf_token),
csrf_token->data, (int) sizeof(csrf_token->data)
);
unpack_token(
session->raw_sess_token, (int) sizeof(session->raw_sess_token),
sess_token->data, (int) sizeof(sess_token->data)
);
set->count++;
return 0;
}
void session_set_remove(SessionSet *set, SessionToken sess_token)
{
char raw_sess_token[RAW_SESSION_TOKEN_SIZE];
pack_token(
sess_token.data, (int) sizeof(sess_token.data),
raw_sess_token, (int) sizeof(raw_sess_token)
);
int i = 0;
while (i < set->count && memcmp(set->sessions[i].raw_sess_token, raw_sess_token, RAW_SESSION_TOKEN_SIZE))
i++;
if (i == set->count)
return;
set->sessions[i] = set->sessions[--set->count];
}
int session_set_find(SessionSet *set, SessionToken sess_token)
{
char raw_sess_token[RAW_SESSION_TOKEN_SIZE];
pack_token(
sess_token.data, (int) sizeof(sess_token.data),
raw_sess_token, (int) sizeof(raw_sess_token)
);
int i = 0;
while (i < set->count && memcmp(set->sessions[i].raw_sess_token, raw_sess_token, RAW_SESSION_TOKEN_SIZE))
i++;
if (i == set->count)
return -1;
return set->sessions[i].user_id;
}
bool valid_name(HTTP_String str) bool valid_name(HTTP_String str)
{ {
(void) str; // TODO (void) str; // TODO
@@ -529,8 +404,10 @@ int main(void)
int pool_cap = 1<<20; int pool_cap = 1<<20;
char *pool = malloc(pool_cap); char *pool = malloc(pool_cap);
SessionSet sessions; SessionStorage *session_storage = session_storage_init(1024);
session_set_init(&sessions); if (session_storage == NULL) {
return -1;
}
for (;;) { for (;;) {
@@ -542,22 +419,17 @@ int main(void)
WL_Arena arena = { pool, pool_cap, 0 }; WL_Arena arena = { pool, pool_cap, 0 };
//printf("%.*s\n", req->raw.len, req->raw.ptr); // TODO printf("%.*s\n", req->raw.len, req->raw.ptr); // TODO
// If logged in, these are set to non-negative values int user_id;
SessionToken sess_token; HTTP_String sess;
int user_id = -1; HTTP_String csrf;
{ sess = http_getcookie(req, HTTP_STR("sess_token"));
HTTP_String str = http_getcookie(req, HTTP_STR("sess_id")); if (find_session(session_storage, sess, &csrf, &user_id) < 0) {
if (str.len == SESSION_TOKEN_SIZE) { user_id = -1;
char tmp[RAW_SESSION_TOKEN_SIZE]; sess = (HTTP_String) { NULL, 0 };
int ret = pack_token(str.ptr, str.len, tmp, (int) sizeof(tmp)); csrf = (HTTP_String) { NULL, 0 };
if (ret) {
memcpy(sess_token.data, str.ptr, str.len);
user_id = session_set_find(&sessions, sess_token);
}
}
} }
HTTP_String path = req->url.path; HTTP_String path = req->url.path;
@@ -617,9 +489,9 @@ int main(void)
} }
int user_id = ret; int user_id = ret;
CSRFToken csrf_token; HTTP_String sess;
SessionToken sess_token; HTTP_String csrf;
if (session_set_add(&sessions, user_id, &sess_token, &csrf_token) < 0) { if (create_session(session_storage, user_id, &sess, &csrf) < 0) {
http_response_builder_status(builder, 200); http_response_builder_status(builder, 200);
http_response_builder_body(builder, HTML_STR(( http_response_builder_body(builder, HTML_STR((
<div class="error"> <div class="error">
@@ -630,8 +502,9 @@ int main(void)
continue; continue;
} }
// TODO: set cookie as secure
char cookie[1<<9]; char cookie[1<<9];
int cookie_len = snprintf(cookie, sizeof(cookie), "Set-Cookie: sess_id=%.*s; Path=/; HttpOnly", (int) sizeof(sess_token.data)-1, sess_token.data); int cookie_len = snprintf(cookie, sizeof(cookie), "Set-Cookie: sess_token=%.*s; Path=/; HttpOnly", sess.len, sess.ptr);
if (cookie_len < 0 || cookie_len >= (int) sizeof(cookie)) { if (cookie_len < 0 || cookie_len >= (int) sizeof(cookie)) {
http_response_builder_status(builder, 200); http_response_builder_status(builder, 200);
http_response_builder_body(builder, HTML_STR(( http_response_builder_body(builder, HTML_STR((
@@ -719,9 +592,9 @@ int main(void)
} }
user_id = ret; user_id = ret;
CSRFToken csrf_token; HTTP_String sess;
SessionToken sess_token; HTTP_String csrf;
if (session_set_add(&sessions, user_id, &sess_token, &csrf_token) < 0) { if (create_session(session_storage, user_id, &sess, &csrf) < 0) {
http_response_builder_status(builder, 200); http_response_builder_status(builder, 200);
http_response_builder_body(builder, HTML_STR(( http_response_builder_body(builder, HTML_STR((
<div class="error"> <div class="error">
@@ -732,8 +605,9 @@ int main(void)
continue; continue;
} }
// TODO: set cookie as secure
char cookie[1<<9]; char cookie[1<<9];
int cookie_len = snprintf(cookie, sizeof(cookie), "Set-Cookie: sess_id=%.*s; Path=/; HttpOnly", (int) sizeof(sess_token.data)-1, sess_token.data); int cookie_len = snprintf(cookie, sizeof(cookie), "Set-Cookie: sess_token=%.*s; Path=/; HttpOnly", sess.len, sess.ptr);
if (cookie_len < 0 || cookie_len >= (int) sizeof(cookie)) { if (cookie_len < 0 || cookie_len >= (int) sizeof(cookie)) {
http_response_builder_status(builder, 200); http_response_builder_status(builder, 200);
http_response_builder_body(builder, HTML_STR(( http_response_builder_body(builder, HTML_STR((
@@ -758,10 +632,11 @@ int main(void)
} else if (http_streq(path, HTTP_STR("/api/logout"))) { } else if (http_streq(path, HTTP_STR("/api/logout"))) {
if (user_id != -1) if (user_id != -1)
session_set_remove(&sessions, sess_token); delete_session(session_storage, sess);
// TODO: set cookie as secure
http_response_builder_status(builder, 303); // TODO: Whats the correct code here? http_response_builder_status(builder, 303); // TODO: Whats the correct code here?
http_response_builder_header(builder, HTTP_STR("Set-Cookie: sess_id=; Path=/; HttpOnly")); http_response_builder_header(builder, HTTP_STR("Set-Cookie: sess_token=; Path=/; HttpOnly"));
http_response_builder_header(builder, HTTP_STR("Location: /index")); http_response_builder_header(builder, HTTP_STR("Location: /index"));
http_response_builder_done(builder); http_response_builder_done(builder);
@@ -783,11 +658,19 @@ int main(void)
HTTP_String title = http_getparam(req->body, HTTP_STR("title"), &arena); HTTP_String title = http_getparam(req->body, HTTP_STR("title"), &arena);
HTTP_String link = http_getparam(req->body, HTTP_STR("link"), &arena); HTTP_String link = http_getparam(req->body, HTTP_STR("link"), &arena);
HTTP_String content = http_getparam(req->body, HTTP_STR("content"), &arena); HTTP_String content = http_getparam(req->body, HTTP_STR("content"), &arena);
HTTP_String csrf2 = http_getparam(req->body, HTTP_STR("csrf"), &arena);
title = http_trim(title); title = http_trim(title);
link = http_trim(link); link = http_trim(link);
content = http_trim(content); content = http_trim(content);
if (!http_streq(csrf, csrf2)) {
http_response_builder_status(builder, 400);
http_response_builder_body(builder, HTTP_STR("Invalid request"));
http_response_builder_done(builder);
continue;
}
if (!valid_post_title(title)) { if (!valid_post_title(title)) {
http_response_builder_status(builder, 200); http_response_builder_status(builder, 200);
http_response_builder_body(builder, HTML_STR(( http_response_builder_body(builder, HTML_STR((
@@ -923,6 +806,14 @@ int main(void)
int parent_post = http_getparami(req->body, HTTP_STR("parent_post"), &arena); int parent_post = http_getparami(req->body, HTTP_STR("parent_post"), &arena);
int parent_comment = http_getparami(req->body, HTTP_STR("parent_comment"), &arena); int parent_comment = http_getparami(req->body, HTTP_STR("parent_comment"), &arena);
HTTP_String content = http_getparam (req->body, HTTP_STR("content"), &arena); HTTP_String content = http_getparam (req->body, HTTP_STR("content"), &arena);
HTTP_String csrf2 = http_getparam(req->body, HTTP_STR("csrf"), &arena);
if (!http_streq(csrf, csrf2)) {
http_response_builder_status(builder, 200);
http_response_builder_body(builder, HTTP_STR("Invalid request"));
http_response_builder_done(builder);
continue;
}
content = http_trim(content); content = http_trim(content);
if (!valid_comment_content(content)) { if (!valid_comment_content(content)) {
@@ -997,7 +888,7 @@ int main(void)
} else if (http_streq(path, HTTP_STR("/index"))) { } else if (http_streq(path, HTTP_STR("/index"))) {
template_eval(builder, 200, WL_STR("pages/index.wl"), tpcache, &arena, dbcache, user_id, -1); template_eval(builder, 200, WL_STR("pages/index.wl"), tpcache, &arena, dbcache, csrf, user_id, -1);
} else if (http_streq(path, HTTP_STR("/write"))) { } else if (http_streq(path, HTTP_STR("/write"))) {
@@ -1009,7 +900,7 @@ int main(void)
continue; continue;
} }
template_eval(builder, 200, WL_STR("pages/write.wl"), tpcache, &arena, dbcache, user_id, -1); template_eval(builder, 200, WL_STR("pages/write.wl"), tpcache, &arena, dbcache, csrf, user_id, -1);
} else if (http_streq(path, HTTP_STR("/login"))) { } else if (http_streq(path, HTTP_STR("/login"))) {
@@ -1021,7 +912,7 @@ int main(void)
continue; continue;
} }
template_eval(builder, 200, WL_STR("pages/login.wl"), tpcache, &arena, dbcache, user_id, -1); template_eval(builder, 200, WL_STR("pages/login.wl"), tpcache, &arena, dbcache, csrf, user_id, -1);
} else if (http_streq(path, HTTP_STR("/signup"))) { } else if (http_streq(path, HTTP_STR("/signup"))) {
@@ -1033,13 +924,13 @@ int main(void)
continue; continue;
} }
template_eval(builder, 200, WL_STR("pages/signup.wl"), tpcache, &arena, dbcache, user_id, -1); template_eval(builder, 200, WL_STR("pages/signup.wl"), tpcache, &arena, dbcache, csrf, user_id, -1);
} else if (http_streq(path, HTTP_STR("/post"))) { } else if (http_streq(path, HTTP_STR("/post"))) {
int post_id = http_getparami(req->url.query, HTTP_STR("id"), &arena); int post_id = http_getparami(req->url.query, HTTP_STR("id"), &arena);
if (post_id < 0) { if (post_id < 0) {
template_eval(builder, 404, WL_STR("pages/notfound.wl"), tpcache, &arena, dbcache, user_id, -1); template_eval(builder, 404, WL_STR("pages/notfound.wl"), tpcache, &arena, dbcache, csrf, user_id, -1);
continue; continue;
} }
@@ -1074,18 +965,19 @@ int main(void)
} }
if (num == 0) { if (num == 0) {
template_eval(builder, 404, WL_STR("pages/notfound.wl"), tpcache, &arena, dbcache, user_id, -1); template_eval(builder, 404, WL_STR("pages/notfound.wl"), tpcache, &arena, dbcache, csrf, user_id, -1);
continue; continue;
} }
template_eval(builder, 200, WL_STR("pages/post.wl"), tpcache, &arena, dbcache, user_id, post_id); template_eval(builder, 200, WL_STR("pages/post.wl"), tpcache, &arena, dbcache, csrf, user_id, post_id);
} else { } else {
template_eval(builder, 404, WL_STR("pages/notfound.wl"), tpcache, &arena, dbcache, user_id, -1); template_eval(builder, 404, WL_STR("pages/notfound.wl"), tpcache, &arena, dbcache, csrf, user_id, -1);
} }
} }
session_storage_free(session_storage);
sqlite_cache_free(dbcache); sqlite_cache_free(dbcache);
template_cache_free(tpcache); template_cache_free(tpcache);
sqlite3_close(db); sqlite3_close(db);
+198
View File
@@ -0,0 +1,198 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "random.h"
#include "session.h"
#define CSRF_RAW_TOKEN_SIZE 32
#define SESS_RAW_TOKEN_SIZE 32
#define CSRF_TOKEN_SIZE (2 * CSRF_RAW_TOKEN_SIZE)
#define SESS_TOKEN_SIZE (2 * SESS_RAW_TOKEN_SIZE)
typedef struct {
int user;
char csrf[CSRF_TOKEN_SIZE];
char sess[SESS_TOKEN_SIZE];
} Session;
struct SessionStorage {
int count;
int capacity;
Session items[];
};
static bool is_hex_digit(char c)
{
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
}
static int hex_digit_to_int(char c)
{
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
return c - '0';
}
static void unpack_token(char *src, int srclen, char *dst, int dstlen)
{
assert(2 * srclen == dstlen);
for (int i = 0; i < srclen; i++) {
static const char table[] = "0123456789abcdef";
int low = (src[i] & 0x0F) >> 0;
int high = (src[i] & 0xF0) >> 4;
dst[(i << 1) | 0] = table[high];
dst[(i << 1) | 1] = table[low];
}
}
static int pack_token(char *src, int srclen, char *dst, int dstlen)
{
if (srclen & 1)
return -1;
assert(srclen == 2 * dstlen);
for (int i = 0; i < srclen; i += 2) {
int high = src[i+0];
int low = src[i+1];
if (!is_hex_digit(high) || !is_hex_digit(low))
return -1;
dst[i] = (hex_digit_to_int(high) << 4) | (hex_digit_to_int(low) << 0);
}
return 0;
}
SessionStorage *session_storage_init(int max_sessions)
{
int capacity = 2 * max_sessions;
SessionStorage *storage = malloc(sizeof(SessionStorage) + capacity * sizeof(Session));
if (storage == NULL)
return NULL;
storage->count = 0;
storage->capacity = capacity;
for (int i = 0; i < capacity; i++)
storage->items[i].user = -1;
return storage;
}
void session_storage_free(SessionStorage *storage)
{
free(storage);
}
#include <stdio.h> // TODO
static Session *lookup_session_slot(SessionStorage *storage, HTTP_String sess, bool find_unused)
{
if (find_unused && 2 * storage->count + 2 > storage->capacity)
return NULL;
if (sess.len != SESS_TOKEN_SIZE)
return NULL;
uint64_t key;
if (sess.len < (int) (2 * sizeof(key)))
return NULL;
for (int i = 0; i < (int) sizeof(key); i++) {
int high = sess.ptr[(i << 1) | 0];
int low = sess.ptr[(i << 1) | 1];
if (!is_hex_digit(sess.ptr[i+0]) ||
!is_hex_digit(sess.ptr[i+1]))
return NULL;
key <<= 4;
key |= hex_digit_to_int(high);
key <<= 4;
key |= hex_digit_to_int(low);
}
int i = key % storage->capacity;
for (int j = 0; j < storage->capacity; j++) {
if (find_unused) {
if (storage->items[i].user < 0)
return &storage->items[i]; // Unused slot
} else {
if (storage->items[i].user == -1)
return NULL;
if (storage->items[i].user != -2)
if (!memcmp(storage->items[i].sess, sess.ptr, SESS_TOKEN_SIZE))
return &storage->items[i];
}
i++;
if (i == storage->capacity)
i = 0;
}
return NULL;
}
int create_session(SessionStorage *storage, int user, HTTP_String *psess, HTTP_String *pcsrf)
{
int ret;
char raw_sess[SESS_RAW_TOKEN_SIZE];
char raw_csrf[CSRF_RAW_TOKEN_SIZE];
ret = generate_random_bytes(raw_sess, SESS_RAW_TOKEN_SIZE);
if (ret) return -1;
ret = generate_random_bytes(raw_csrf, CSRF_RAW_TOKEN_SIZE);
if (ret) return -1;
char sess[SESS_TOKEN_SIZE];
char csrf[CSRF_TOKEN_SIZE];
unpack_token(raw_sess, SESS_RAW_TOKEN_SIZE, sess, SESS_TOKEN_SIZE);
unpack_token(raw_csrf, CSRF_RAW_TOKEN_SIZE, csrf, CSRF_TOKEN_SIZE);
Session *found = lookup_session_slot(storage, (HTTP_String) { sess, SESS_TOKEN_SIZE }, true);
if (found == NULL) return -1;
found->user = user;
memcpy(found->sess, sess, SESS_TOKEN_SIZE);
memcpy(found->csrf, csrf, CSRF_TOKEN_SIZE);
*psess = (HTTP_String) { found->sess, SESS_TOKEN_SIZE };
*pcsrf = (HTTP_String) { found->csrf, CSRF_TOKEN_SIZE };
storage->count++;
return 0;
}
int delete_session(SessionStorage *storage, HTTP_String sess)
{
char raw_sess[SESS_RAW_TOKEN_SIZE];
if (sess.len != SESS_TOKEN_SIZE || pack_token(sess.ptr, sess.len, raw_sess, (int) sizeof(raw_sess)) < 0)
return -1;
Session *found = lookup_session_slot(storage, sess, false);
if (found == NULL)
return false;
assert(found->user >= 0);
found->user = -2;
storage->count--;
return 0;
}
int find_session(SessionStorage *storage, HTTP_String sess, HTTP_String *pcsrf, int *puser)
{
Session *found = lookup_session_slot(storage, sess, false);
if (found == NULL)
return -1;
assert(found->user >= 0);
*pcsrf = (HTTP_String) { found->csrf, CSRF_TOKEN_SIZE };
*puser = found->user;
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef SESSION_INCLUDED
#define SESSION_INCLUDED
#include <chttp.h> // Only for HTTP_String
typedef struct SessionStorage SessionStorage;
SessionStorage *session_storage_init(int max_sessions);
void session_storage_free(SessionStorage *storage);
int create_session(SessionStorage *storage, int user, HTTP_String *psess, HTTP_String *pcsrf);
int delete_session(SessionStorage *storage, HTTP_String sess);
int find_session(SessionStorage *storage, HTTP_String sess, HTTP_String *pcsrf, int *puser);
#endif // SESSION_INCLUDED
+10 -3
View File
@@ -293,7 +293,7 @@ static int query_routine(WL_Runtime *rt, SQLiteCache *dbcache)
return 0; return 0;
} }
static void push_sysvar(WL_Runtime *rt, WL_String name, SQLiteCache *dbcache, int user_id, int post_id) static void push_sysvar(WL_Runtime *rt, WL_String name, SQLiteCache *dbcache, HTTP_String csrf, int user_id, int post_id)
{ {
(void) dbcache; (void) dbcache;
@@ -310,6 +310,13 @@ static void push_sysvar(WL_Runtime *rt, WL_String name, SQLiteCache *dbcache, in
wl_push_none(rt); wl_push_none(rt);
else else
wl_push_s64(rt, post_id); wl_push_s64(rt, post_id);
} else if (wl_streq(name, "csrf", -1)) {
if (csrf.len == 0)
wl_push_none(rt);
else
wl_push_str(rt, (WL_String) { csrf.ptr, csrf.len });
} }
} }
@@ -353,7 +360,7 @@ static int get_or_create_program(TemplateCache *cache, WL_String path, WL_Arena
void template_eval(HTTP_ResponseBuilder builder, int status, void template_eval(HTTP_ResponseBuilder builder, int status,
WL_String path, TemplateCache *cache, WL_Arena *arena, WL_String path, TemplateCache *cache, WL_Arena *arena,
SQLiteCache *dbcache, int user_id, int post_id) SQLiteCache *dbcache, HTTP_String csrf, int user_id, int post_id)
{ {
http_response_builder_status(builder, status); http_response_builder_status(builder, status);
@@ -394,7 +401,7 @@ void template_eval(HTTP_ResponseBuilder builder, int status,
return; return;
case WL_EVAL_SYSVAR: case WL_EVAL_SYSVAR:
push_sysvar(rt, result.str, dbcache, user_id, post_id); push_sysvar(rt, result.str, dbcache, csrf, user_id, post_id);
break; break;
case WL_EVAL_SYSCALL: case WL_EVAL_SYSCALL:
+1 -1
View File
@@ -11,6 +11,6 @@ void template_cache_free(TemplateCache *cache);
void template_eval(HTTP_ResponseBuilder builder, int status, void template_eval(HTTP_ResponseBuilder builder, int status,
WL_String path, TemplateCache *cache, WL_Arena *arena, WL_String path, TemplateCache *cache, WL_Arena *arena,
SQLiteCache *dbcache, int user_id, int post_id); SQLiteCache *dbcache, HTTP_String csrf, int user_id, int post_id);
#endif // TEMPLATE_INCLUDED #endif // TEMPLATE_INCLUDED