Add CSRF tokens
This commit is contained in:
@@ -6,7 +6,7 @@ else
|
||||
LFLAGS =
|
||||
endif
|
||||
|
||||
CFLAGS = -Wall -Wextra -O0 -g3 -I3p
|
||||
CFLAGS = -Wall -Wextra -O0 -g3 -I3p -fsanitize=address,undefined
|
||||
|
||||
HFILES = $(shell find src 3p -name "*.h")
|
||||
CFILES = $(filter-out 3p/sqlite3.c, $(shell find src 3p -name "*.c"))
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
bcrypt passwords
|
||||
session management using proper random tokens
|
||||
CSRF protection
|
||||
input validation to avoid XSS and injection
|
||||
only allow signup, login ecc over HTTPS
|
||||
session expiration
|
||||
mark cookies as secure
|
||||
@@ -59,6 +59,8 @@ let style =
|
||||
let main =
|
||||
<main>
|
||||
<form action="/api/post" method="POST">
|
||||
|
||||
<input type="hidden" name="csrf" value=\'"'\$csrf\'"' />
|
||||
<input type="text" id="title" name="title" placeholder="Title" required />
|
||||
|
||||
<div class="checkbox-row">
|
||||
|
||||
+52
-160
@@ -9,6 +9,7 @@
|
||||
#include "sqlite3.h"
|
||||
#include "sqlite3utils.h"
|
||||
#include "template.h"
|
||||
#include "session.h"
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
#define SESSION_LIMIT 1024
|
||||
#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)
|
||||
{
|
||||
(void) str; // TODO
|
||||
@@ -529,8 +404,10 @@ int main(void)
|
||||
int pool_cap = 1<<20;
|
||||
char *pool = malloc(pool_cap);
|
||||
|
||||
SessionSet sessions;
|
||||
session_set_init(&sessions);
|
||||
SessionStorage *session_storage = session_storage_init(1024);
|
||||
if (session_storage == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
||||
@@ -542,22 +419,17 @@ int main(void)
|
||||
|
||||
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
|
||||
SessionToken sess_token;
|
||||
int user_id = -1;
|
||||
int user_id;
|
||||
HTTP_String sess;
|
||||
HTTP_String csrf;
|
||||
|
||||
{
|
||||
HTTP_String str = http_getcookie(req, HTTP_STR("sess_id"));
|
||||
if (str.len == SESSION_TOKEN_SIZE) {
|
||||
char tmp[RAW_SESSION_TOKEN_SIZE];
|
||||
int ret = pack_token(str.ptr, str.len, tmp, (int) sizeof(tmp));
|
||||
if (ret) {
|
||||
memcpy(sess_token.data, str.ptr, str.len);
|
||||
user_id = session_set_find(&sessions, sess_token);
|
||||
}
|
||||
}
|
||||
sess = http_getcookie(req, HTTP_STR("sess_token"));
|
||||
if (find_session(session_storage, sess, &csrf, &user_id) < 0) {
|
||||
user_id = -1;
|
||||
sess = (HTTP_String) { NULL, 0 };
|
||||
csrf = (HTTP_String) { NULL, 0 };
|
||||
}
|
||||
|
||||
HTTP_String path = req->url.path;
|
||||
@@ -617,9 +489,9 @@ int main(void)
|
||||
}
|
||||
int user_id = ret;
|
||||
|
||||
CSRFToken csrf_token;
|
||||
SessionToken sess_token;
|
||||
if (session_set_add(&sessions, user_id, &sess_token, &csrf_token) < 0) {
|
||||
HTTP_String sess;
|
||||
HTTP_String csrf;
|
||||
if (create_session(session_storage, user_id, &sess, &csrf) < 0) {
|
||||
http_response_builder_status(builder, 200);
|
||||
http_response_builder_body(builder, HTML_STR((
|
||||
<div class="error">
|
||||
@@ -630,8 +502,9 @@ int main(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: set cookie as secure
|
||||
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)) {
|
||||
http_response_builder_status(builder, 200);
|
||||
http_response_builder_body(builder, HTML_STR((
|
||||
@@ -719,9 +592,9 @@ int main(void)
|
||||
}
|
||||
user_id = ret;
|
||||
|
||||
CSRFToken csrf_token;
|
||||
SessionToken sess_token;
|
||||
if (session_set_add(&sessions, user_id, &sess_token, &csrf_token) < 0) {
|
||||
HTTP_String sess;
|
||||
HTTP_String csrf;
|
||||
if (create_session(session_storage, user_id, &sess, &csrf) < 0) {
|
||||
http_response_builder_status(builder, 200);
|
||||
http_response_builder_body(builder, HTML_STR((
|
||||
<div class="error">
|
||||
@@ -732,8 +605,9 @@ int main(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: set cookie as secure
|
||||
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)) {
|
||||
http_response_builder_status(builder, 200);
|
||||
http_response_builder_body(builder, HTML_STR((
|
||||
@@ -758,10 +632,11 @@ int main(void)
|
||||
} else if (http_streq(path, HTTP_STR("/api/logout"))) {
|
||||
|
||||
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_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_done(builder);
|
||||
|
||||
@@ -783,11 +658,19 @@ int main(void)
|
||||
HTTP_String title = http_getparam(req->body, HTTP_STR("title"), &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 csrf2 = http_getparam(req->body, HTTP_STR("csrf"), &arena);
|
||||
|
||||
title = http_trim(title);
|
||||
link = http_trim(link);
|
||||
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)) {
|
||||
http_response_builder_status(builder, 200);
|
||||
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_comment = http_getparami(req->body, HTTP_STR("parent_comment"), &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);
|
||||
if (!valid_comment_content(content)) {
|
||||
@@ -997,7 +888,7 @@ int main(void)
|
||||
|
||||
} 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"))) {
|
||||
|
||||
@@ -1009,7 +900,7 @@ int main(void)
|
||||
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"))) {
|
||||
|
||||
@@ -1021,7 +912,7 @@ int main(void)
|
||||
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"))) {
|
||||
|
||||
@@ -1033,13 +924,13 @@ int main(void)
|
||||
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"))) {
|
||||
|
||||
int post_id = http_getparami(req->url.query, HTTP_STR("id"), &arena);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1074,18 +965,19 @@ int main(void)
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
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);
|
||||
template_cache_free(tpcache);
|
||||
sqlite3_close(db);
|
||||
|
||||
+198
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -293,7 +293,7 @@ static int query_routine(WL_Runtime *rt, SQLiteCache *dbcache)
|
||||
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;
|
||||
|
||||
@@ -310,6 +310,13 @@ static void push_sysvar(WL_Runtime *rt, WL_String name, SQLiteCache *dbcache, in
|
||||
wl_push_none(rt);
|
||||
else
|
||||
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,
|
||||
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);
|
||||
|
||||
@@ -394,7 +401,7 @@ void template_eval(HTTP_ResponseBuilder builder, int status,
|
||||
return;
|
||||
|
||||
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;
|
||||
|
||||
case WL_EVAL_SYSCALL:
|
||||
|
||||
+1
-1
@@ -11,6 +11,6 @@ void template_cache_free(TemplateCache *cache);
|
||||
|
||||
void template_eval(HTTP_ResponseBuilder builder, int status,
|
||||
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
|
||||
Reference in New Issue
Block a user