From b3246c9a3ed1496c7e34d3f3b24b75d8323287d4 Mon Sep 17 00:00:00 2001 From: SimonFJ20 Date: Thu, 6 Mar 2025 16:36:33 +0100 Subject: [PATCH] register --- backend/.gitignore | 1 + backend/src/controllers.h | 6 ++- backend/src/controllers/auth.c | 10 +++++ backend/src/controllers/general.c | 48 ++++++++++++++++++++++ backend/src/controllers/users.c | 66 +++++++++++++++++++++++++++++++ backend/src/db.h | 2 +- backend/src/db_sqlite.c | 4 +- backend/src/str_util.c | 44 +++++++++++++++------ backend/src/str_util.h | 17 ++------ 9 files changed, 168 insertions(+), 30 deletions(-) create mode 100644 backend/src/controllers/auth.c create mode 100644 backend/src/controllers/general.c create mode 100644 backend/src/controllers/users.c diff --git a/backend/.gitignore b/backend/.gitignore index 5e19c1d..2f64681 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,2 +1,3 @@ build/ database.db +Session.vim diff --git a/backend/src/controllers.h b/backend/src/controllers.h index 8e917fd..3a1d8b7 100644 --- a/backend/src/controllers.h +++ b/backend/src/controllers.h @@ -38,5 +38,7 @@ void route_post_user_register(HttpCtx* ctx); #define RESPOND_JSON(HTTP_CTX, STATUS, ...) \ RESPOND(HTTP_CTX, STATUS, "application/json", __VA_ARGS__) -#define RESPOND_BAD_REQUEST(HTTP_CTX) \ - RESPOND_JSON(HTTP_CTX, 400, "{\"ok\":false}") +#define RESPOND_BAD_REQUEST(HTTP_CTX, MSG) \ + RESPOND_JSON(HTTP_CTX, 400, "{\"ok\":false,\"msg\":\"%s\"}", (MSG)) +#define RESPOND_SERVER_ERROR(HTTP_CTX) \ + RESPOND_JSON(HTTP_CTX, 500, "{\"ok\":false,\"msg\":\"server error\"}") diff --git a/backend/src/controllers/auth.c b/backend/src/controllers/auth.c new file mode 100644 index 0000000..754ee6a --- /dev/null +++ b/backend/src/controllers/auth.c @@ -0,0 +1,10 @@ +#include "../controllers.h" +#include "../http_server.h" +#include "../models_json.h" +#include "../str_util.h" + +void route_post_auth_login(HttpCtx* ctx) +{ + + Cx* cx = http_ctx_user_ctx(ctx); +} diff --git a/backend/src/controllers/general.c b/backend/src/controllers/general.c new file mode 100644 index 0000000..c876953 --- /dev/null +++ b/backend/src/controllers/general.c @@ -0,0 +1,48 @@ +#include "../controllers.h" +#include "../http_server.h" +#include "../models_json.h" + +void route_get_index(HttpCtx* ctx) +{ + Cx* cx = http_ctx_user_ctx(ctx); + + RESPOND_HTML(ctx, 200, + "

Number = %d

", + cx->number); +} + +void route_post_set_number(HttpCtx* ctx) +{ + Cx* cx = http_ctx_user_ctx(ctx); + + const char* body_text = http_ctx_req_body(ctx); + JsonParser parser; + json_parser_construct(&parser, body_text, strlen(body_text)); + JsonValue* body = json_parser_parse(&parser); + json_parser_destroy(&parser); + + if (!json_object_has(body, "value")) { + RESPOND_JSON( + ctx, 200, "{\"ok\": false, \"msg\": \"no 'value' key\"}\r\n"); + goto l0_return; + } + + int64_t value = json_int(json_object_get(body, "value")); + cx->number = (int)value; + + RESPOND_JSON(ctx, 200, "{\"ok\": true}\r\n"); + +l0_return: + json_free(body); +} + +void route_get_not_found(HttpCtx* ctx) +{ + RESPOND_HTML(ctx, 404, + "

404 Not " + "Found

GET " + "%s
", + http_ctx_req_path(ctx)); +} diff --git a/backend/src/controllers/users.c b/backend/src/controllers/users.c new file mode 100644 index 0000000..910a476 --- /dev/null +++ b/backend/src/controllers/users.c @@ -0,0 +1,66 @@ +#include "../controllers.h" +#include "../http_server.h" +#include "../models_json.h" +#include "../str_util.h" +#include + +void route_post_user_register(HttpCtx* ctx) +{ + Cx* cx = http_ctx_user_ctx(ctx); + + const char* body_str = http_ctx_req_body(ctx); + + JsonValue* body_json = json_parse(body_str, strlen(body_str)); + + UsersRegisterReq req; + if (users_register_req_from_json(&req, body_json) != 0) { + RESPOND_BAD_REQUEST(ctx, "bad request"); + json_free(body_json); + return; + } + json_free(body_json); + + if (strlen(req.name) == 0 || strlen(req.email) == 0 + || strlen(req.password) > MAX_HASH_INPUT_LEN) { + RESPOND_BAD_REQUEST(ctx, "bad request"); + users_register_req_free(&req); + return; + } + + Ids ids; + ids_construct(&ids); + if (db_users_with_email(cx->db, &ids, req.email) != DbRes_Ok) { + RESPOND_SERVER_ERROR(ctx); + ids_destroy(&ids); + users_register_req_free(&req); + return; + } + if (ids.size > 0) { + RESPOND_BAD_REQUEST(ctx, "email in use"); + ids_destroy(&ids); + users_register_req_free(&req); + return; + } + ids_destroy(&ids); + + char* password_hash = str_hash(req.password); + + if (db_user_insert(cx->db, + &(User) { + .id = 0, + .name = req.name, + .email = req.email, + .password_hash = password_hash, + .balance_dkk_cent = 0, + }) + != DbRes_Ok) { + + RESPOND_SERVER_ERROR(ctx); + free(password_hash); + users_register_req_free(&req); + return; + } + free(password_hash); + users_register_req_free(&req); + RESPOND_JSON(ctx, 200, "{\"ok\":true}"); +} diff --git a/backend/src/db.h b/backend/src/db.h index d07b66d..dfba81e 100644 --- a/backend/src/db.h +++ b/backend/src/db.h @@ -15,7 +15,7 @@ typedef enum { typedef struct Db Db; /// `user.id` field is ignored. -DbRes db_user_insert(Db* db, User* user); +DbRes db_user_insert(Db* db, const User* user); DbRes db_user_from_id(Db* db, User* user, int64_t id); /// Expects `ids` to be constructed. DbRes db_users_with_email(Db* db, Ids* ids, const char* email); diff --git a/backend/src/db_sqlite.c b/backend/src/db_sqlite.c index ad49ecb..7ef6c55 100644 --- a/backend/src/db_sqlite.c +++ b/backend/src/db_sqlite.c @@ -65,7 +65,7 @@ static inline void disconnect(sqlite3* connection) disconnect(connection); \ } -DbRes db_user_insert(Db* db, User* user) +DbRes db_user_insert(Db* db, const User* user) { static_assert(sizeof(User) == 40, "model has changed"); @@ -76,7 +76,7 @@ DbRes db_user_insert(Db* db, User* user) sqlite3_stmt* stmt; sqlite3_prepare_v2(connection, "INSERT INTO users (name, email, password_hash, balance_dkk_cent) " - "VALUES (?, ?, ?)", + "VALUES (?, ?, ?, ?)", -1, &stmt, NULL); sqlite3_bind_text(stmt, 1, user->name, -1, SQLITE_STATIC); diff --git a/backend/src/str_util.c b/backend/src/str_util.c index 2989eba..6894ea6 100644 --- a/backend/src/str_util.c +++ b/backend/src/str_util.c @@ -72,17 +72,27 @@ char* string_copy(const String* string) return copy; } -static inline StrHash str_hash_with_salt(const char* str, const uint8_t* salt) +#define STR_HASH_SALT_SIZE 32 +#define STR_HASH_HASH_SIZE 32 +#define STR_HASH_STR_LEN 128 + +typedef struct { + uint8_t salt[STR_HASH_SALT_SIZE]; + uint8_t hash[STR_HASH_HASH_SIZE]; +} HashData; + +static inline HashData hashdata_from_str_and_salt( + const char* str, const uint8_t* salt) { - if (strlen(str) >= MAX_HASH_INPUT_LEN - 1) { + if (strlen(str) >= MAX_HASH_INPUT_LEN) { fprintf(stderr, "error: tried to hash too long input\n"); exit(1); } - StrHash hash; + HashData hash; memcpy(hash.salt, salt, STR_HASH_SALT_SIZE); - uint8_t input[MAX_HASH_INPUT_LEN + STR_HASH_SALT_SIZE] = { 0 }; + uint8_t input[MAX_HASH_INPUT_LEN + 1 + STR_HASH_SALT_SIZE] = { 0 }; memcpy(input, hash.salt, STR_HASH_SALT_SIZE); memcpy(&input[STR_HASH_SALT_SIZE], str, strlen(str)); @@ -90,20 +100,20 @@ static inline StrHash str_hash_with_salt(const char* str, const uint8_t* salt) return hash; } -StrHash str_hash(const char* str) +static inline HashData hashdata_from_str(const char* str) { uint8_t salt[STR_HASH_SALT_SIZE]; RAND_bytes(salt, STR_HASH_SALT_SIZE); - return str_hash_with_salt(str, salt); + return hashdata_from_str_and_salt(str, salt); } -bool str_hash_is_equal(StrHash hash, const char* str) +static inline bool hashdata_is_equal(HashData hash, const char* str) { - StrHash other = str_hash_with_salt(str, hash.salt); + HashData other = hashdata_from_str_and_salt(str, hash.salt); return memcmp(hash.hash, other.hash, STR_HASH_HASH_SIZE) == 0; } -char* str_hash_to_string(StrHash hash) +static inline char* hashdata_to_string(HashData hash) { char* result = calloc(STR_HASH_STR_LEN + 1, sizeof(char)); for (size_t i = 0; i < STR_HASH_SALT_SIZE; ++i) { @@ -121,7 +131,7 @@ char* str_hash_to_string(StrHash hash) return result; } -StrHash str_hash_from_string(const char* str) +static inline HashData hashdata_from_hash_string(const char* str) { uint8_t result[64] = { 0 }; size_t result_i = 0; @@ -133,7 +143,7 @@ StrHash str_hash_from_string(const char* str) result_i += 1; } - StrHash hash; + HashData hash; // memcpy((uint8_t*)&hash, result, sizeof(result)); for (size_t i = 0; i < 32; ++i) { hash.salt[i] = result[i]; @@ -141,3 +151,15 @@ StrHash str_hash_from_string(const char* str) } return hash; } + +char* str_hash(const char* input) +{ + HashData data = hashdata_from_str(input); + return hashdata_to_string(data); +} + +bool str_hash_equal(const char* hash, const char* input) +{ + HashData data = hashdata_from_hash_string(hash); + return hashdata_is_equal(data, input); +} diff --git a/backend/src/str_util.h b/backend/src/str_util.h index 44aaacc..0ebe580 100644 --- a/backend/src/str_util.h +++ b/backend/src/str_util.h @@ -33,18 +33,7 @@ char* string_copy(const String* string); DEFINE_VEC(char*, RawStrVec, rawstr_vec, 8) -#define MAX_HASH_INPUT_LEN 256 +#define MAX_HASH_INPUT_LEN 256 - 1 -#define STR_HASH_SALT_SIZE 32 -#define STR_HASH_HASH_SIZE 32 -#define STR_HASH_STR_LEN 128 - -typedef struct { - uint8_t salt[STR_HASH_SALT_SIZE]; - uint8_t hash[STR_HASH_HASH_SIZE]; -} StrHash; - -StrHash str_hash(const char* str); -bool str_hash_is_equal(StrHash hash, const char* str); -char* str_hash_to_string(StrHash hash); -StrHash str_hash_from_string(const char* str); +char* str_hash(const char* input); +bool str_hash_equal(const char* hash, const char* input);