implemented RegisterRequest handler

This commit is contained in:
Timerix 2025-11-13 06:19:16 +05:00
parent d53557dbb6
commit ef2531c63b
12 changed files with 126 additions and 21 deletions

2
dependencies/tlibc vendored

@ -1 +1 @@
Subproject commit 1775b27980d550dd9a50a81b11d797c51253ab22
Subproject commit adaf5cc31199b8b70404f30b51a0e4ef822d6fab

11
src/common_constants.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "tlibc/std.h"
#define USERNAME_SIZE_MIN 2
#define USERNAME_SIZE_MAX 63
#define PASSWORD_SIZE_MIN 8
#define PASSWORD_SIZE_MAX 31
#define PASSWORD_HASH_SIZE 32
#define CHANNEL_NAME_MIN 1
#define CHANNEL_NAME_MAX 127
#define CHANNEL_DESC_MAX 4095

View File

@ -2,6 +2,7 @@
#include "tlibc/collections/Array.h"
#include "tlibc/errors.h"
#include "bearssl_rand.h"
#include "common_constants.h"
//////////////////////////////////////////////////////////////////////////////
// //
@ -14,7 +15,6 @@
/// @param out_buffer u8[PASSWORD_HASH_SIZE]
/// @param rounds number of rounds
void hash_password(Array(u8) password, u8* out_buffer, i32 rounds);
#define PASSWORD_HASH_SIZE 32
#define PASSWORD_HASH_LVL_ROUNDS 1e5
//////////////////////////////////////////////////////////////////////////////

View File

@ -14,13 +14,13 @@ void idb_close(IncrementalDB* db);
Result(Table*) idb_getOrCreateTable(IncrementalDB* db, str table_name, u32 row_size);
Result(void) idb_getRows(Table* t, u64 id, void* dst, u64 count);
Result(void) idb_getRows(Table* t, u64 start_from_id, void* dst, u64 count);
#define idb_getRow(T, ID, DST) idb_getRows(T, ID, DST, 1)
Result(u64) idb_pushRows(Table* t, const void* src, u64 count);
#define idb_pushRow(T, SRC) idb_pushRows(T, SRC, 1)
Result(void) idb_updateRows(Table* t, u64 id, const void* src, u64 count);
Result(void) idb_updateRows(Table* t, u64 start_from_id, const void* src, u64 count);
#define idb_updateRow(T, ID, SRC) idb_updateRows(T, ID, SRC, 1)
Result(u64) idb_getRowCount(Table* t);

View File

@ -1,6 +1,7 @@
#pragma once
#include "tlibc/errors.h"
#include "magic.h"
#include "common_constants.h"
#define AES_SESSION_KEY_SIZE 32

View File

@ -56,8 +56,8 @@ Result(void) RegisterRequest_tryConstruct(RegisterRequest *ptr, PacketHeader* he
_PacketHeader_construct(RegisterRequest);
try_assert(username.size >= USERNAME_SIZE_MIN && username.size <= USERNAME_SIZE_MAX);
ptr->username_size = username.size;
memcpy(ptr->username, username.data, username.size);
ptr->username[username.size] = 0;
try_assert(token.size == sizeof(ptr->token));
memcpy(ptr->token, token.data, token.size);

View File

@ -2,7 +2,6 @@
#include "tlibc/errors.h"
#include "tlibc/string/str.h"
#include "network/tcp-chat-protocol/constant.h"
#include "cryptography/cryptography.h"
#define PROTOCOL_VERSION 1 /* 1.0.0 */
#define NETWORK_BUFFER_SIZE 65536
@ -80,14 +79,8 @@ void LoginResponse_construct(LoginResponse* ptr, PacketHeader* header,
u64 user_id, u64 landing_channel_id);
#define USERNAME_SIZE_MIN 4
#define USERNAME_SIZE_MAX 64
#define PASSWORD_SIZE_MIN 8
#define PASSWORD_SIZE_MAX 32
typedef struct RegisterRequest {
u32 username_size;
char username[USERNAME_SIZE_MAX];
char username[USERNAME_SIZE_MAX + 1]; // null-terminated
u8 token[PASSWORD_HASH_SIZE];
} ALIGN_PACKET_STRUCT RegisterRequest;

17
src/server/db_tables.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include "common_constants.h"
#include "tlibc/time.h"
typedef struct User {
u16 name_len;
char name[USERNAME_SIZE_MAX + 1]; // null-terminated
u8 token_hash[PASSWORD_HASH_SIZE]; // token is hashed again on server side
DateTime registration_time;
} ATTRIBUTE_ALIGNED(256) User;
typedef struct Channel {
u16 name_len;
u16 desc_len;
char name[CHANNEL_NAME_MAX + 1];
char desc[CHANNEL_DESC_MAX + 1];
} ATTRIBUTE_ALIGNED(16*1024) Channel;

View File

@ -9,8 +9,62 @@ declare_RequestHandler(Register)
try_void(PacketHeader_validateContentSize(req_head, sizeof(req)));
try_void(EncryptedSocketTCP_recvStruct(&conn->sock, &req));
//TODO: try register client
u64 user_id;
//TODO: reject usernames with restricted characters
// must end with 0
if(req.username[sizeof(req.username - 1)] != 0){
try(char* err_msg, p, sendErrorMessage(conn, res_head,
"Username is incorrect\n"));
logWarn(log_ctx, "%s", err_msg);
free(err_msg);
Return RESULT_VOID;
}
// check username size
str username_str = str_from_cstr(req.username);
if(username_str.size < USERNAME_SIZE_MIN){
try(char* err_msg, p, sendErrorMessage(conn, res_head,
"Username length (in bytes) must be >= %i and <= %i\n",
USERNAME_SIZE_MIN, USERNAME_SIZE_MAX));
logWarn(log_ctx, "%s", err_msg);
free(err_msg);
Return RESULT_VOID;
}
// lock users cache
try_stderrcode(pthread_mutex_lock(&server->users_cache_mutex));
bool unlocked_users_cache_mutex = false;
Defer(if(!unlocked_users_cache_mutex) pthread_mutex_unlock(&server->users_cache_mutex));
// check if name is taken
if(HashMap_tryGetPtr(&server->users_name_id_map, username_str) != NULL){
try(char* err_msg, p, sendErrorMessage(conn, res_head,
"User with name '%s' already exists\n",
username_str.data));
logWarn(log_ctx, "%s", err_msg);
free(err_msg);
Return RESULT_VOID;
}
// initialize new user
User user;
memset(&user, 0, sizeof(User));
memcpy(user.name, username_str.data, username_str.size + 1);
user.name_len = username_str.size;
hash_password(
Array_construct_size(req.token, sizeof(req.token)),
user.token_hash,
PASSWORD_HASH_LVL_ROUNDS
);
DateTime_getUTC(&user.registration_time);
// save new user to db and cache
try(u64 user_id, u, idb_pushRow(server->db_users_table, &user));
try_assert(List_len(server->users_cache_list, User) == user_id);
List_push(&server->users_cache_list, User, user);
try_assert(HashMap_tryPush(&server->users_name_id_map, username_str, &user_id));
// manually unlock mutex
pthread_mutex_unlock(&server->users_cache_mutex);
unlocked_users_cache_mutex = true;
RegisterResponse res = {0};
RegisterResponse_construct(&res, res_head, user_id);

View File

@ -12,12 +12,14 @@ declare_RequestHandler(ServerPublicInfo)
//TODO: try find requested info
Array(u8) content;
switch(req.property){
default:
default:{
try(char* err_msg, p, sendErrorMessage(conn, res_head,
"unknown ServerPublicInfo property %u", req.property));
"Unknown ServerPublicInfo property %u",
req.property));
logWarn(log_ctx, "%s", err_msg);
free(err_msg);
Return RESULT_VOID;
break;
}
case ServerPublicInfo_Name:
content = str_castTo_Array(server->name);
break;

View File

@ -18,6 +18,9 @@ void Server_free(Server* server){
free(server->description.data);
ServerCredentials_destroy(&server->cred);
idb_close(server->db);
pthread_mutex_destroy(&server->users_cache_mutex);
free(server->users_cache_list.data);
HashMap_destroy(&server->users_name_id_map);
}
Result(Server*) Server_createFromConfig(cstr config_path){
@ -76,6 +79,23 @@ Result(Server*) Server_createFromConfig(cstr config_path){
try_void(config_findValue(config_str, STR("db_dir"), &tmp_str, true));
try(server->db, p, idb_open(tmp_str, db_aes_key));
// build users cache
pthread_mutex_init(&server->users_cache_mutex, NULL);
try(server->db_users_table, p, idb_getOrCreateTable(server->db, STR("users"), sizeof(User)));
try(u64 users_count, u, idb_getRowCount(server->db_users_table));
server->users_cache_list = List_alloc(User, users_count);
HashMap_construct(&server->users_name_id_map, u64, NULL);
// load whole table to list
try_void(idb_getRows(server->db_users_table, 0, server->users_cache_list.data, users_count));
// build name-id map
for(u64 id; id < users_count; id++){
User* u = &List_index(server->users_cache_list, User, id);
str key = str_construct(u->name, u->name_len, true);
if(!HashMap_tryPush(&server->users_name_id_map, key, &id)){
Return RESULT_ERROR_FMT("duplicate user name '%s'", u->name);
}
}
success = true;
Return RESULT_VALUE(p, server);
}
@ -154,10 +174,9 @@ static Result(void) try_handleConnection(ConnectionHandlerArgs* args, cstr log_c
try(char* err_msg, p,
sendErrorMessage(conn, &res_head,
"Received unexpected packet of type %u",
req_head.type
)
);
req_head.type));
logWarn(log_ctx, "%s", err_msg);
free(err_msg);
Return RESULT_VOID;
// unauthorized requests

View File

@ -3,6 +3,10 @@
#include "cryptography/RSA.h"
#include "network/encrypted_sockets.h"
#include "db/idb.h"
#include "tlibc/collections/HashMap.h"
#include "tlibc/collections/List.h"
#include "db_tables.h"
#include <pthread.h>
typedef struct Server Server;
@ -44,6 +48,10 @@ typedef struct Server {
EndpointIPv4 local_end;
ServerCredentials cred;
IncrementalDB* db;
Table* db_users_table;
pthread_mutex_t users_cache_mutex;
List(User) users_cache_list; // index is id
HashMap(u64) users_name_id_map; //key is user name
} Server;
Result(Server*) Server_createFromConfig(cstr config_path);