diff --git a/TODO.md b/TODO.md index 81efd97..7d2c97b 100644 --- a/TODO.md +++ b/TODO.md @@ -1,10 +1,13 @@ # Development plans -- [] Remove file when error while saving the data in DB +- [ ] Remove file when error while saving the data in DB ## Tasks -- [] Switch to SQLite -- [] Auto create a database when one is missing. + +- [ ] Switch to SQLite +- [ ] Check registration +- [x] Auto create a database when one is missing. + ## Features - [x] Database integration diff --git a/src/db/CMakeLists.txt b/src/db/CMakeLists.txt index aac8e10..4e4b699 100644 --- a/src/db/CMakeLists.txt +++ b/src/db/CMakeLists.txt @@ -15,6 +15,7 @@ endif() target_sources(db PRIVATE "db.c" + "db_common.c" PUBLIC FILE_SET HEADERS FILES diff --git a/src/db/db.c b/src/db/db.c index f93a553..58ad220 100644 --- a/src/db/db.c +++ b/src/db/db.c @@ -2,4 +2,5 @@ #include "db_postgresql.c" #else #include "db_sqlite.c" -#endif \ No newline at end of file +#endif + diff --git a/src/db/db.h b/src/db/db.h index 8c988cb..7ee8e4e 100644 --- a/src/db/db.h +++ b/src/db/db.h @@ -44,7 +44,7 @@ typedef struct { char email[EMAIL_LEN]; } i_db_user_create; -enum db_cb_resp { db_no_result, db_success, db_err }; +enum db_cb_resp { db_no_result, db_success, db_err, db_fail }; /* fail: the problem is on the user's side; no error */ int32_t init_db_connection(); int32_t db_save_file(session *s); diff --git a/src/db/db_common.c b/src/db/db_common.c new file mode 100644 index 0000000..3718872 --- /dev/null +++ b/src/db/db_common.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include + +void SHA256_raw_to_string(const unsigned char *passHashed, char *restrict out) { + int i; + for (i = 0; i < 4; i++) { + uint64_t *num_pointer = (uint64_t *)(passHashed + i * 8); + sprintf(out + 16 * i, "%016lx", htobe64(*num_pointer)); + } +} + +void string_to_SHA256(const char *str, char *restrict out) { + unsigned char md[SHA256_DIGEST_LENGTH]; + unsigned char *passHashed = SHA256((unsigned char *)str, strlen(str), md); + SHA256_raw_to_string(passHashed, out); +} \ No newline at end of file diff --git a/src/db/db_common.h b/src/db/db_common.h new file mode 100644 index 0000000..76b21b9 --- /dev/null +++ b/src/db/db_common.h @@ -0,0 +1,5 @@ +#ifndef DB_COMMON_H +#define DB_COMMON_H +void SHA256_raw_to_string(const unsigned char *passHashed, char *restrict out); +void string_to_SHA256(const char *str, char *restrict out); +#endif \ No newline at end of file diff --git a/src/db/db_postgresql.c b/src/db/db_postgresql.c index 62456bf..247813e 100644 --- a/src/db/db_postgresql.c +++ b/src/db/db_postgresql.c @@ -16,6 +16,7 @@ #include #include #include +#include "db_common.h" #define UNUSED(x) (void)(x) #define Q_LEN 128 @@ -101,20 +102,6 @@ int init_db_connection() { return exit_query(0); } -void SHA256_raw_to_string(const unsigned char *passHashed, char *restrict out) { - int i; - for (i = 0; i < 4; i++) { - uint64_t *num_pointer = (uint64_t *)(passHashed + i * 8); - sprintf(out + 16 * i, "%016lx", htobe64(*num_pointer)); - } -} - -void string_to_SHA256(const char *str, char *restrict out) { - unsigned char md[SHA256_DIGEST_LENGTH]; - unsigned char *passHashed = SHA256((unsigned char *)str, strlen(str), md); - SHA256_raw_to_string(passHashed, out); -} - int32_t db_user_auth(i_auth_t *c, o_auth_t *r) { const char *paramValues[1]; paramValues[0] = c->name; @@ -264,7 +251,6 @@ int32_t db_save_file(session *s) { return id; } -// TODO: get file s_file_t *db_get_file(i_get_file_db *arg) { s_file_t *sf; char s_field[24]; diff --git a/src/db/db_sqlite.c b/src/db/db_sqlite.c index 77376cd..4057b07 100644 --- a/src/db/db_sqlite.c +++ b/src/db/db_sqlite.c @@ -2,6 +2,7 @@ /* Copyright (c) 2026 Oleksandr Zhylin */ #include "../main.h" +#include "db_common.h" #include #include #include @@ -11,6 +12,7 @@ #include #include #include +#include #define UNUSED(x) (void)(x) #define Q_LEN 128 @@ -31,7 +33,7 @@ enum db_arg_type { db_end }; -typedef enum db_cb_resp (*db_callback)(sqlite3_stmt *stmt, void **resp); +typedef enum db_cb_resp (*db_callback)(sqlite3_stmt *stmt, void *resp); void print_err(char **err) { if (*err != NULL) { @@ -96,7 +98,7 @@ int check_and_create_tables() { } int init_db_connection(void) { - int res = sqlite3_open("db.sql", &db); + int res = sqlite3_open("db.sqlite", &db); char *err = NULL; if (!res) { res = check_and_create_tables(); @@ -104,22 +106,8 @@ int init_db_connection(void) { return 0; } - -void SHA256_raw_to_string(const unsigned char *passHashed, char *restrict out) { - int i; - for (i = 0; i < 4; i++) { - uint64_t *num_pointer = (uint64_t *)(passHashed + i * 8); - sprintf(out + 16 * i, "%016lx", htobe64(*num_pointer)); - } -} - -void string_to_SHA256(const char *str, char *restrict out) { - unsigned char md[SHA256_DIGEST_LENGTH]; - unsigned char *passHashed = SHA256((unsigned char *)str, strlen(str), md); - SHA256_raw_to_string(passHashed, out); -} - -enum db_cb_resp db_query(const char *zSql, db_callback callback, void **a_resp, +/* ATTENTION: you need to make a copy of responses in callbacks. */ +enum db_cb_resp db_query(const char *zSql, db_callback callback, void *a_resp, enum db_arg_type arg_types[], ...) { sqlite3_stmt *stmt; const char *pzTail; @@ -183,28 +171,75 @@ enum db_cb_resp db_query(const char *zSql, db_callback callback, void **a_resp, return res; } -enum db_cb_resp db_user_auth_db(sqlite3_stmt *stmt, void **resp) { - return db_success; - /* TODO: complete */ +struct db_user_login_data { + char *passwordHashed; + o_auth_t *r; +}; + +enum db_cb_resp db_user_auth_db(sqlite3_stmt *stmt, void *resp) { + struct db_user_login_data *data = (struct db_user_login_data *)resp; + const unsigned char *pass = sqlite3_column_text(stmt, 2); + if (!strcmp(data->passwordHashed, (const char *)pass)) { + data->r->uid = sqlite3_column_int(stmt, 0); + data->r->privileges = sqlite3_column_int(stmt, 6); + return db_success; + } else { + return db_fail; + } } int32_t db_user_auth(i_auth_t *c, o_auth_t *r) { - enum db_arg_type args[] = {db_str}; + char passHashed[SHA256_DIGEST_LENGTH * 2]; + struct db_user_login_data data = {.r = r}; + string_to_SHA256(c->pass, passHashed); + data.passwordHashed = passHashed; + enum db_arg_type arg_types[] = {db_str, db_end}; long int user_id; + enum db_cb_resp res; char zSql[] = "SELECT id, username, password, privileges " "FROM users " "WHERE username= $1"; - db_query(zSql, db_user_auth_db, (void *)&user_id, args, c->name); + res = db_query(zSql, db_user_auth_db, (void *)&data, arg_types, c->name); - /* TODO: complete */ + if (res == db_success) { + char u_buf[128]; + sprintf(u_buf, "UPDATE users SET last_login = NOW() WHERE id = %u", r->uid); + sqlite3_exec(db, u_buf, NULL, NULL, NULL); + return r->uid; + } return 0; } -int32_t db_user_create(i_db_user_create *args) { return 0; } +struct db_user_create_data { + int uid; +}; + +enum db_cb_resp db_user_create_db(sqlite3_stmt *stmt, void *resp) { + struct db_user_create_data *data = (struct db_user_create_data *)resp; + data->uid = sqlite3_column_int(stmt, 0); + + return db_success; +} + +int32_t db_user_create(i_db_user_create *args) { + char passHashed[SHA256_DIGEST_LENGTH * 2]; + struct db_user_create_data data = {.uid = 0}; + string_to_SHA256(args->pass, passHashed); + enum db_arg_type arg_types[] = {db_str, db_str, db_str, db_end}; + long int user_id; + enum db_cb_resp res; + char zSql[] = "INSERT INTO users (username, password, email, " + "privileges, created_at, last_login)" + " VALUES ($1, $2, $3, 1, NOW(), NOW()) RETURNING id"; + + res = db_query(zSql, db_user_create_db, (void *)NULL, arg_types, args->uname, + args->pass, args->email); + + return data.uid; +} int32_t db_save_file(session *s) { return 0; } -// TODO: get file s_file_t *db_get_file(i_get_file_db *arg) { s_file_t *sf = NULL; diff --git a/src/main.c b/src/main.c index 93b3343..d766925 100644 --- a/src/main.c +++ b/src/main.c @@ -12,7 +12,6 @@ int main(int argc, char *argv[]) { prepare_start(argc, argv); server_data.welcome_message = get_welcome_mes(); init_db_connection(); - return 0; server_data.ls = start_server(); /* TODO: display server port */ printf("Server is started!\n");