implemented RegisterRequest handler
This commit is contained in:
parent
d53557dbb6
commit
ef2531c63b
2
dependencies/tlibc
vendored
2
dependencies/tlibc
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 1775b27980d550dd9a50a81b11d797c51253ab22
|
Subproject commit adaf5cc31199b8b70404f30b51a0e4ef822d6fab
|
||||||
11
src/common_constants.h
Normal file
11
src/common_constants.h
Normal 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
|
||||||
@ -2,6 +2,7 @@
|
|||||||
#include "tlibc/collections/Array.h"
|
#include "tlibc/collections/Array.h"
|
||||||
#include "tlibc/errors.h"
|
#include "tlibc/errors.h"
|
||||||
#include "bearssl_rand.h"
|
#include "bearssl_rand.h"
|
||||||
|
#include "common_constants.h"
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// //
|
// //
|
||||||
@ -14,7 +15,6 @@
|
|||||||
/// @param out_buffer u8[PASSWORD_HASH_SIZE]
|
/// @param out_buffer u8[PASSWORD_HASH_SIZE]
|
||||||
/// @param rounds number of rounds
|
/// @param rounds number of rounds
|
||||||
void hash_password(Array(u8) password, u8* out_buffer, i32 rounds);
|
void hash_password(Array(u8) password, u8* out_buffer, i32 rounds);
|
||||||
#define PASSWORD_HASH_SIZE 32
|
|
||||||
#define PASSWORD_HASH_LVL_ROUNDS 1e5
|
#define PASSWORD_HASH_LVL_ROUNDS 1e5
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -14,13 +14,13 @@ void idb_close(IncrementalDB* db);
|
|||||||
|
|
||||||
Result(Table*) idb_getOrCreateTable(IncrementalDB* db, str table_name, u32 row_size);
|
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)
|
#define idb_getRow(T, ID, DST) idb_getRows(T, ID, DST, 1)
|
||||||
|
|
||||||
Result(u64) idb_pushRows(Table* t, const void* src, u64 count);
|
Result(u64) idb_pushRows(Table* t, const void* src, u64 count);
|
||||||
#define idb_pushRow(T, SRC) idb_pushRows(T, SRC, 1)
|
#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)
|
#define idb_updateRow(T, ID, SRC) idb_updateRows(T, ID, SRC, 1)
|
||||||
|
|
||||||
Result(u64) idb_getRowCount(Table* t);
|
Result(u64) idb_getRowCount(Table* t);
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "tlibc/errors.h"
|
#include "tlibc/errors.h"
|
||||||
#include "magic.h"
|
#include "magic.h"
|
||||||
|
#include "common_constants.h"
|
||||||
|
|
||||||
#define AES_SESSION_KEY_SIZE 32
|
#define AES_SESSION_KEY_SIZE 32
|
||||||
|
|
||||||
|
|||||||
@ -56,8 +56,8 @@ Result(void) RegisterRequest_tryConstruct(RegisterRequest *ptr, PacketHeader* he
|
|||||||
_PacketHeader_construct(RegisterRequest);
|
_PacketHeader_construct(RegisterRequest);
|
||||||
|
|
||||||
try_assert(username.size >= USERNAME_SIZE_MIN && username.size <= USERNAME_SIZE_MAX);
|
try_assert(username.size >= USERNAME_SIZE_MIN && username.size <= USERNAME_SIZE_MAX);
|
||||||
ptr->username_size = username.size;
|
|
||||||
memcpy(ptr->username, username.data, username.size);
|
memcpy(ptr->username, username.data, username.size);
|
||||||
|
ptr->username[username.size] = 0;
|
||||||
|
|
||||||
try_assert(token.size == sizeof(ptr->token));
|
try_assert(token.size == sizeof(ptr->token));
|
||||||
memcpy(ptr->token, token.data, token.size);
|
memcpy(ptr->token, token.data, token.size);
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
#include "tlibc/errors.h"
|
#include "tlibc/errors.h"
|
||||||
#include "tlibc/string/str.h"
|
#include "tlibc/string/str.h"
|
||||||
#include "network/tcp-chat-protocol/constant.h"
|
#include "network/tcp-chat-protocol/constant.h"
|
||||||
#include "cryptography/cryptography.h"
|
|
||||||
|
|
||||||
#define PROTOCOL_VERSION 1 /* 1.0.0 */
|
#define PROTOCOL_VERSION 1 /* 1.0.0 */
|
||||||
#define NETWORK_BUFFER_SIZE 65536
|
#define NETWORK_BUFFER_SIZE 65536
|
||||||
@ -80,14 +79,8 @@ void LoginResponse_construct(LoginResponse* ptr, PacketHeader* header,
|
|||||||
u64 user_id, u64 landing_channel_id);
|
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 {
|
typedef struct RegisterRequest {
|
||||||
u32 username_size;
|
char username[USERNAME_SIZE_MAX + 1]; // null-terminated
|
||||||
char username[USERNAME_SIZE_MAX];
|
|
||||||
u8 token[PASSWORD_HASH_SIZE];
|
u8 token[PASSWORD_HASH_SIZE];
|
||||||
} ALIGN_PACKET_STRUCT RegisterRequest;
|
} ALIGN_PACKET_STRUCT RegisterRequest;
|
||||||
|
|
||||||
|
|||||||
17
src/server/db_tables.h
Normal file
17
src/server/db_tables.h
Normal 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;
|
||||||
@ -9,8 +9,62 @@ declare_RequestHandler(Register)
|
|||||||
try_void(PacketHeader_validateContentSize(req_head, sizeof(req)));
|
try_void(PacketHeader_validateContentSize(req_head, sizeof(req)));
|
||||||
try_void(EncryptedSocketTCP_recvStruct(&conn->sock, &req));
|
try_void(EncryptedSocketTCP_recvStruct(&conn->sock, &req));
|
||||||
|
|
||||||
//TODO: try register client
|
//TODO: reject usernames with restricted characters
|
||||||
u64 user_id;
|
// 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 res = {0};
|
||||||
RegisterResponse_construct(&res, res_head, user_id);
|
RegisterResponse_construct(&res, res_head, user_id);
|
||||||
|
|||||||
@ -12,12 +12,14 @@ declare_RequestHandler(ServerPublicInfo)
|
|||||||
//TODO: try find requested info
|
//TODO: try find requested info
|
||||||
Array(u8) content;
|
Array(u8) content;
|
||||||
switch(req.property){
|
switch(req.property){
|
||||||
default:
|
default:{
|
||||||
try(char* err_msg, p, sendErrorMessage(conn, res_head,
|
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);
|
logWarn(log_ctx, "%s", err_msg);
|
||||||
|
free(err_msg);
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
break;
|
}
|
||||||
case ServerPublicInfo_Name:
|
case ServerPublicInfo_Name:
|
||||||
content = str_castTo_Array(server->name);
|
content = str_castTo_Array(server->name);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -18,6 +18,9 @@ void Server_free(Server* server){
|
|||||||
free(server->description.data);
|
free(server->description.data);
|
||||||
ServerCredentials_destroy(&server->cred);
|
ServerCredentials_destroy(&server->cred);
|
||||||
idb_close(server->db);
|
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){
|
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_void(config_findValue(config_str, STR("db_dir"), &tmp_str, true));
|
||||||
try(server->db, p, idb_open(tmp_str, db_aes_key));
|
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;
|
success = true;
|
||||||
Return RESULT_VALUE(p, server);
|
Return RESULT_VALUE(p, server);
|
||||||
}
|
}
|
||||||
@ -154,10 +174,9 @@ static Result(void) try_handleConnection(ConnectionHandlerArgs* args, cstr log_c
|
|||||||
try(char* err_msg, p,
|
try(char* err_msg, p,
|
||||||
sendErrorMessage(conn, &res_head,
|
sendErrorMessage(conn, &res_head,
|
||||||
"Received unexpected packet of type %u",
|
"Received unexpected packet of type %u",
|
||||||
req_head.type
|
req_head.type));
|
||||||
)
|
|
||||||
);
|
|
||||||
logWarn(log_ctx, "%s", err_msg);
|
logWarn(log_ctx, "%s", err_msg);
|
||||||
|
free(err_msg);
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
|
|
||||||
// unauthorized requests
|
// unauthorized requests
|
||||||
|
|||||||
@ -3,6 +3,10 @@
|
|||||||
#include "cryptography/RSA.h"
|
#include "cryptography/RSA.h"
|
||||||
#include "network/encrypted_sockets.h"
|
#include "network/encrypted_sockets.h"
|
||||||
#include "db/idb.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;
|
typedef struct Server Server;
|
||||||
|
|
||||||
@ -44,6 +48,10 @@ typedef struct Server {
|
|||||||
EndpointIPv4 local_end;
|
EndpointIPv4 local_end;
|
||||||
ServerCredentials cred;
|
ServerCredentials cred;
|
||||||
IncrementalDB* db;
|
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;
|
} Server;
|
||||||
|
|
||||||
Result(Server*) Server_createFromConfig(cstr config_path);
|
Result(Server*) Server_createFromConfig(cstr config_path);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user