Compare commits
4 Commits
85c0736c8d
...
1b00f503c8
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b00f503c8 | |||
| a1a11c10e2 | |||
| eec45cac71 | |||
| 5266872c2b |
1
.vscode/c_cpp_properties.json
vendored
1
.vscode/c_cpp_properties.json
vendored
@ -5,6 +5,7 @@
|
|||||||
"defines": [],
|
"defines": [],
|
||||||
"includePath": [
|
"includePath": [
|
||||||
"src",
|
"src",
|
||||||
|
"include",
|
||||||
"dependencies/BearSSL/inc",
|
"dependencies/BearSSL/inc",
|
||||||
"dependencies/BearSSL/src",
|
"dependencies/BearSSL/src",
|
||||||
"dependencies/tlibc/include",
|
"dependencies/tlibc/include",
|
||||||
|
|||||||
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -7,7 +7,7 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/bin/tcp-chat",
|
"program": "${workspaceFolder}/bin/tcp-chat",
|
||||||
"windows": { "program": "${workspaceFolder}/bin/tcp-chat.exe" },
|
"windows": { "program": "${workspaceFolder}/bin/tcp-chat.exe" },
|
||||||
"args": [ "-l" ],
|
// "args": [ "-l" ],
|
||||||
"preLaunchTask": "build_exec_dbg",
|
"preLaunchTask": "build_exec_dbg",
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}/bin",
|
"cwd": "${workspaceFolder}/bin",
|
||||||
|
|||||||
2
dependencies/tlibc
vendored
2
dependencies/tlibc
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 425794361bc52240bb50001becbb5fb6e9ebcf20
|
Subproject commit c68e4e87b327ad21cd664e50ee2b5ef4ded3aed9
|
||||||
28
include/tcp-chat/client.h
Normal file
28
include/tcp-chat/client.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "tlibc/errors.h"
|
||||||
|
#include "tlibc/string/str.h"
|
||||||
|
|
||||||
|
typedef struct Client Client;
|
||||||
|
|
||||||
|
Result(Client*) Client_create(str username, str password);
|
||||||
|
void Client_free(Client* client);
|
||||||
|
|
||||||
|
/// @return username saved during client initialization
|
||||||
|
str Client_getUserName(Client* client);
|
||||||
|
|
||||||
|
/// @return AES key calculated from password that can be used to encrypt user data
|
||||||
|
Array(u8) Client_getUserDataKey(Client* client);
|
||||||
|
|
||||||
|
/// @param server_addr_cstr ip:port
|
||||||
|
/// @param server_pk_base64 public key encoded by `RSA_serializePublicKey_base64()`
|
||||||
|
Result(void) Client_connect(Client* client, cstr server_addr_cstr, cstr server_pk_base64);
|
||||||
|
/// disconnect from current server
|
||||||
|
void Client_disconnect(Client* client);
|
||||||
|
|
||||||
|
/// @param self connected client
|
||||||
|
/// @param out_name owned by Client, fetched from server during Client_connect
|
||||||
|
Result(void) Client_getServerName(Client* self, str* out_name);
|
||||||
|
|
||||||
|
/// @param self connected client
|
||||||
|
/// @param out_name owned by Client, fetched from server during Client_connect
|
||||||
|
Result(void) Client_getServerDescription(Client* self, str* out_desc);
|
||||||
15
include/tcp-chat/common_constants.h
Normal file
15
include/tcp-chat/common_constants.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "tlibc/std.h"
|
||||||
|
|
||||||
|
#define USERNAME_SIZE_MIN 2
|
||||||
|
#define USERNAME_SIZE_MAX 31
|
||||||
|
#define PASSWORD_SIZE_MIN 8
|
||||||
|
#define PASSWORD_SIZE_MAX 31
|
||||||
|
#define PASSWORD_HASH_SIZE 32
|
||||||
|
#define CHANNEL_NAME_SIZE_MIN 1
|
||||||
|
#define CHANNEL_NAME_SIZE_MAX 127
|
||||||
|
#define CHANNEL_DESC_SIZE_MAX 1023
|
||||||
|
#define PRIVATE_KEY_BASE64_SIZE_MAX 1724
|
||||||
|
#define PUBLIC_KEY_BASE64_SIZE_MAX 699
|
||||||
|
#define HOSTADDR_SIZE_MIN 4
|
||||||
|
#define HOSTADDR_SIZE_MAX 255
|
||||||
26
include/tcp-chat/log.h
Normal file
26
include/tcp-chat/log.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "tlibc/std.h"
|
||||||
|
#include "tlibc/string/cstr.h"
|
||||||
|
|
||||||
|
typedef enum LogSeverity {
|
||||||
|
LogSeverity_Debug,
|
||||||
|
LogSeverity_Info,
|
||||||
|
LogSeverity_Warn,
|
||||||
|
LogSeverity_Error,
|
||||||
|
} LogSeverity;
|
||||||
|
|
||||||
|
typedef void (*LogFunction_t)(void* logger, LogSeverity severity, cstr context, cstr msg);
|
||||||
|
|
||||||
|
#define log(severity, context, format, ...) { \
|
||||||
|
if(LOG_FUNC) { \
|
||||||
|
char* ___log_msg = sprintf_malloc(format ,##__VA_ARGS__); \
|
||||||
|
LOG_FUNC(LOGGER, severity, context, ___log_msg); \
|
||||||
|
free(___log_msg); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define logDebug(context, format, ...) log(LogSeverity_Debug, context, format ,##__VA_ARGS__)
|
||||||
|
#define logInfo(context, format, ...) log(LogSeverity_Info, context, format ,##__VA_ARGS__)
|
||||||
|
#define logWarn(context, format, ...) log(LogSeverity_Warn, context, format ,##__VA_ARGS__)
|
||||||
|
#define logError(context, format, ...) log(LogSeverity_Error, context, format ,##__VA_ARGS__)
|
||||||
10
include/tcp-chat/server.h
Normal file
10
include/tcp-chat/server.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "tlibc/errors.h"
|
||||||
|
#include "tlibc/string/str.h"
|
||||||
|
#include "tcp-chat/log.h"
|
||||||
|
|
||||||
|
typedef struct Server Server;
|
||||||
|
|
||||||
|
Result(Server*) Server_create(str config_str, void* logger, LogFunction_t log_func);
|
||||||
|
void Server_free(Server* server);
|
||||||
|
Result(void) Server_run(Server* server);
|
||||||
@ -35,7 +35,7 @@ OBJDIR="obj"
|
|||||||
OUTDIR="bin"
|
OUTDIR="bin"
|
||||||
STATIC_LIB_FILE="$PROJECT.a"
|
STATIC_LIB_FILE="$PROJECT.a"
|
||||||
|
|
||||||
INCLUDE="-Isrc -I$DEPENDENCIES_DIR/BearSSL/inc -I$DEPENDENCIES_DIR/tlibc/include"
|
INCLUDE="-Isrc -Iinclude -I$DEPENDENCIES_DIR/BearSSL/inc -I$DEPENDENCIES_DIR/tlibc/include"
|
||||||
|
|
||||||
# OS-specific options
|
# OS-specific options
|
||||||
case "$OS" in
|
case "$OS" in
|
||||||
|
|||||||
248
src/cli/ClientCLI/ClientCLI.c
Normal file
248
src/cli/ClientCLI/ClientCLI.c
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
#include "cli/ClientCLI/ClientCLI.h"
|
||||||
|
#include "cli/ClientCLI/db_tables.h"
|
||||||
|
#include "cli/term.h"
|
||||||
|
#include "tcp-chat/common_constants.h"
|
||||||
|
#include "tlibc/time.h"
|
||||||
|
#include "tlibc/filesystem.h"
|
||||||
|
|
||||||
|
static const str greeting_art = STR(
|
||||||
|
" ^,,^ ╱|\n"
|
||||||
|
" ( •·•) Meum! (o.o`7\n"
|
||||||
|
" / ` | Meum... |`˜ \\\n"
|
||||||
|
"\\(_,J J L l`,)/\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
static const str farewell_art = STR(
|
||||||
|
" ^,,^ ╱|\n"
|
||||||
|
" ( -.-) (>,<`7\n"
|
||||||
|
" / ` | Goodbye! |`˜ \\\n"
|
||||||
|
"\\(_,J J L l`,)/\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
#define is_alias(LITERAL) str_equals(command, STR(LITERAL))
|
||||||
|
|
||||||
|
static Result(void) ClientCLI_askUserNameAndPassword(str* username_out, str* password_out);
|
||||||
|
static Result(void) ClientCLI_commandExec(ClientCLI* self, str command, bool* stop);
|
||||||
|
static Result(void) ClientCLI_openUserDB(ClientCLI* self);
|
||||||
|
static Result(void) ClientCLI_saveServerInfo(ClientCLI* self,
|
||||||
|
cstr server_addr_cstr, cstr server_pk_base64,
|
||||||
|
str server_name, str server_description);
|
||||||
|
|
||||||
|
|
||||||
|
void ClientCLI_destroy(ClientCLI* self){
|
||||||
|
if(!self)
|
||||||
|
return;
|
||||||
|
Client_free(self->client);
|
||||||
|
idb_close(self->user_db);
|
||||||
|
}
|
||||||
|
void ClientCLI_construct(ClientCLI* self){
|
||||||
|
self->client = NULL;
|
||||||
|
self->user_db = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) ClientCLI_run(ClientCLI* self) {
|
||||||
|
Deferral(16);
|
||||||
|
|
||||||
|
try_void(term_init());
|
||||||
|
term_clear();
|
||||||
|
printf("%s\n", greeting_art.data);
|
||||||
|
|
||||||
|
// create Client
|
||||||
|
str username = str_null, password = str_null;
|
||||||
|
try_void(ClientCLI_askUserNameAndPassword(&username, &password));
|
||||||
|
Defer(
|
||||||
|
str_free(username);
|
||||||
|
str_free(password);
|
||||||
|
);
|
||||||
|
Client_free(self->client);
|
||||||
|
try(self->client, p, Client_create(username, password));
|
||||||
|
memset(password.data, 0, password.size);
|
||||||
|
|
||||||
|
// init db
|
||||||
|
try_void(ClientCLI_openUserDB(self));
|
||||||
|
|
||||||
|
char input_buf[1024];
|
||||||
|
str command_input = str_null;
|
||||||
|
bool stop = false;
|
||||||
|
while(!stop){
|
||||||
|
sleepMsec(50);
|
||||||
|
printf("> ");
|
||||||
|
try_void(term_readLine(input_buf, sizeof(input_buf)));
|
||||||
|
|
||||||
|
command_input = str_from_cstr(input_buf);
|
||||||
|
str_trim(&command_input, true);
|
||||||
|
if(command_input.size == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ResultVar(void) com_result = ClientCLI_commandExec(self, command_input, &stop);
|
||||||
|
if(com_result.error){
|
||||||
|
Error_addCallPos(com_result.error, ErrorCallPos_here());
|
||||||
|
str e_str = Error_toStr(com_result.error);
|
||||||
|
printf("%s\n", e_str.data);
|
||||||
|
str_free(e_str);
|
||||||
|
Error_free(com_result.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result(void) ClientCLI_askUserNameAndPassword(str* username_out, str* password_out){
|
||||||
|
Deferral(8);
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
// ask username
|
||||||
|
Array(char) username_buf = Array_alloc_size(128);
|
||||||
|
Defer(if(!success) Array_free(username_buf));
|
||||||
|
str username = str_null;
|
||||||
|
while(true) {
|
||||||
|
printf("username: ");
|
||||||
|
try_void(term_readLine(username_buf.data, username_buf.size));
|
||||||
|
username = str_from_cstr(username_buf.data);
|
||||||
|
str_trim(&username, true);
|
||||||
|
if(username.size < USERNAME_SIZE_MIN || username.size > USERNAME_SIZE_MAX){
|
||||||
|
printf("ERROR: username length (in bytes) must be >= %i and <= %i\n",
|
||||||
|
USERNAME_SIZE_MIN, USERNAME_SIZE_MAX);
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ask password
|
||||||
|
Array(char) password_buf = Array_alloc_size(128);
|
||||||
|
Defer(if(!success) Array_free(password_buf));
|
||||||
|
str password = str_null;
|
||||||
|
while(true) {
|
||||||
|
printf("password: ");
|
||||||
|
// TODO: hide password
|
||||||
|
try_void(term_readLineHidden(password_buf.data, password_buf.size));
|
||||||
|
password = str_from_cstr(password_buf.data);
|
||||||
|
str_trim(&password, true);
|
||||||
|
if(password.size < PASSWORD_SIZE_MIN || password.size > PASSWORD_SIZE_MAX){
|
||||||
|
printf("ERROR: password length (in bytes) must be >= %i and <= %i\n",
|
||||||
|
PASSWORD_SIZE_MIN, PASSWORD_SIZE_MAX);
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*username_out = username;
|
||||||
|
*password_out = password;
|
||||||
|
success = true;
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result(void) ClientCLI_commandExec(ClientCLI* self, str command, bool* stop){
|
||||||
|
Deferral(64);
|
||||||
|
|
||||||
|
if(is_alias("q") || is_alias("quit") || is_alias("exit")){
|
||||||
|
printf("%s\n", farewell_art.data);
|
||||||
|
*stop = true;
|
||||||
|
}
|
||||||
|
else if(is_alias("clear")){
|
||||||
|
term_clear();
|
||||||
|
}
|
||||||
|
else if(is_alias("h") || is_alias("help")){
|
||||||
|
printf(
|
||||||
|
"COMMANDS:\n"
|
||||||
|
"h, help Show this message.\n"
|
||||||
|
"q, quit, exit Close the program.\n"
|
||||||
|
"clear Clear the screen.\n"
|
||||||
|
"j, join Join a server.\n"
|
||||||
|
"c, connect Connect to a server you joined.\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (is_alias("j") || is_alias("join")){
|
||||||
|
// ask server address
|
||||||
|
printf("Enter server address (ip:port):\n");
|
||||||
|
char server_addr_cstr[HOSTADDR_SIZE_MAX + 1];
|
||||||
|
try_void(term_readLine(server_addr_cstr, sizeof(server_addr_cstr)));
|
||||||
|
str server_addr_str = str_from_cstr(server_addr_cstr);
|
||||||
|
str_trim(&server_addr_str, true);
|
||||||
|
|
||||||
|
// ask server public key
|
||||||
|
printf("Enter server public key (RSA-Public-<SIZE>:<DATA>):\n");
|
||||||
|
char server_pk_cstr[PUBLIC_KEY_BASE64_SIZE_MAX + 1];
|
||||||
|
try_void(term_readLine(server_pk_cstr, sizeof(server_pk_cstr)));
|
||||||
|
str server_pk_str = str_from_cstr(server_pk_cstr);
|
||||||
|
str_trim(&server_pk_str, true);
|
||||||
|
|
||||||
|
// connect to server
|
||||||
|
printf("connecting to server...\n");
|
||||||
|
try_void(Client_connect(self->client, server_addr_cstr, server_pk_cstr));
|
||||||
|
printf("connection established\n");
|
||||||
|
|
||||||
|
// show server info
|
||||||
|
str server_name = str_null;
|
||||||
|
str server_description = str_null;
|
||||||
|
try_void(Client_getServerName(self->client, &server_name));
|
||||||
|
try_void(Client_getServerName(self->client, &server_description));
|
||||||
|
printf("server name: %s\n", server_name.data);
|
||||||
|
printf("server description: %s\n", server_description.data);
|
||||||
|
|
||||||
|
try_void(ClientCLI_saveServerInfo(self, server_addr_cstr, server_pk_cstr,
|
||||||
|
server_name, server_description));
|
||||||
|
// TODO: ask in loop: log in / register
|
||||||
|
|
||||||
|
//TODO: call Client_runIO():
|
||||||
|
// function with infinite loop which sends and receives messages
|
||||||
|
// with navigation across server channels
|
||||||
|
}
|
||||||
|
else if(is_alias("c") || is_alias("connect")){
|
||||||
|
// TODO: read saved servers from database
|
||||||
|
// TODO: show scrollable list of servers, get selected one
|
||||||
|
// TODO: ask in loop: log in / register
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("ERROR: unknown command.\n"
|
||||||
|
"Use 'h' to see list of avaliable commands\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result(void) ClientCLI_openUserDB(ClientCLI* self){
|
||||||
|
Deferral(8);
|
||||||
|
|
||||||
|
str username = Client_getUserName(self->client);
|
||||||
|
Array(u8) user_data_key = Client_getUserDataKey(self->client);
|
||||||
|
str user_db_dir = str_from_cstr(strcat_malloc("client-db", path_seps, username.data));
|
||||||
|
Defer(free(user_db_dir.data));
|
||||||
|
try(self->user_db, p, idb_open(user_db_dir, user_data_key));
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result(void) ClientCLI_saveServerInfo(ClientCLI* self,
|
||||||
|
cstr server_addr_cstr, cstr server_pk_base64,
|
||||||
|
str server_name, str server_description){
|
||||||
|
Deferral(8);
|
||||||
|
|
||||||
|
ServerInfo si;
|
||||||
|
memset(&si, 0, sizeof(ServerInfo));
|
||||||
|
|
||||||
|
// address
|
||||||
|
si.address_len = strlen(server_addr_cstr);
|
||||||
|
memcpy(si.address, server_addr_cstr, si.address_len);
|
||||||
|
si.address[si.address_len] = 0;
|
||||||
|
|
||||||
|
// public key
|
||||||
|
si.pk_base64_len = strlen(server_pk_base64);
|
||||||
|
memcpy(si.pk_base64, server_addr_cstr, si.pk_base64_len);
|
||||||
|
si.pk_base64[si.pk_base64_len] = 0;
|
||||||
|
|
||||||
|
// name
|
||||||
|
si.name_len = server_name.size;
|
||||||
|
memcpy(si.name, server_name.data, si.name_len);
|
||||||
|
si.name[si.name_len] = 0;
|
||||||
|
|
||||||
|
// description
|
||||||
|
si.desc_len = server_name.size;
|
||||||
|
memcpy(si.desc, server_description.data, si.desc_len);
|
||||||
|
si.desc[si.desc_len] = 0;
|
||||||
|
|
||||||
|
// TODO: check server_address_id_cache_map
|
||||||
|
(void)self;
|
||||||
|
// TODO: save server info to user's db
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
12
src/cli/ClientCLI/ClientCLI.h
Normal file
12
src/cli/ClientCLI/ClientCLI.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "tcp-chat/client.h"
|
||||||
|
#include "db/idb.h"
|
||||||
|
|
||||||
|
typedef struct ClientCLI {
|
||||||
|
Client* client;
|
||||||
|
IncrementalDB* user_db;
|
||||||
|
} ClientCLI;
|
||||||
|
|
||||||
|
void ClientCLI_construct(ClientCLI* self);
|
||||||
|
void ClientCLI_destroy(ClientCLI* self);
|
||||||
|
Result(void) ClientCLI_run(ClientCLI* self);
|
||||||
14
src/cli/ClientCLI/db_tables.h
Normal file
14
src/cli/ClientCLI/db_tables.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "tcp-chat/common_constants.h"
|
||||||
|
#include "tlibc/time.h"
|
||||||
|
|
||||||
|
typedef struct ServerInfo {
|
||||||
|
char address[HOSTADDR_SIZE_MAX + 1];
|
||||||
|
u16 address_len;
|
||||||
|
char pk_base64[PUBLIC_KEY_BASE64_SIZE_MAX + 1];
|
||||||
|
u32 pk_base64_len;
|
||||||
|
char name[CHANNEL_NAME_SIZE_MAX + 1];
|
||||||
|
u16 name_len;
|
||||||
|
char desc[CHANNEL_DESC_SIZE_MAX + 1];
|
||||||
|
u16 desc_len;
|
||||||
|
} ATTRIBUTE_ALIGNED(16*1024) ServerInfo;
|
||||||
63
src/main.c → src/cli/main.c
Executable file → Normal file
63
src/main.c → src/cli/main.c
Executable file → Normal file
@ -1,12 +1,16 @@
|
|||||||
#include "network/network.h"
|
|
||||||
#include "client/client.h"
|
|
||||||
#include "server/server.h"
|
|
||||||
#include "tlibc/tlibc.h"
|
#include "tlibc/tlibc.h"
|
||||||
#include "tlibc/base64.h"
|
#include "tlibc/base64.h"
|
||||||
|
#include "tlibc/filesystem.h"
|
||||||
|
#include "tlibc/time.h"
|
||||||
|
#include "network/network.h"
|
||||||
|
#include "cli/ClientCLI/ClientCLI.h"
|
||||||
|
#include "server/server_internal.h"
|
||||||
|
|
||||||
#define _DEFAULT_CONFIG_PATH_CLIENT "tcp-chat-client.config"
|
#define _DEFAULT_CONFIG_PATH_CLIENT "tcp-chat-client.config"
|
||||||
#define _DEFAULT_CONFIG_PATH_SERVER "tcp-chat-server.config"
|
#define _DEFAULT_CONFIG_PATH_SERVER "tcp-chat-server.config"
|
||||||
|
|
||||||
|
#define arg_is(LITERAL) str_equals(arg_str, STR(LITERAL))
|
||||||
|
|
||||||
typedef enum ProgramMode {
|
typedef enum ProgramMode {
|
||||||
ClientMode,
|
ClientMode,
|
||||||
ServerMode,
|
ServerMode,
|
||||||
@ -16,7 +20,24 @@ typedef enum ProgramMode {
|
|||||||
RandomBytesBase64,
|
RandomBytesBase64,
|
||||||
} ProgramMode;
|
} ProgramMode;
|
||||||
|
|
||||||
#define arg_is(LITERAL) str_equals(arg_str, STR(LITERAL))
|
static void log_func(void* logger, LogSeverity severity, cstr context, cstr msg){
|
||||||
|
(void)logger;
|
||||||
|
|
||||||
|
cstr severity_cstr;
|
||||||
|
switch(severity){
|
||||||
|
default: severity_cstr = "INVALID_LOG_SEVERITY"; break;
|
||||||
|
case LogSeverity_Debug: severity_cstr = "DBUG"; break;
|
||||||
|
case LogSeverity_Info: severity_cstr = "INFO"; break;
|
||||||
|
case LogSeverity_Warn: severity_cstr = "WARN"; break;
|
||||||
|
case LogSeverity_Error: severity_cstr = "ERRR"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime dt;
|
||||||
|
DateTime_getLocal(&dt);
|
||||||
|
|
||||||
|
printf("[" FMT_DateTime_text "][%s/%s]: %s\n", DT_expand(dt), context, severity_cstr, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(const int argc, cstr const* argv){
|
int main(const int argc, cstr const* argv){
|
||||||
Deferral(32);
|
Deferral(32);
|
||||||
@ -141,9 +162,10 @@ int main(const int argc, cstr const* argv){
|
|||||||
if(!config_path)
|
if(!config_path)
|
||||||
config_path = _DEFAULT_CONFIG_PATH_CLIENT;
|
config_path = _DEFAULT_CONFIG_PATH_CLIENT;
|
||||||
|
|
||||||
try_fatal(Client* client, p, Client_createFromConfig(config_path));
|
ClientCLI client;
|
||||||
Defer(Client_free(client));
|
ClientCLI_construct(&client);
|
||||||
try_fatal_void(Client_run(client));
|
Defer(ClientCLI_destroy(&client));
|
||||||
|
try_fatal_void(ClientCLI_run(&client));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,8 +173,23 @@ int main(const int argc, cstr const* argv){
|
|||||||
if(!config_path)
|
if(!config_path)
|
||||||
config_path = _DEFAULT_CONFIG_PATH_SERVER;
|
config_path = _DEFAULT_CONFIG_PATH_SERVER;
|
||||||
|
|
||||||
try_fatal(Server* server, p, Server_createFromConfig(config_path));
|
// open file
|
||||||
|
try_fatal(FILE* config_file, p, file_open(config_path, FO_ReadExisting));
|
||||||
|
Defer(file_close(config_file));
|
||||||
|
// read whole file into str
|
||||||
|
Array(u8) config_buf = Array_null;
|
||||||
|
try_fatal_void(file_readWhole(config_file, &config_buf));
|
||||||
|
Defer(Array_free(config_buf));
|
||||||
|
str config_str = Array_castTo_str(config_buf, false);
|
||||||
|
config_buf.data = NULL;
|
||||||
|
// init server
|
||||||
|
try_fatal(Server* server, p, Server_create(config_str, NULL, log_func));
|
||||||
Defer(Server_free(server));
|
Defer(Server_free(server));
|
||||||
|
// manually close file and free config_buf
|
||||||
|
file_close(config_file);
|
||||||
|
config_file = NULL;
|
||||||
|
Array_free(config_buf);
|
||||||
|
// start infinite loop on main thread
|
||||||
try_fatal_void(Server_run(server));
|
try_fatal_void(Server_run(server));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -160,7 +197,7 @@ int main(const int argc, cstr const* argv){
|
|||||||
case RsaGenStdin: {
|
case RsaGenStdin: {
|
||||||
printfe("reading stdin...\n");
|
printfe("reading stdin...\n");
|
||||||
Array(u8) input_buf = Array_alloc_size(64*1024);
|
Array(u8) input_buf = Array_alloc_size(64*1024);
|
||||||
Defer(free(input_buf.data));
|
Defer(Array_free(input_buf));
|
||||||
br_hmac_drbg_context rng = { .vtable = &br_hmac_drbg_vtable };
|
br_hmac_drbg_context rng = { .vtable = &br_hmac_drbg_vtable };
|
||||||
br_hmac_drbg_init(&rng, &br_sha256_vtable, NULL, 0);
|
br_hmac_drbg_init(&rng, &br_sha256_vtable, NULL, 0);
|
||||||
i64 read_n = 0;
|
i64 read_n = 0;
|
||||||
@ -184,11 +221,11 @@ int main(const int argc, cstr const* argv){
|
|||||||
|
|
||||||
str sk_str = RSA_serializePrivateKey_base64(&sk);
|
str sk_str = RSA_serializePrivateKey_base64(&sk);
|
||||||
printf("rsa_private_key = %s\n", sk_str.data);
|
printf("rsa_private_key = %s\n", sk_str.data);
|
||||||
free(sk_str.data);
|
str_free(sk_str);
|
||||||
|
|
||||||
str pk_str = RSA_serializePublicKey_base64(&pk);
|
str pk_str = RSA_serializePublicKey_base64(&pk);
|
||||||
printf("\nrsa_public_key = %s\n", pk_str.data);
|
printf("\nrsa_public_key = %s\n", pk_str.data);
|
||||||
free(pk_str.data);
|
str_free(pk_str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,11 +241,11 @@ int main(const int argc, cstr const* argv){
|
|||||||
|
|
||||||
str sk_str = RSA_serializePrivateKey_base64(&sk);
|
str sk_str = RSA_serializePrivateKey_base64(&sk);
|
||||||
printf("rsa_private_key = %s\n", sk_str.data);
|
printf("rsa_private_key = %s\n", sk_str.data);
|
||||||
free(sk_str.data);
|
str_free(sk_str);
|
||||||
|
|
||||||
str pk_str = RSA_serializePublicKey_base64(&pk);
|
str pk_str = RSA_serializePublicKey_base64(&pk);
|
||||||
printf("\nrsa_public_key = %s\n", pk_str.data);
|
printf("\nrsa_public_key = %s\n", pk_str.data);
|
||||||
free(pk_str.data);
|
str_free(pk_str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
182
src/cli/term.c
Normal file
182
src/cli/term.c
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
#include "term.h"
|
||||||
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
#define try_win_bool(EXPR) if(!(EXPR)) { Return RESULT_ERROR_FMT(#EXPR " failed with WindowsError %lu", GetLastError()); }
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#define try_zero_errno(EXPR) if((EXPR) != 0) { Return RESULT_ERROR_FMT(#EXPR " failed with errno: %s", strerror(errno)); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Result(void) term_init(){
|
||||||
|
Deferral(8);
|
||||||
|
|
||||||
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
|
DWORD mode = 0;
|
||||||
|
HANDLE console_handle;
|
||||||
|
|
||||||
|
// configure stdout
|
||||||
|
console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
try_assert(console_handle != INVALID_HANDLE_VALUE);
|
||||||
|
GetConsoleMode(console_handle, &mode);
|
||||||
|
// https://learn.microsoft.com/en-us/windows/console/setconsolemode
|
||||||
|
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
|
mode |= ENABLE_PROCESSED_OUTPUT;
|
||||||
|
mode |= DISABLE_NEWLINE_AUTO_RETURN;
|
||||||
|
SetConsoleMode(console_handle, mode);
|
||||||
|
|
||||||
|
// configure stderr
|
||||||
|
console_handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
try_assert(console_handle != INVALID_HANDLE_VALUE);
|
||||||
|
GetConsoleMode(console_handle, &mode);
|
||||||
|
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
|
mode |= ENABLE_PROCESSED_OUTPUT;
|
||||||
|
mode |= DISABLE_NEWLINE_AUTO_RETURN;
|
||||||
|
SetConsoleMode(console_handle, mode);
|
||||||
|
|
||||||
|
// configure stdin
|
||||||
|
console_handle = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
try_assert(console_handle != INVALID_HANDLE_VALUE);
|
||||||
|
GetConsoleMode(console_handle, &mode);
|
||||||
|
mode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
|
||||||
|
SetConsoleMode(console_handle, mode);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
i64 getenv_int(const char* var_name){
|
||||||
|
char* s = getenv(var_name);
|
||||||
|
if(s == NULL)
|
||||||
|
return -1;
|
||||||
|
return strtoll(s, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) term_getSize(TerminalSize* out) {
|
||||||
|
Deferral(4);
|
||||||
|
|
||||||
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
|
// helps when STD_OUT is redirected to a file
|
||||||
|
HANDLE console_handle_stderr = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
try_assert(console_handle_stderr != INVALID_HANDLE_VALUE)
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
|
||||||
|
try_win_bool(GetConsoleScreenBufferInfo(console_handle_stderr, &consoleInfo));
|
||||||
|
|
||||||
|
out->cols = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1;
|
||||||
|
out->rows = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1;
|
||||||
|
#else
|
||||||
|
struct winsize ws = {0};
|
||||||
|
// try to get terminal size from stdin, stdout, stderr
|
||||||
|
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0 ||
|
||||||
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 ||
|
||||||
|
ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == 0 ){
|
||||||
|
out->cols = ws.ws_col;
|
||||||
|
out->rows = ws.ws_row;
|
||||||
|
}
|
||||||
|
// try to get size from environtent variables
|
||||||
|
else {
|
||||||
|
out->cols = getenv_int("COLUMNS");
|
||||||
|
out->rows = getenv_int("LINES");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
try_assert(out->cols > 0);
|
||||||
|
try_assert(out->rows > 0);
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) term_readLine(char* buf, u32 bufsize) {
|
||||||
|
Deferral(1);
|
||||||
|
try_assert(fgets(buf, bufsize, stdin) != NULL);
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) term_readLineHidden(char *buf, u32 bufsize) {
|
||||||
|
Deferral(4);
|
||||||
|
|
||||||
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
|
HANDLE console_handle_stdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
try_assert(console_handle_stdin != INVALID_HANDLE_VALUE);
|
||||||
|
DWORD old_mode;
|
||||||
|
GetConsoleMode(console_handle_stdin, &old_mode);
|
||||||
|
// turn off echo
|
||||||
|
DWORD new_mode = old_mode & ~(ENABLE_ECHO_INPUT);
|
||||||
|
SetConsoleMode(console_handle_stdin, new_mode);
|
||||||
|
// restore echo
|
||||||
|
Defer(SetConsoleMode(console_handle_stdin, old_mode));
|
||||||
|
#else
|
||||||
|
struct termios old_mode, new_mode;
|
||||||
|
try_zero_errno(tcgetattr(STDIN_FILENO, &old_mode));
|
||||||
|
new_mode = old_mode;
|
||||||
|
// turn off echo
|
||||||
|
new_mode.c_lflag &= ~(ECHO);
|
||||||
|
try_zero_errno(tcsetattr(STDIN_FILENO, TCSAFLUSH, &new_mode));
|
||||||
|
// restore echo
|
||||||
|
Defer(tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_mode));
|
||||||
|
#endif
|
||||||
|
// read line
|
||||||
|
try_void(term_readLine(buf, bufsize));
|
||||||
|
fputchar('\n');
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Most of escape sequences can be found there
|
||||||
|
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
|
||||||
|
*/
|
||||||
|
#define ESC "\x1b"
|
||||||
|
#define CSI ESC"["
|
||||||
|
|
||||||
|
void term_setFgColor16(Color16 c){
|
||||||
|
printf(CSI"%um", c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_setBgColor16(Color16 c){
|
||||||
|
printf(CSI"%um", c + 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_bold(){
|
||||||
|
printf(CSI"1m");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_italic(){
|
||||||
|
printf(CSI"3m");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_underline(){
|
||||||
|
printf(CSI"4m");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_strikethrough(){
|
||||||
|
printf(CSI"9m");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_resetCursor() {
|
||||||
|
printf(CSI"H");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_resetColors() {
|
||||||
|
printf(CSI"0m");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_clear() {
|
||||||
|
printf(CSI"0m" CSI"H" CSI"2J");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_eraseRow(){
|
||||||
|
printf(CSI"2K\r");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_cursorMove(u16 row, u16 column) {
|
||||||
|
printf(CSI"%u;%uH", row, column);
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_cursorHide() {
|
||||||
|
printf(CSI"?25l");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_cursorShow() {
|
||||||
|
printf(CSI"?25h");
|
||||||
|
}
|
||||||
47
src/cli/term.h
Normal file
47
src/cli/term.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "tlibc/errors.h"
|
||||||
|
|
||||||
|
typedef struct TerminalSize {
|
||||||
|
i16 cols;
|
||||||
|
i16 rows;
|
||||||
|
} TerminalSize;
|
||||||
|
|
||||||
|
typedef enum Color16 {
|
||||||
|
Color16_Black = 30,
|
||||||
|
Color16_DarkRed = 31,
|
||||||
|
Color16_DarkGreen = 32,
|
||||||
|
Color16_DarkYellow = 33,
|
||||||
|
Color16_DarkBlue = 34,
|
||||||
|
Color16_DarkMagenta = 35,
|
||||||
|
Color16_DarkCyan = 36,
|
||||||
|
Color16_Gray = 37,
|
||||||
|
Color16_DarkGray = 90,
|
||||||
|
Color16_Red = 91,
|
||||||
|
Color16_Green = 92,
|
||||||
|
Color16_Yellow = 93,
|
||||||
|
Color16_Blue = 94,
|
||||||
|
Color16_Magenta = 95,
|
||||||
|
Color16_Cyan = 96,
|
||||||
|
Color16_White = 97
|
||||||
|
} Color16;
|
||||||
|
|
||||||
|
Result(void) term_init();
|
||||||
|
Result(void) term_getSize(TerminalSize* out);
|
||||||
|
|
||||||
|
Result(void) term_readLine(char* buf, u32 bufsize);
|
||||||
|
Result(void) term_readLineHidden(char *buf, u32 bufsize);
|
||||||
|
|
||||||
|
void term_setFgColor16(Color16 c);
|
||||||
|
void term_setBgColor16(Color16 c);
|
||||||
|
void term_bold();
|
||||||
|
void term_italic();
|
||||||
|
void term_underline();
|
||||||
|
void term_strikethrough();
|
||||||
|
void term_resetColors();
|
||||||
|
|
||||||
|
void term_clear();
|
||||||
|
void term_eraseRow();
|
||||||
|
void term_resetCursor();
|
||||||
|
void term_cursorMove(u16 row, u16 column);
|
||||||
|
void term_cursorHide();
|
||||||
|
void term_cursorShow();
|
||||||
@ -1,44 +0,0 @@
|
|||||||
#include "client.h"
|
|
||||||
#include "tlibc/collections/List.h"
|
|
||||||
|
|
||||||
void ClientCredentials_destroy(ClientCredentials* cred){
|
|
||||||
if(!cred)
|
|
||||||
return;
|
|
||||||
free(cred->username.data);
|
|
||||||
free(cred->user_data_key.data);
|
|
||||||
free(cred->token.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Result(void) ClientCredentials_tryConstruct(ClientCredentials* cred,
|
|
||||||
str username, str password)
|
|
||||||
{
|
|
||||||
Deferral(8);
|
|
||||||
|
|
||||||
memset(cred, 0, sizeof(ClientCredentials));
|
|
||||||
bool success = false;
|
|
||||||
Defer(if(!success) ClientCredentials_destroy(cred));
|
|
||||||
|
|
||||||
cred->username = str_copy(username);
|
|
||||||
|
|
||||||
// concat password and username
|
|
||||||
List(u8) data_to_hash = List_alloc_size(password.size + username.size + PASSWORD_HASH_SIZE);
|
|
||||||
Defer(free(data_to_hash.data));
|
|
||||||
List_push_size(&data_to_hash, password.data, password.size);
|
|
||||||
List_push_size(&data_to_hash, username.data, username.size);
|
|
||||||
|
|
||||||
// lvl 1 hash - is used as AES key for user data
|
|
||||||
cred->user_data_key = Array_alloc(u8, PASSWORD_HASH_SIZE);
|
|
||||||
hash_password(List_castTo_Array(data_to_hash), cred->user_data_key.data, PASSWORD_HASH_LVL_ROUNDS);
|
|
||||||
// concat lvl 1 hash to data_to_hash
|
|
||||||
List_push_size(&data_to_hash, cred->user_data_key.data, cred->user_data_key.size);
|
|
||||||
// lvl 2 hash - is used for authentification
|
|
||||||
cred->token = Array_alloc(u8, PASSWORD_HASH_SIZE);
|
|
||||||
hash_password(List_castTo_Array(data_to_hash), cred->token.data, PASSWORD_HASH_LVL_ROUNDS);
|
|
||||||
|
|
||||||
AESBlockEncryptor_construct(&cred->user_data_aes_enc, cred->user_data_key, AESBlockEncryptor_DEFAULT_CLASS);
|
|
||||||
AESBlockDecryptor_construct(&cred->user_data_aes_dec, cred->user_data_key, AESBlockDecryptor_DEFAULT_CLASS);
|
|
||||||
|
|
||||||
success = true;
|
|
||||||
Return RESULT_VOID;
|
|
||||||
}
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
#include "client.h"
|
#include "client_internal.h"
|
||||||
#include "requests/requests.h"
|
#include "requests/requests.h"
|
||||||
|
|
||||||
void ServerConnection_close(ServerConnection* conn){
|
void ServerConnection_close(ServerConnection* conn){
|
||||||
@ -6,44 +6,14 @@ void ServerConnection_close(ServerConnection* conn){
|
|||||||
return;
|
return;
|
||||||
RSA_destroyPublicKey(&conn->server_pk);
|
RSA_destroyPublicKey(&conn->server_pk);
|
||||||
EncryptedSocketTCP_destroy(&conn->sock);
|
EncryptedSocketTCP_destroy(&conn->sock);
|
||||||
free(conn->session_key.data);
|
Array_free(conn->session_key);
|
||||||
free(conn->name.data);
|
str_free(conn->server_name);
|
||||||
free(conn->description.data);
|
str_free(conn->server_description);
|
||||||
free(conn);
|
free(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief
|
Result(ServerConnection*) ServerConnection_open(cstr server_addr_cstr, cstr server_pk_base64)
|
||||||
/// @param server_link_cstr address:port:public_key
|
{
|
||||||
/// @return
|
|
||||||
Result(void) ServerLink_parse(cstr server_link_cstr, EndpointIPv4* server_end_out, br_rsa_public_key* server_key_out){
|
|
||||||
Deferral(8);
|
|
||||||
str server_link_str = str_from_cstr(server_link_cstr);
|
|
||||||
|
|
||||||
// parse address and port
|
|
||||||
i32 sep_pos = str_seekChar(server_link_str, ':', 0);
|
|
||||||
if(sep_pos == -1){
|
|
||||||
Return RESULT_ERROR_FMT("server link is invalid: %s", server_link_cstr);
|
|
||||||
}
|
|
||||||
*server_end_out = EndpointIPv4_INVALID;
|
|
||||||
try_void(EndpointIPv4_parse(server_link_cstr, server_end_out));
|
|
||||||
if(EndpointIPv4_is_invalid(*server_end_out)){
|
|
||||||
Return RESULT_ERROR_FMT("server address or port is invalid: %s", server_link_cstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse public key
|
|
||||||
sep_pos = str_seekChar(server_link_str, ':', sep_pos + 1);
|
|
||||||
if(sep_pos == -1){
|
|
||||||
Return RESULT_ERROR_FMT("server link is invalid: %s", server_link_cstr);
|
|
||||||
}
|
|
||||||
str server_key_str = str_sliceAfter(server_link_str, sep_pos + 1);
|
|
||||||
char* server_key_cstr = str_copy(server_key_str).data;
|
|
||||||
Defer(free(server_key_cstr));
|
|
||||||
try_void(RSA_parsePublicKey_base64(server_key_cstr, server_key_out));
|
|
||||||
|
|
||||||
Return RESULT_VOID;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result(ServerConnection*) ServerConnection_open(cstr server_link_cstr){
|
|
||||||
Deferral(16);
|
Deferral(16);
|
||||||
|
|
||||||
ServerConnection* conn = (ServerConnection*)malloc(sizeof(ServerConnection));
|
ServerConnection* conn = (ServerConnection*)malloc(sizeof(ServerConnection));
|
||||||
@ -51,7 +21,14 @@ Result(ServerConnection*) ServerConnection_open(cstr server_link_cstr){
|
|||||||
bool success = false;
|
bool success = false;
|
||||||
Defer(if(!success) ServerConnection_close(conn));
|
Defer(if(!success) ServerConnection_close(conn));
|
||||||
|
|
||||||
try_void(ServerLink_parse(server_link_cstr, &conn->server_end, &conn->server_pk));
|
// TODO: parse domain name and get ip from it
|
||||||
|
conn->server_end = EndpointIPv4_INVALID;
|
||||||
|
try_void(EndpointIPv4_parse(server_addr_cstr, &conn->server_end));
|
||||||
|
if(EndpointIPv4_is_invalid(conn->server_end)){
|
||||||
|
Return RESULT_ERROR_FMT("server address or port is invalid: %s", server_addr_cstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
try_void(RSA_parsePublicKey_base64(server_pk_base64, &conn->server_pk));
|
||||||
RSAEncryptor_construct(&conn->rsa_enc, &conn->server_pk);
|
RSAEncryptor_construct(&conn->rsa_enc, &conn->server_pk);
|
||||||
|
|
||||||
conn->session_key = Array_alloc_size(AES_SESSION_KEY_SIZE);
|
conn->session_key = Array_alloc_size(AES_SESSION_KEY_SIZE);
|
||||||
@ -82,6 +59,21 @@ Result(ServerConnection*) ServerConnection_open(cstr server_link_cstr){
|
|||||||
conn->session_id = server_handshake.session_id;
|
conn->session_id = server_handshake.session_id;
|
||||||
|
|
||||||
// get server name
|
// get server name
|
||||||
|
try_void(ServerConnection_requestServerName(conn));
|
||||||
|
// get server description
|
||||||
|
try_void(ServerConnection_requestServerDescription(conn));
|
||||||
|
|
||||||
|
success = true;
|
||||||
|
Return RESULT_VALUE(p, conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) ServerConnection_requestServerName(ServerConnection* conn){
|
||||||
|
if(conn == NULL){
|
||||||
|
return RESULT_ERROR("Client is not connected to a server", false);
|
||||||
|
}
|
||||||
|
Deferral(4);
|
||||||
|
|
||||||
|
PacketHeader req_header, res_header;
|
||||||
ServerPublicInfoRequest public_info_req;
|
ServerPublicInfoRequest public_info_req;
|
||||||
ServerPublicInfoResponse public_info_res;
|
ServerPublicInfoResponse public_info_res;
|
||||||
ServerPublicInfoRequest_construct(&public_info_req, &req_header,
|
ServerPublicInfoRequest_construct(&public_info_req, &req_header,
|
||||||
@ -89,16 +81,26 @@ Result(ServerConnection*) ServerConnection_open(cstr server_link_cstr){
|
|||||||
try_void(sendRequest(&conn->sock, &req_header, &public_info_req));
|
try_void(sendRequest(&conn->sock, &req_header, &public_info_req));
|
||||||
try_void(recvResponse(&conn->sock, &res_header, &public_info_res,
|
try_void(recvResponse(&conn->sock, &res_header, &public_info_res,
|
||||||
PacketType_ServerPublicInfoResponse));
|
PacketType_ServerPublicInfoResponse));
|
||||||
try_void(recvStr(&conn->sock, public_info_res.data_size, &conn->name));
|
try_void(recvStr(&conn->sock, public_info_res.data_size, &conn->server_name));
|
||||||
|
|
||||||
// get server description
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) ServerConnection_requestServerDescription(ServerConnection* conn){
|
||||||
|
if(conn == NULL){
|
||||||
|
return RESULT_ERROR("Client is not connected to a server", false);
|
||||||
|
}
|
||||||
|
Deferral(4);
|
||||||
|
|
||||||
|
PacketHeader req_header, res_header;
|
||||||
|
ServerPublicInfoRequest public_info_req;
|
||||||
|
ServerPublicInfoResponse public_info_res;
|
||||||
ServerPublicInfoRequest_construct(&public_info_req, &req_header,
|
ServerPublicInfoRequest_construct(&public_info_req, &req_header,
|
||||||
ServerPublicInfo_Description);
|
ServerPublicInfo_Description);
|
||||||
try_void(sendRequest(&conn->sock, &req_header, &public_info_req));
|
try_void(sendRequest(&conn->sock, &req_header, &public_info_req));
|
||||||
try_void(recvResponse(&conn->sock, &res_header, &public_info_res,
|
try_void(recvResponse(&conn->sock, &res_header, &public_info_res,
|
||||||
PacketType_ServerPublicInfoResponse));
|
PacketType_ServerPublicInfoResponse));
|
||||||
try_void(recvStr(&conn->sock, public_info_res.data_size, &conn->description));
|
try_void(recvStr(&conn->sock, public_info_res.data_size, &conn->server_description));
|
||||||
|
|
||||||
success = true;
|
Return RESULT_VOID;
|
||||||
Return RESULT_VALUE(p, conn);
|
}
|
||||||
}
|
|
||||||
@ -1,180 +1,79 @@
|
|||||||
#include "client.h"
|
#include "client/client_internal.h"
|
||||||
#include "term.h"
|
|
||||||
#include "tlibc/time.h"
|
|
||||||
#include "network/tcp-chat-protocol/v1.h"
|
|
||||||
|
|
||||||
static const str greeting_art = STR(
|
void Client_free(Client* self){
|
||||||
" ^,,^ ╱|\n"
|
if(!self)
|
||||||
" ( •·•) Meum! (o.o`7\n"
|
|
||||||
" / ` | Meum... |`˜ \\\n"
|
|
||||||
"\\(_,J J L l`,)/\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
static const str farewell_art = STR(
|
|
||||||
" ^,,^ ╱|\n"
|
|
||||||
" ( -.-) (>,<`7\n"
|
|
||||||
" / ` | Goodbye! |`˜ \\\n"
|
|
||||||
"\\(_,J J L l`,)/\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
Result(void) Client_createFromConfig(cstr config_path){
|
|
||||||
Deferral(16);
|
|
||||||
|
|
||||||
Client* client = (Client*)malloc(sizeof(Client));
|
|
||||||
memset(client, 0, sizeof(Client));
|
|
||||||
bool success = false;
|
|
||||||
Defer(if(!success) Client_free(client));
|
|
||||||
|
|
||||||
(void)config_path;
|
|
||||||
|
|
||||||
success = true;
|
|
||||||
Return RESULT_VALUE(p, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client_free(Client* client){
|
|
||||||
if(!client)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ClientCredentials_destroy(&client->cred);
|
str_free(self->username);
|
||||||
ServerConnection_close(client->server_connection);
|
Array_free(self->token);
|
||||||
free(client);
|
Array_free(self->user_data_key);
|
||||||
|
ServerConnection_close(self->server_connection);
|
||||||
|
free(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result(void) commandExec(Client* client, str command, bool* stop);
|
Result(Client*) Client_create(str username, str password){
|
||||||
|
|
||||||
static Result(void) askUserNameAndPassword(ClientCredentials* cred){
|
|
||||||
Deferral(8);
|
|
||||||
|
|
||||||
char username_buf[128];
|
|
||||||
str username = str_null;
|
|
||||||
while(true) {
|
|
||||||
printf("username: ");
|
|
||||||
if(fgets(username_buf, sizeof(username_buf), stdin) == NULL){
|
|
||||||
Return RESULT_ERROR("STDIN is closed", false);
|
|
||||||
}
|
|
||||||
username = str_from_cstr(username_buf);
|
|
||||||
str_trim(&username, true);
|
|
||||||
if(username.size < USERNAME_SIZE_MIN || username.size > USERNAME_SIZE_MAX){
|
|
||||||
printf("ERROR: username length (in bytes) must be >= %i and <= %i\n",
|
|
||||||
USERNAME_SIZE_MIN, USERNAME_SIZE_MAX);
|
|
||||||
}
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
|
|
||||||
char password_buf[128];
|
|
||||||
str password = str_null;
|
|
||||||
while(true) {
|
|
||||||
printf("password: ");
|
|
||||||
// TODO: hide password
|
|
||||||
if(fgets(password_buf, sizeof(password_buf), stdin) == NULL){
|
|
||||||
Return RESULT_ERROR("STDIN is closed", false);
|
|
||||||
}
|
|
||||||
password = str_from_cstr(password_buf);
|
|
||||||
str_trim(&password, true);
|
|
||||||
if(password.size < PASSWORD_SIZE_MIN || password.size > PASSWORD_SIZE_MAX){
|
|
||||||
printf("ERROR: password length (in bytes) must be >= %i and <= %i\n",
|
|
||||||
PASSWORD_SIZE_MIN, PASSWORD_SIZE_MAX);
|
|
||||||
}
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
|
|
||||||
try_void(ClientCredentials_tryConstruct(cred, username, password));
|
|
||||||
Return RESULT_VOID;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result(void) Client_run(Client* client) {
|
|
||||||
Deferral(16);
|
Deferral(16);
|
||||||
if(!term_init()){
|
|
||||||
Return RESULT_ERROR("can't init terminal", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs(greeting_art.data, stdout);
|
Client* self = (Client*)malloc(sizeof(Client));
|
||||||
try_void(askUserNameAndPassword(&client->cred));
|
memset(self, 0, sizeof(Client));
|
||||||
|
bool success = false;
|
||||||
|
Defer(if(!success) Client_free(self));
|
||||||
|
|
||||||
Array(char) input_buf = Array_alloc(char, 10000);
|
self->username = str_copy(username);
|
||||||
Defer(free(input_buf.data));
|
|
||||||
str command_input = str_null;
|
|
||||||
bool stop = false;
|
|
||||||
while(!stop){
|
|
||||||
sleepMsec(50);
|
|
||||||
fputs("> ", stdout);
|
|
||||||
if(fgets(input_buf.data, input_buf.size, stdin) == NULL){
|
|
||||||
Return RESULT_ERROR("STDIN is closed", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
command_input = str_from_cstr(input_buf.data);
|
|
||||||
str_trim(&command_input, true);
|
|
||||||
if(command_input.size == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ResultVar(void) com_result = commandExec(client, command_input, &stop);
|
|
||||||
if(com_result.error){
|
|
||||||
str e_str = Error_toStr(com_result.error);
|
|
||||||
printf("%s\n", e_str.data);
|
|
||||||
free(e_str.data);
|
|
||||||
Error_free(com_result.error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// concat password and username
|
||||||
|
List(u8) data_to_hash = List_alloc_size(password.size + username.size + PASSWORD_HASH_SIZE);
|
||||||
|
Defer(free(data_to_hash.data));
|
||||||
|
List_push_size(&data_to_hash, password.data, password.size);
|
||||||
|
List_push_size(&data_to_hash, username.data, username.size);
|
||||||
|
|
||||||
|
// lvl 1 hash - is used as AES key for user data
|
||||||
|
self->user_data_key = Array_alloc(u8, PASSWORD_HASH_SIZE);
|
||||||
|
hash_password(List_castTo_Array(data_to_hash), self->user_data_key.data, PASSWORD_HASH_LVL_ROUNDS);
|
||||||
|
// concat lvl 1 hash to data_to_hash
|
||||||
|
List_push_size(&data_to_hash, self->user_data_key.data, self->user_data_key.size);
|
||||||
|
// lvl 2 hash - is used for authentification
|
||||||
|
self->token = Array_alloc(u8, PASSWORD_HASH_SIZE);
|
||||||
|
// TODO: generate different token for each server
|
||||||
|
hash_password(List_castTo_Array(data_to_hash), self->token.data, PASSWORD_HASH_LVL_ROUNDS);
|
||||||
|
|
||||||
|
success = true;
|
||||||
|
Return RESULT_VALUE(p, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) Client_connect(Client* self, cstr server_addr_cstr, cstr server_pk_base64){
|
||||||
|
Deferral(8);
|
||||||
|
Client_disconnect(self);
|
||||||
|
try(self->server_connection, p,
|
||||||
|
ServerConnection_open(server_addr_cstr, server_pk_base64));
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define is_alias(LITERAL) str_equals(command, STR(LITERAL))
|
void Client_disconnect(Client* self){
|
||||||
|
ServerConnection_close(self->server_connection);
|
||||||
static Result(void) commandExec(Client* client, str command, bool* stop){
|
self->server_connection = NULL;
|
||||||
Deferral(64);
|
|
||||||
char answer_buf[10000];
|
|
||||||
const u32 answer_buf_size = sizeof(answer_buf);
|
|
||||||
if(is_alias("q") || is_alias("quit") || is_alias("exit")){
|
|
||||||
fputs(farewell_art.data, stdout);
|
|
||||||
*stop = true;
|
|
||||||
}
|
|
||||||
else if(is_alias("clear")){
|
|
||||||
term_clear();
|
|
||||||
}
|
|
||||||
else if(is_alias("h") || is_alias("help")){
|
|
||||||
puts(
|
|
||||||
"COMMANDS:\n"
|
|
||||||
"h, help Show this message.\n"
|
|
||||||
"q, quit, exit Close the program.\n"
|
|
||||||
"clear Clear the screen.\n"
|
|
||||||
"j, join Join a server.\n"
|
|
||||||
"c, connect Connect to a server you joined.\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if (is_alias("j") || is_alias("join")){
|
|
||||||
ServerConnection_close(client->server_connection);
|
|
||||||
|
|
||||||
puts("Enter server address (ip:port:public_key): ");
|
|
||||||
if(fgets(answer_buf, answer_buf_size, stdin) == NULL){
|
|
||||||
Return RESULT_ERROR("STDIN is closed", false);
|
|
||||||
}
|
|
||||||
str new_server_link = str_from_cstr(answer_buf);
|
|
||||||
str_trim(&new_server_link, true);
|
|
||||||
|
|
||||||
printf("connecting to server...\n");
|
|
||||||
try(client->server_connection, p,
|
|
||||||
ServerConnection_open(new_server_link.data));
|
|
||||||
printf("connection established\n");
|
|
||||||
|
|
||||||
// TODO: show server info
|
|
||||||
// TODO: save server info to user's db
|
|
||||||
// TODO: ask in loop: log in / register
|
|
||||||
|
|
||||||
//TODO: call Client_runIO():
|
|
||||||
// function with infinite loop which sends and receives messages
|
|
||||||
// with navigation across server channels
|
|
||||||
}
|
|
||||||
else if(is_alias("c") || is_alias("connect")){
|
|
||||||
// TODO: read saved servers from database
|
|
||||||
// TODO: show scrollable list of servers, get selected one
|
|
||||||
// TODO: ask in loop: log in / register
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("ERROR: unknown command.\n"
|
|
||||||
"Use 'h' to see list of avaliable commands\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
Return RESULT_VOID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
str Client_getUserName(Client* client){
|
||||||
|
return client->username;
|
||||||
|
}
|
||||||
|
|
||||||
|
Array(u8) Client_getUserDataKey(Client* client){
|
||||||
|
return client->user_data_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) Client_getServerName(Client* self, str* out_name){
|
||||||
|
if(self->server_connection == NULL){
|
||||||
|
return RESULT_ERROR("Client is not connected to a server", false);
|
||||||
|
}
|
||||||
|
*out_name = self->server_connection->server_name;
|
||||||
|
return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) Client_getServerDescription(Client* self, str* out_desc){
|
||||||
|
if(self->server_connection == NULL){
|
||||||
|
return RESULT_ERROR("Client is not connected to a server", false);
|
||||||
|
}
|
||||||
|
*out_desc = self->server_connection->server_description;
|
||||||
|
return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,45 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "cryptography/AES.h"
|
|
||||||
#include "cryptography/RSA.h"
|
|
||||||
#include "network/encrypted_sockets.h"
|
|
||||||
#include "tlibc/string/str.h"
|
|
||||||
|
|
||||||
typedef struct Client Client;
|
|
||||||
|
|
||||||
typedef struct ClientCredentials {
|
|
||||||
str username;
|
|
||||||
Array(u8) user_data_key;
|
|
||||||
Array(u8) token;
|
|
||||||
AESBlockEncryptor user_data_aes_enc;
|
|
||||||
AESBlockDecryptor user_data_aes_dec;
|
|
||||||
} ClientCredentials;
|
|
||||||
|
|
||||||
Result(void) ClientCredentials_tryConstruct(ClientCredentials* cred,
|
|
||||||
str username, str password);
|
|
||||||
|
|
||||||
void ClientCredentials_destroy(ClientCredentials* cred);
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct ServerConnection {
|
|
||||||
EndpointIPv4 server_end;
|
|
||||||
br_rsa_public_key server_pk;
|
|
||||||
RSAEncryptor rsa_enc;
|
|
||||||
u64 session_id;
|
|
||||||
Array(u8) session_key;
|
|
||||||
EncryptedSocketTCP sock;
|
|
||||||
str name;
|
|
||||||
str description;
|
|
||||||
} ServerConnection;
|
|
||||||
|
|
||||||
Result(ServerConnection*) ServerConnection_open(cstr server_link_cstr);
|
|
||||||
void ServerConnection_close(ServerConnection* conn);
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct Client {
|
|
||||||
ClientCredentials cred;
|
|
||||||
ServerConnection* server_connection;
|
|
||||||
} Client;
|
|
||||||
|
|
||||||
Result(void) Client_createFromConfig(cstr config_path);
|
|
||||||
void Client_free(Client* client);
|
|
||||||
Result(void) Client_run(Client* client);
|
|
||||||
36
src/client/client_internal.h
Normal file
36
src/client/client_internal.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "tcp-chat/client.h"
|
||||||
|
#include "cryptography/AES.h"
|
||||||
|
#include "cryptography/RSA.h"
|
||||||
|
#include "network/encrypted_sockets.h"
|
||||||
|
|
||||||
|
typedef struct ServerConnection ServerConnection;
|
||||||
|
|
||||||
|
typedef struct Client {
|
||||||
|
str username;
|
||||||
|
Array(u8) user_data_key;
|
||||||
|
Array(u8) token;
|
||||||
|
ServerConnection* server_connection;
|
||||||
|
} Client;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct ServerConnection {
|
||||||
|
EndpointIPv4 server_end;
|
||||||
|
br_rsa_public_key server_pk;
|
||||||
|
RSAEncryptor rsa_enc;
|
||||||
|
u64 session_id;
|
||||||
|
Array(u8) session_key;
|
||||||
|
EncryptedSocketTCP sock;
|
||||||
|
str server_name;
|
||||||
|
str server_description;
|
||||||
|
} ServerConnection;
|
||||||
|
|
||||||
|
/// @param server_addr_cstr
|
||||||
|
/// @param server_pk_base64 public key encoded by `RSA_serializePublicKey_base64()`
|
||||||
|
Result(ServerConnection*) ServerConnection_open(cstr server_addr_cstr, cstr server_pk_base64);
|
||||||
|
void ServerConnection_close(ServerConnection* conn);
|
||||||
|
|
||||||
|
/// updates conn->server_name
|
||||||
|
Result(void) ServerConnection_requestServerName(ServerConnection* conn);
|
||||||
|
/// updates conn->server_description
|
||||||
|
Result(void) ServerConnection_requestServerDescription(ServerConnection* conn);
|
||||||
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "network/tcp-chat-protocol/v1.h"
|
#include "network/tcp-chat-protocol/v1.h"
|
||||||
#include "client/client.h"
|
#include "client/client_internal.h"
|
||||||
|
|
||||||
|
|
||||||
Result(void) recvErrorMessage(EncryptedSocketTCP* sock, PacketHeader* res_header,
|
Result(void) recvErrorMessage(EncryptedSocketTCP* sock, PacketHeader* res_header,
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "tlibc/std.h"
|
|
||||||
|
|
||||||
#define USERNAME_SIZE_MIN 2
|
|
||||||
#define USERNAME_SIZE_MAX 31
|
|
||||||
#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,7 +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"
|
#include "tcp-chat/common_constants.h"
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// //
|
// //
|
||||||
|
|||||||
12
src/db/idb.c
12
src/db/idb.c
@ -43,11 +43,11 @@ void Table_close(Table* t){
|
|||||||
return;
|
return;
|
||||||
fclose(t->table_file);
|
fclose(t->table_file);
|
||||||
fclose(t->changes_file);
|
fclose(t->changes_file);
|
||||||
free(t->name.data);
|
str_free(t->name);
|
||||||
free(t->table_file_path.data);
|
str_free(t->table_file_path);
|
||||||
free(t->changes_file_path.data);
|
str_free(t->changes_file_path);
|
||||||
pthread_mutex_destroy(&t->mutex);
|
pthread_mutex_destroy(&t->mutex);
|
||||||
free(t->enc_buf.data);
|
Array_free(t->enc_buf);
|
||||||
free(t);
|
free(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,8 +201,8 @@ Result(IncrementalDB*) idb_open(str db_dir, NULLABLE(Array(u8) aes_key)){
|
|||||||
void idb_close(IncrementalDB* db){
|
void idb_close(IncrementalDB* db){
|
||||||
if(db == NULL)
|
if(db == NULL)
|
||||||
return;
|
return;
|
||||||
free(db->db_dir.data);
|
str_free(db->db_dir);
|
||||||
free(db->aes_key.data);
|
Array_free(db->aes_key);
|
||||||
HashMap_destroy(&db->tables_map);
|
HashMap_destroy(&db->tables_map);
|
||||||
pthread_mutex_destroy(&db->mutex);
|
pthread_mutex_destroy(&db->mutex);
|
||||||
free(db);
|
free(db);
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#define log(context, severity, format, ...) printf("[%s/" severity "]: " format "\n", context ,##__VA_ARGS__)
|
|
||||||
#define logDebug(context, format, ...) log(context, "DEBUG", format ,##__VA_ARGS__)
|
|
||||||
#define logInfo(context, format, ...) log(context, "INFO", format ,##__VA_ARGS__)
|
|
||||||
#define logWarn(context, format, ...) log(context, "WARN", format ,##__VA_ARGS__)
|
|
||||||
#define logError(context, format, ...) log(context, "ERROR", format ,##__VA_ARGS__)
|
|
||||||
@ -18,8 +18,8 @@ void EncryptedSocketTCP_destroy(EncryptedSocketTCP* ptr){
|
|||||||
if(!ptr)
|
if(!ptr)
|
||||||
return;
|
return;
|
||||||
socket_close(ptr->sock);
|
socket_close(ptr->sock);
|
||||||
free(ptr->recv_buf.data);
|
Array_free(ptr->recv_buf);
|
||||||
free(ptr->send_buf.data);
|
Array_free(ptr->send_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncryptedSocketTCP_changeKey(EncryptedSocketTCP* ptr, Array(u8) aes_key){
|
void EncryptedSocketTCP_changeKey(EncryptedSocketTCP* ptr, Array(u8) aes_key){
|
||||||
@ -171,8 +171,8 @@ void EncryptedSocketUDP_destroy(EncryptedSocketUDP* ptr){
|
|||||||
if(!ptr)
|
if(!ptr)
|
||||||
return;
|
return;
|
||||||
socket_close(ptr->sock);
|
socket_close(ptr->sock);
|
||||||
free(ptr->recv_buf.data);
|
Array_free(ptr->recv_buf);
|
||||||
free(ptr->send_buf.data);
|
Array_free(ptr->send_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncryptedSocketUDP_changeKey(EncryptedSocketUDP* ptr, Array(u8) aes_key){
|
void EncryptedSocketUDP_changeKey(EncryptedSocketUDP* ptr, Array(u8) aes_key){
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "tlibc/errors.h"
|
#include "tlibc/errors.h"
|
||||||
#include "magic.h"
|
#include "magic.h"
|
||||||
#include "common_constants.h"
|
#include "tcp-chat/common_constants.h"
|
||||||
|
|
||||||
#define AES_SESSION_KEY_SIZE 32
|
#define AES_SESSION_KEY_SIZE 32
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
#include "server.h"
|
#include "server/server_internal.h"
|
||||||
#include "network/tcp-chat-protocol/v1.h"
|
#include "network/tcp-chat-protocol/v1.h"
|
||||||
|
|
||||||
void ClientConnection_close(ClientConnection* conn){
|
void ClientConnection_close(ClientConnection* conn){
|
||||||
if(!conn)
|
if(!conn)
|
||||||
return;
|
return;
|
||||||
EncryptedSocketTCP_destroy(&conn->sock);
|
EncryptedSocketTCP_destroy(&conn->sock);
|
||||||
free(conn->session_key.data);
|
Array_free(conn->session_key);
|
||||||
free(conn);
|
free(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ Result(ClientConnection*) ClientConnection_accept(ConnectionHandlerArgs* args)
|
|||||||
|
|
||||||
// decrypt the rsa messages using server private key
|
// decrypt the rsa messages using server private key
|
||||||
RSADecryptor rsa_dec;
|
RSADecryptor rsa_dec;
|
||||||
RSADecryptor_construct(&rsa_dec, &args->server->cred.rsa_sk);
|
RSADecryptor_construct(&rsa_dec, &args->server->rsa_sk);
|
||||||
|
|
||||||
// receive PacketHeader
|
// receive PacketHeader
|
||||||
PacketHeader packet_header;
|
PacketHeader packet_header;
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
#include "server.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Result(void) ServerCredentials_tryConstruct(ServerCredentials* cred,
|
|
||||||
cstr rsa_sk_base64, cstr rsa_pk_base64)
|
|
||||||
{
|
|
||||||
Deferral(4);
|
|
||||||
|
|
||||||
memset(cred, 0, sizeof(*cred));
|
|
||||||
bool success = false;
|
|
||||||
Defer(if(!success) ServerCredentials_destroy(cred));
|
|
||||||
|
|
||||||
try_void(RSA_parsePrivateKey_base64(rsa_sk_base64, &cred->rsa_sk));
|
|
||||||
try_void(RSA_parsePublicKey_base64(rsa_pk_base64, &cred->rsa_pk));
|
|
||||||
|
|
||||||
success = true;
|
|
||||||
Return RESULT_VOID;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerCredentials_destroy(ServerCredentials* cred){
|
|
||||||
if(!cred)
|
|
||||||
return;
|
|
||||||
RSA_destroyPrivateKey(&cred->rsa_sk);
|
|
||||||
RSA_destroyPublicKey(&cred->rsa_pk);
|
|
||||||
}
|
|
||||||
@ -1,17 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "common_constants.h"
|
#include "tcp-chat/common_constants.h"
|
||||||
#include "tlibc/time.h"
|
#include "tlibc/time.h"
|
||||||
|
|
||||||
typedef struct User {
|
typedef struct User {
|
||||||
u16 name_len;
|
|
||||||
char name[USERNAME_SIZE_MAX + 1]; // null-terminated
|
char name[USERNAME_SIZE_MAX + 1]; // null-terminated
|
||||||
|
u16 name_len;
|
||||||
u8 token_hash[PASSWORD_HASH_SIZE]; // token is hashed again on server side
|
u8 token_hash[PASSWORD_HASH_SIZE]; // token is hashed again on server side
|
||||||
DateTime registration_time;
|
DateTime registration_time;
|
||||||
} ATTRIBUTE_ALIGNED(256) User;
|
} ATTRIBUTE_ALIGNED(256) User;
|
||||||
|
|
||||||
typedef struct Channel {
|
typedef struct Channel {
|
||||||
|
char name[CHANNEL_NAME_SIZE_MAX + 1];
|
||||||
u16 name_len;
|
u16 name_len;
|
||||||
|
char desc[CHANNEL_DESC_SIZE_MAX + 1];
|
||||||
u16 desc_len;
|
u16 desc_len;
|
||||||
char name[CHANNEL_NAME_MAX + 1];
|
} ATTRIBUTE_ALIGNED(4*1024) Channel;
|
||||||
char desc[CHANNEL_DESC_MAX + 1];
|
|
||||||
} ATTRIBUTE_ALIGNED(16*1024) Channel;
|
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#include "request_handlers.h"
|
#include "request_handlers.h"
|
||||||
|
|
||||||
|
#define LOGGER server->logger
|
||||||
|
#define LOG_FUNC server->log_func
|
||||||
|
|
||||||
declare_RequestHandler(Login)
|
declare_RequestHandler(Login)
|
||||||
{
|
{
|
||||||
@ -12,8 +14,10 @@ declare_RequestHandler(Login)
|
|||||||
try_void(EncryptedSocketTCP_recvStruct(&conn->sock, &req));
|
try_void(EncryptedSocketTCP_recvStruct(&conn->sock, &req));
|
||||||
|
|
||||||
if(conn->authorized){
|
if(conn->authorized){
|
||||||
try_void(sendErrorMessage(log_ctx, false, conn, res_head,
|
try_void(sendErrorMessage(server, log_ctx, conn, res_head,
|
||||||
STR("is logged in already")));
|
LogSeverity_Warn,
|
||||||
|
STR("is logged in already")
|
||||||
|
));
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,7 +25,10 @@ declare_RequestHandler(Login)
|
|||||||
str username_str = str_null;
|
str username_str = str_null;
|
||||||
str username_check_error = validateUsername_cstr(req.username, &username_str);
|
str username_check_error = validateUsername_cstr(req.username, &username_str);
|
||||||
if(username_check_error.data){
|
if(username_check_error.data){
|
||||||
try_void(sendErrorMessage(log_ctx, false, conn, res_head, username_check_error));
|
try_void(sendErrorMessage(server, log_ctx, conn, res_head,
|
||||||
|
LogSeverity_Warn,
|
||||||
|
username_check_error
|
||||||
|
));
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,9 +48,11 @@ declare_RequestHandler(Login)
|
|||||||
// try get id from name cache
|
// try get id from name cache
|
||||||
u64* id_ptr = HashMap_tryGetPtr(&server->users_name_id_map, username_str);
|
u64* id_ptr = HashMap_tryGetPtr(&server->users_name_id_map, username_str);
|
||||||
if(id_ptr == NULL){
|
if(id_ptr == NULL){
|
||||||
try_void(sendErrorMessage_f(log_ctx, false, conn, res_head,
|
try_void(sendErrorMessage_f(server, log_ctx, conn, res_head,
|
||||||
|
LogSeverity_Warn,
|
||||||
"Username '%s' is not registered\n",
|
"Username '%s' is not registered\n",
|
||||||
username_str.data));
|
username_str.data
|
||||||
|
));
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
u64 user_id = *id_ptr;
|
u64 user_id = *id_ptr;
|
||||||
@ -54,8 +63,10 @@ declare_RequestHandler(Login)
|
|||||||
|
|
||||||
// validate token hash
|
// validate token hash
|
||||||
if(memcmp(token_hash, u->token_hash, sizeof(token_hash)) != 0){
|
if(memcmp(token_hash, u->token_hash, sizeof(token_hash)) != 0){
|
||||||
try_void(sendErrorMessage(log_ctx, false, conn, res_head,
|
try_void(sendErrorMessage(server, log_ctx, conn, res_head,
|
||||||
STR("wrong password")));
|
LogSeverity_Warn,
|
||||||
|
STR("wrong password")
|
||||||
|
));
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
#include "request_handlers.h"
|
#include "request_handlers.h"
|
||||||
|
|
||||||
|
#define LOGGER server->logger
|
||||||
|
#define LOG_FUNC server->log_func
|
||||||
|
|
||||||
declare_RequestHandler(Register)
|
declare_RequestHandler(Register)
|
||||||
{
|
{
|
||||||
Deferral(4);
|
Deferral(4);
|
||||||
@ -14,7 +17,10 @@ declare_RequestHandler(Register)
|
|||||||
str username_str = str_null;
|
str username_str = str_null;
|
||||||
str username_check_error = validateUsername_cstr(req.username, &username_str);
|
str username_check_error = validateUsername_cstr(req.username, &username_str);
|
||||||
if(username_check_error.data){
|
if(username_check_error.data){
|
||||||
try_void(sendErrorMessage(log_ctx, false, conn, res_head, username_check_error));
|
try_void(sendErrorMessage(server, log_ctx, conn, res_head,
|
||||||
|
LogSeverity_Warn,
|
||||||
|
username_check_error
|
||||||
|
));
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +31,8 @@ declare_RequestHandler(Register)
|
|||||||
|
|
||||||
// check if name is taken
|
// check if name is taken
|
||||||
if(HashMap_tryGetPtr(&server->users_name_id_map, username_str) != NULL){
|
if(HashMap_tryGetPtr(&server->users_name_id_map, username_str) != NULL){
|
||||||
try_void(sendErrorMessage_f(log_ctx, false, conn, res_head,
|
try_void(sendErrorMessage_f(server, log_ctx, conn, res_head,
|
||||||
|
LogSeverity_Warn,
|
||||||
"Username'%s' already exists\n",
|
"Username'%s' already exists\n",
|
||||||
username_str.data));
|
username_str.data));
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
@ -34,13 +41,17 @@ declare_RequestHandler(Register)
|
|||||||
// initialize new user
|
// initialize new user
|
||||||
User user;
|
User user;
|
||||||
memset(&user, 0, sizeof(User));
|
memset(&user, 0, sizeof(User));
|
||||||
memcpy(user.name, username_str.data, username_str.size + 1);
|
|
||||||
|
memcpy(user.name, username_str.data, username_str.size);
|
||||||
user.name_len = username_str.size;
|
user.name_len = username_str.size;
|
||||||
|
user.name[user.name_len] = 0;
|
||||||
|
|
||||||
hash_password(
|
hash_password(
|
||||||
Array_construct_size(req.token, sizeof(req.token)),
|
Array_construct_size(req.token, sizeof(req.token)),
|
||||||
user.token_hash,
|
user.token_hash,
|
||||||
PASSWORD_HASH_LVL_ROUNDS
|
PASSWORD_HASH_LVL_ROUNDS
|
||||||
);
|
);
|
||||||
|
|
||||||
DateTime_getUTC(&user.registration_time);
|
DateTime_getUTC(&user.registration_time);
|
||||||
|
|
||||||
// save new user to db and cache
|
// save new user to db and cache
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
#include "request_handlers.h"
|
#include "request_handlers.h"
|
||||||
|
|
||||||
|
#define LOGGER server->logger
|
||||||
|
#define LOG_FUNC server->log_func
|
||||||
|
|
||||||
declare_RequestHandler(ServerPublicInfo)
|
declare_RequestHandler(ServerPublicInfo)
|
||||||
{
|
{
|
||||||
Deferral(4);
|
Deferral(4);
|
||||||
@ -14,7 +17,8 @@ declare_RequestHandler(ServerPublicInfo)
|
|||||||
Array(u8) content;
|
Array(u8) content;
|
||||||
switch(req.property){
|
switch(req.property){
|
||||||
default:{
|
default:{
|
||||||
try_void(sendErrorMessage_f(log_ctx, false, conn, res_head,
|
try_void(sendErrorMessage_f(server, log_ctx, conn, res_head,
|
||||||
|
LogSeverity_Warn,
|
||||||
"Unknown ServerPublicInfo property %u",
|
"Unknown ServerPublicInfo property %u",
|
||||||
req.property));
|
req.property));
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
|
|||||||
@ -1,24 +1,26 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "network/tcp-chat-protocol/v1.h"
|
#include "network/tcp-chat-protocol/v1.h"
|
||||||
#include "server/server.h"
|
#include "server/server_internal.h"
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
|
|
||||||
Result(void) sendErrorMessage(cstr log_ctx, bool logAsError,
|
Result(void) sendErrorMessage(
|
||||||
|
Server* server, cstr log_ctx,
|
||||||
ClientConnection* conn, PacketHeader* res_head,
|
ClientConnection* conn, PacketHeader* res_head,
|
||||||
str msg);
|
LogSeverity log_severity, str msg);
|
||||||
|
|
||||||
Result(void) __sendErrorMessage_fv(cstr log_ctx, bool logAsError,
|
Result(void) __sendErrorMessage_fv(
|
||||||
|
Server* server, cstr log_ctx,
|
||||||
ClientConnection* conn, PacketHeader* res_head,
|
ClientConnection* conn, PacketHeader* res_head,
|
||||||
cstr format, va_list argv);
|
LogSeverity log_severity, cstr format, va_list argv);
|
||||||
|
|
||||||
Result(void) sendErrorMessage_f(cstr log_ctx, bool logAsError,
|
Result(void) sendErrorMessage_f(
|
||||||
|
Server* server, cstr log_ctx,
|
||||||
ClientConnection* conn, PacketHeader* res_head,
|
ClientConnection* conn, PacketHeader* res_head,
|
||||||
cstr format, ...) ATTRIBUTE_CHECK_FORMAT_PRINTF(5, 6);
|
LogSeverity log_severity, cstr format, ...) ATTRIBUTE_CHECK_FORMAT_PRINTF(6, 7);
|
||||||
|
|
||||||
|
|
||||||
#define declare_RequestHandler(TYPE) \
|
#define declare_RequestHandler(TYPE) \
|
||||||
Result(void) handleRequest_##TYPE( \
|
Result(void) handleRequest_##TYPE(\
|
||||||
Server* server, cstr log_ctx, cstr req_type_name, \
|
Server* server, cstr log_ctx, cstr req_type_name, \
|
||||||
ClientConnection* conn, PacketHeader* req_head, PacketHeader* res_head)
|
ClientConnection* conn, PacketHeader* req_head, PacketHeader* res_head)
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
#include "request_handlers.h"
|
#include "request_handlers.h"
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
Result(void) sendErrorMessage(cstr log_ctx, bool logAsError,
|
#define LOGGER server->logger
|
||||||
|
#define LOG_FUNC server->log_func
|
||||||
|
|
||||||
|
Result(void) sendErrorMessage(
|
||||||
|
Server* server, cstr log_ctx,
|
||||||
ClientConnection* conn, PacketHeader* res_head,
|
ClientConnection* conn, PacketHeader* res_head,
|
||||||
str msg)
|
LogSeverity log_severity, str msg)
|
||||||
{
|
{
|
||||||
Deferral(1);
|
Deferral(1);
|
||||||
|
|
||||||
@ -11,11 +14,7 @@ Result(void) sendErrorMessage(cstr log_ctx, bool logAsError,
|
|||||||
if(msg.size > ERROR_MESSAGE_MAX_SIZE)
|
if(msg.size > ERROR_MESSAGE_MAX_SIZE)
|
||||||
msg.size = ERROR_MESSAGE_MAX_SIZE;
|
msg.size = ERROR_MESSAGE_MAX_SIZE;
|
||||||
|
|
||||||
if(logAsError){
|
log(log_severity, log_ctx, FMT_str, msg.size, msg.data);
|
||||||
logError(log_ctx, FMT_str, msg.size, msg.data);
|
|
||||||
} else {
|
|
||||||
logWarn(log_ctx, FMT_str, msg.size, msg.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorMessage res;
|
ErrorMessage res;
|
||||||
ErrorMessage_construct(&res, res_head, msg.size);
|
ErrorMessage_construct(&res, res_head, msg.size);
|
||||||
@ -26,29 +25,31 @@ Result(void) sendErrorMessage(cstr log_ctx, bool logAsError,
|
|||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result(void) __sendErrorMessage_fv(cstr log_ctx, bool logAsError,
|
Result(void) __sendErrorMessage_fv(
|
||||||
ClientConnection* conn, PacketHeader* res_head,
|
Server* server, cstr log_ctx,
|
||||||
cstr format, va_list argv)
|
ClientConnection* conn, PacketHeader* res_head,
|
||||||
|
LogSeverity log_severity, cstr format, va_list argv)
|
||||||
{
|
{
|
||||||
Deferral(4);
|
Deferral(4);
|
||||||
|
|
||||||
str msg = str_from_cstr(vsprintf_malloc(format, argv));
|
str msg = str_from_cstr(vsprintf_malloc(format, argv));
|
||||||
Defer(free(msg.data));
|
Defer(free(msg.data));
|
||||||
try_void(sendErrorMessage(log_ctx, logAsError, conn, res_head, msg));
|
try_void(sendErrorMessage(server, log_ctx, conn, res_head, log_severity, msg));
|
||||||
|
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result(void) sendErrorMessage_f(cstr log_ctx, bool logAsError,
|
Result(void) sendErrorMessage_f(
|
||||||
|
Server* server, cstr log_ctx,
|
||||||
ClientConnection* conn, PacketHeader* res_head,
|
ClientConnection* conn, PacketHeader* res_head,
|
||||||
cstr format, ...)
|
LogSeverity log_severity, cstr format, ...)
|
||||||
{
|
{
|
||||||
Deferral(1);
|
Deferral(1);
|
||||||
|
|
||||||
va_list argv;
|
va_list argv;
|
||||||
va_start(argv, format);
|
va_start(argv, format);
|
||||||
Defer(va_end(argv));
|
Defer(va_end(argv));
|
||||||
try_void(__sendErrorMessage_fv(log_ctx, logAsError, conn, res_head, format, argv));
|
try_void(__sendErrorMessage_fv(server, log_ctx, conn, res_head, log_severity, format, argv));
|
||||||
|
|
||||||
return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
#include "request_handlers.h"
|
#include "request_handlers.h"
|
||||||
|
|
||||||
|
#define LOGGER server->logger
|
||||||
|
#define LOG_FUNC server->log_func
|
||||||
|
|
||||||
declare_RequestHandler(NAME)
|
declare_RequestHandler(NAME)
|
||||||
{
|
{
|
||||||
Deferral(4);
|
Deferral(4);
|
||||||
|
|||||||
@ -2,46 +2,45 @@
|
|||||||
#include "tlibc/filesystem.h"
|
#include "tlibc/filesystem.h"
|
||||||
#include "tlibc/time.h"
|
#include "tlibc/time.h"
|
||||||
#include "tlibc/base64.h"
|
#include "tlibc/base64.h"
|
||||||
#include "server.h"
|
#include "server/server_internal.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "log.h"
|
|
||||||
#include "network/tcp-chat-protocol/v1.h"
|
#include "network/tcp-chat-protocol/v1.h"
|
||||||
#include "server/request_handlers/request_handlers.h"
|
#include "server/request_handlers/request_handlers.h"
|
||||||
|
|
||||||
static void* handleConnection(void* _args);
|
static void* handleConnection(void* _args);
|
||||||
static Result(void) try_handleConnection(ConnectionHandlerArgs* args, cstr log_ctx);
|
static Result(void) try_handleConnection(ConnectionHandlerArgs* args, cstr log_ctx);
|
||||||
|
|
||||||
void Server_free(Server* server){
|
void Server_free(Server* self){
|
||||||
if(!server)
|
if(!self)
|
||||||
return;
|
return;
|
||||||
free(server->name.data);
|
|
||||||
free(server->description.data);
|
str_free(self->name);
|
||||||
ServerCredentials_destroy(&server->cred);
|
str_free(self->description);
|
||||||
idb_close(server->db);
|
RSA_destroyPrivateKey(&self->rsa_sk);
|
||||||
pthread_mutex_destroy(&server->users_cache_mutex);
|
RSA_destroyPublicKey(&self->rsa_pk);
|
||||||
free(server->users_cache_list.data);
|
|
||||||
HashMap_destroy(&server->users_name_id_map);
|
idb_close(self->db);
|
||||||
|
pthread_mutex_destroy(&self->users_cache_mutex);
|
||||||
|
List_destroy(self->users_cache_list);
|
||||||
|
HashMap_destroy(&self->users_name_id_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result(Server*) Server_createFromConfig(cstr config_path){
|
|
||||||
|
#define LOGGER logger
|
||||||
|
#define LOG_FUNC log_func
|
||||||
|
|
||||||
|
Result(Server*) Server_create(str config_str, void* logger, LogFunction_t log_func){
|
||||||
Deferral(16);
|
Deferral(16);
|
||||||
cstr log_ctx = "ServerInit";
|
cstr log_ctx = "ServerInit";
|
||||||
logInfo(log_ctx, "parsing config");
|
|
||||||
|
|
||||||
Server* server = (Server*)malloc(sizeof(Server));
|
Server* server = (Server*)malloc(sizeof(Server));
|
||||||
memset(server, 0, sizeof(Server));
|
memset(server, 0, sizeof(Server));
|
||||||
bool success = false;
|
bool success = false;
|
||||||
Defer(if(!success) Server_free(server));
|
Defer(if(!success) Server_free(server));
|
||||||
|
|
||||||
// open file
|
server->logger = logger;
|
||||||
try(FILE* config_file, p, file_open(config_path, FO_ReadExisting));
|
server->log_func = log_func;
|
||||||
Defer(file_close(config_file));
|
logDebug(log_ctx, "parsing config");
|
||||||
// read whole file into Array(char)
|
|
||||||
try(i64 config_file_size, i, file_getSize(config_file));
|
|
||||||
Array(char) config_buf = Array_alloc(char, config_file_size);
|
|
||||||
Defer(free(config_buf.data));
|
|
||||||
try_void(file_readBytesArray(config_file, config_buf));
|
|
||||||
str config_str = Array_castTo_str(config_buf, false);
|
|
||||||
|
|
||||||
// parse name
|
// parse name
|
||||||
str tmp_str = str_null;
|
str tmp_str = str_null;
|
||||||
@ -76,11 +75,13 @@ Result(Server*) Server_createFromConfig(cstr config_path){
|
|||||||
char* pk_base64_cstr = str_copy(tmp_str).data;
|
char* pk_base64_cstr = str_copy(tmp_str).data;
|
||||||
Defer(free(pk_base64_cstr));
|
Defer(free(pk_base64_cstr));
|
||||||
|
|
||||||
try_void(ServerCredentials_tryConstruct(&server->cred, sk_base64_cstr, pk_base64_cstr));
|
try_void(RSA_parsePrivateKey_base64(sk_base64_cstr, &server->rsa_sk));
|
||||||
|
try_void(RSA_parsePublicKey_base64(pk_base64_cstr, &server->rsa_pk));
|
||||||
|
|
||||||
// parse db_aes_key
|
// parse db_aes_key
|
||||||
try_void(config_findValue(config_str, STR("db_aes_key"), &tmp_str, true));
|
try_void(config_findValue(config_str, STR("db_aes_key"), &tmp_str, true));
|
||||||
Array(u8) db_aes_key = Array_alloc_size(base64_decodedSize(tmp_str.data, tmp_str.size));
|
Array(u8) db_aes_key = Array_alloc_size(base64_decodedSize(tmp_str.data, tmp_str.size));
|
||||||
|
Defer(free(db_aes_key.data));
|
||||||
base64_decode(tmp_str.data, tmp_str.size, db_aes_key.data);
|
base64_decode(tmp_str.data, tmp_str.size, db_aes_key.data);
|
||||||
|
|
||||||
// parse db_dir and open db
|
// parse db_dir and open db
|
||||||
@ -108,6 +109,11 @@ Result(Server*) Server_createFromConfig(cstr config_path){
|
|||||||
Return RESULT_VALUE(p, server);
|
Return RESULT_VALUE(p, server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef LOGGER
|
||||||
|
#undef LOG_FUNC
|
||||||
|
#define LOGGER server->logger
|
||||||
|
#define LOG_FUNC server->log_func
|
||||||
|
|
||||||
Result(void) Server_run(Server* server){
|
Result(void) Server_run(Server* server){
|
||||||
Deferral(16);
|
Deferral(16);
|
||||||
cstr log_ctx = "ListenerThread";
|
cstr log_ctx = "ListenerThread";
|
||||||
@ -138,33 +144,35 @@ Result(void) Server_run(Server* server){
|
|||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void* handleConnection(void* _args){
|
static void* handleConnection(void* _args){
|
||||||
ConnectionHandlerArgs* args = (ConnectionHandlerArgs*)_args;
|
ConnectionHandlerArgs* args = (ConnectionHandlerArgs*)_args;
|
||||||
|
Server* server = args->server;
|
||||||
char log_ctx[64];
|
char log_ctx[64];
|
||||||
sprintf(log_ctx, "Session-"FMT_x64, args->session_id);
|
sprintf(log_ctx, "Session-"FMT_x64, args->session_id);
|
||||||
|
|
||||||
ResultVar(void) r = try_handleConnection(args, log_ctx);
|
ResultVar(void) r = try_handleConnection(args, log_ctx);
|
||||||
if(r.error){
|
if(r.error){
|
||||||
|
Error_addCallPos(r.error, ErrorCallPos_here());
|
||||||
str e_str = Error_toStr(r.error);
|
str e_str = Error_toStr(r.error);
|
||||||
logError(log_ctx, "%s", e_str.data);
|
logError(log_ctx, "%s", e_str.data);
|
||||||
free(e_str.data);
|
str_free(e_str);
|
||||||
Error_free(r.error);
|
Error_free(r.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logInfo(log_ctx, "session end");
|
||||||
|
free(args);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result(void) try_handleConnection(ConnectionHandlerArgs* args, cstr log_ctx){
|
static Result(void) try_handleConnection(ConnectionHandlerArgs* args, cstr log_ctx){
|
||||||
Deferral(16);
|
Deferral(16);
|
||||||
Defer(free(args));
|
|
||||||
|
|
||||||
|
Server* server = args->server;
|
||||||
ClientConnection* conn = NULL;
|
ClientConnection* conn = NULL;
|
||||||
Defer(
|
|
||||||
ClientConnection_close(conn);
|
|
||||||
logInfo(log_ctx, "session closed");
|
|
||||||
);
|
|
||||||
// establish encrypted connection
|
// establish encrypted connection
|
||||||
try(conn, p, ClientConnection_accept(args));
|
try(conn, p, ClientConnection_accept(args));
|
||||||
|
Defer(ClientConnection_close(conn));
|
||||||
logInfo(log_ctx, "session accepted");
|
logInfo(log_ctx, "session accepted");
|
||||||
|
|
||||||
// handle requests
|
// handle requests
|
||||||
@ -180,7 +188,8 @@ static Result(void) try_handleConnection(ConnectionHandlerArgs* args, cstr log_c
|
|||||||
switch(req_head.type){
|
switch(req_head.type){
|
||||||
// send error message and close connection
|
// send error message and close connection
|
||||||
default:
|
default:
|
||||||
try_void(sendErrorMessage_f(log_ctx, false, conn, &res_head,
|
try_void(sendErrorMessage_f(server, log_ctx, conn, &res_head,
|
||||||
|
LogSeverity_Error,
|
||||||
"Received unexpected packet of type %u",
|
"Received unexpected packet of type %u",
|
||||||
req_head.type));
|
req_head.type));
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
|
|||||||
@ -1,24 +1,36 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "tlibc/collections/HashMap.h"
|
||||||
|
#include "tlibc/collections/List.h"
|
||||||
|
#include "tcp-chat/server.h"
|
||||||
#include "cryptography/AES.h"
|
#include "cryptography/AES.h"
|
||||||
#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 "server/db_tables.h"
|
||||||
#include "tlibc/collections/List.h"
|
|
||||||
#include "db_tables.h"
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
typedef struct Server Server;
|
typedef struct ClientConnection ClientConnection;
|
||||||
|
|
||||||
typedef struct ServerCredentials {
|
typedef struct Server {
|
||||||
|
/* from constructor */
|
||||||
|
void* logger;
|
||||||
|
LogFunction_t log_func;
|
||||||
|
|
||||||
|
/* from config */
|
||||||
|
str name;
|
||||||
|
str description;
|
||||||
|
u64 landing_channel_id;
|
||||||
|
EndpointIPv4 local_end;
|
||||||
br_rsa_private_key rsa_sk;
|
br_rsa_private_key rsa_sk;
|
||||||
br_rsa_public_key rsa_pk;
|
br_rsa_public_key rsa_pk;
|
||||||
} ServerCredentials;
|
|
||||||
|
|
||||||
Result(void) ServerCredentials_tryConstruct(ServerCredentials* cred,
|
/* database and cache */
|
||||||
cstr rsa_sk_base64, cstr rsa_pk_base64);
|
IncrementalDB* db;
|
||||||
|
Table* db_users_table;
|
||||||
void ServerCredentials_destroy(ServerCredentials* cred);
|
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;
|
||||||
|
|
||||||
|
|
||||||
typedef struct ClientConnection {
|
typedef struct ClientConnection {
|
||||||
@ -29,7 +41,6 @@ typedef struct ClientConnection {
|
|||||||
bool authorized;
|
bool authorized;
|
||||||
} ClientConnection;
|
} ClientConnection;
|
||||||
|
|
||||||
|
|
||||||
typedef struct ConnectionHandlerArgs {
|
typedef struct ConnectionHandlerArgs {
|
||||||
Server* server;
|
Server* server;
|
||||||
Socket accepted_socket_tcp;
|
Socket accepted_socket_tcp;
|
||||||
@ -42,19 +53,3 @@ Result(ClientConnection*) ClientConnection_accept(ConnectionHandlerArgs* args);
|
|||||||
void ClientConnection_close(ClientConnection* conn);
|
void ClientConnection_close(ClientConnection* conn);
|
||||||
|
|
||||||
|
|
||||||
typedef struct Server {
|
|
||||||
str name;
|
|
||||||
str description;
|
|
||||||
u64 landing_channel_id;
|
|
||||||
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);
|
|
||||||
void Server_free(Server* server);
|
|
||||||
Result(void) Server_run(Server* server);
|
|
||||||
95
src/term.c
95
src/term.c
@ -1,95 +0,0 @@
|
|||||||
#include "term.h"
|
|
||||||
#include <unistd.h>
|
|
||||||
#include IFWIN("windows.h", "sys/ioctl.h")
|
|
||||||
|
|
||||||
bool term_init(){
|
|
||||||
#if defined(_WIN64) || defined(_WIN32)
|
|
||||||
DWORD mode=0;
|
|
||||||
HANDLE h;
|
|
||||||
|
|
||||||
// configure stdout
|
|
||||||
h = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
if(h == INVALID_HANDLE_VALUE)
|
|
||||||
return false;
|
|
||||||
GetConsoleMode(h, &mode);
|
|
||||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
|
||||||
mode |= ENABLE_PROCESSED_OUTPUT;
|
|
||||||
SetConsoleMode(h, mode);
|
|
||||||
|
|
||||||
// configure stdin
|
|
||||||
h = GetStdHandle(STD_INPUT_HANDLE);
|
|
||||||
if(h == INVALID_HANDLE_VALUE)
|
|
||||||
return false;
|
|
||||||
GetConsoleMode(h, &mode);
|
|
||||||
mode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
|
|
||||||
mode |= ENABLE_PROCESSED_INPUT;
|
|
||||||
SetConsoleMode(h, mode);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getenv_int(const char* var_name){
|
|
||||||
char* str=getenv(var_name);
|
|
||||||
if(str==NULL)
|
|
||||||
return -1;
|
|
||||||
return strtol(str, NULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool term_getSize(TerminalSize* out) {
|
|
||||||
#if defined(_WIN64) || defined(_WIN32)
|
|
||||||
// helps when STD_OUT is redirected to a file
|
|
||||||
HANDLE hConsoleErr = GetStdHandle(STD_ERROR_HANDLE);
|
|
||||||
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
|
|
||||||
if(!GetConsoleScreenBufferInfo(hConsoleErr, &consoleInfo))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
out->cols = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1;
|
|
||||||
out->rows = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1;
|
|
||||||
#else
|
|
||||||
struct winsize ws = {0};
|
|
||||||
// try to get terminal size from stdin, stdout, stderr
|
|
||||||
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)==0 ||
|
|
||||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws)==0 ||
|
|
||||||
ioctl(STDERR_FILENO, TIOCGWINSZ, &ws)==0 ){
|
|
||||||
out->cols=ws.ws_col;
|
|
||||||
out->rows=ws.ws_row;
|
|
||||||
}
|
|
||||||
// try to get size from environtent variables
|
|
||||||
else {
|
|
||||||
out->cols=getenv_int("COLUMNS");
|
|
||||||
out->rows=getenv_int("LINES");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return out->cols > 0 && out->rows > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Most of escape sequences can be found there
|
|
||||||
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
|
|
||||||
*/
|
|
||||||
|
|
||||||
void term_resetCursor() {
|
|
||||||
printf("\e[H");
|
|
||||||
}
|
|
||||||
|
|
||||||
void term_resetColors() {
|
|
||||||
printf("\e[0m");
|
|
||||||
}
|
|
||||||
|
|
||||||
void term_clear() {
|
|
||||||
printf("\e[0m\e[H\e[2J");
|
|
||||||
}
|
|
||||||
|
|
||||||
void term_cursorMove(u16 row, u16 column) {
|
|
||||||
printf("\e[%u;%uH",row,column);
|
|
||||||
}
|
|
||||||
|
|
||||||
void term_cursorHide() {
|
|
||||||
printf("\e[?25l");
|
|
||||||
}
|
|
||||||
|
|
||||||
void term_cursorShow() {
|
|
||||||
printf("\e[?25h");
|
|
||||||
}
|
|
||||||
16
src/term.h
16
src/term.h
@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "tlibc/std.h"
|
|
||||||
|
|
||||||
typedef struct TerminalSize {
|
|
||||||
i16 cols;
|
|
||||||
i16 rows;
|
|
||||||
} TerminalSize;
|
|
||||||
|
|
||||||
bool term_init();
|
|
||||||
bool term_getSize(TerminalSize* out);
|
|
||||||
void term_resetCursor();
|
|
||||||
void term_resetColors();
|
|
||||||
void term_clear();
|
|
||||||
void term_cursorMove(u16 row, u16 column);
|
|
||||||
void term_cursorHide();
|
|
||||||
void term_cursorShow();
|
|
||||||
Loading…
Reference in New Issue
Block a user