added database
This commit is contained in:
1 parent
c4ea7a4293
commit
4f67cf11bd
30 files changed
+601
-267
No files matched your search
@@ -0,0 +1,6 @@
|
||||
BasedOnStyle: Google
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
SpaceAfterCStyleCast: true
|
||||
PointerBindsToType: false
|
||||
DerivePointerBinding: false
|
||||
IncludeBlocks: Preserve
|
||||
@@ -3,4 +3,6 @@
|
||||
.cache
|
||||
.idea
|
||||
build
|
||||
builddir
|
||||
fmongoose
|
||||
users.db
|
||||
+4
-2
@@ -4,13 +4,15 @@ project(fmongoose LANGUAGES C)
|
||||
set(CMAKE_C_STANDARD 23)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
include_directories(./src/lib/)
|
||||
include_directories(./src/lib/ ${SQLite3_INCLUDE_DIRS})
|
||||
|
||||
FILE(GLOB_RECURSE SOURCES src/*.c)
|
||||
|
||||
find_package(SQLite3 REQUIRED)
|
||||
|
||||
add_executable(
|
||||
fmongoose
|
||||
${SOURCES}
|
||||
)
|
||||
|
||||
target_link_libraries(fmongoose ssl crypto)
|
||||
target_link_libraries(fmongoose ssl crypto sqlite3 pthread)
|
||||
@@ -1,7 +1,7 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -g -std=gnu2x
|
||||
LDFLAGS =
|
||||
LIBS = -lpthread -lcrypto
|
||||
LIBS = -lpthread -lcrypto -lsqlite3
|
||||
INCLUDES = -I./src/lib -I./src
|
||||
SRCS = $(wildcard src/*.c src/lib/*.c)
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
+6
-1
@@ -1,6 +1,6 @@
|
||||
project('fmongoose', 'c', default_options: ['c_std=gnu2x'])
|
||||
include_dirs = include_directories('src', 'src/lib')
|
||||
deps = dependency('openssl')
|
||||
deps = [dependency('openssl'), dependency('sqlite3')]
|
||||
executable(
|
||||
'fmongoose',
|
||||
'src/main.c',
|
||||
@@ -18,6 +18,11 @@ executable(
|
||||
'src/jwt.c',
|
||||
'src/lib/mongoose.c',
|
||||
'src/lib/cJSON.c',
|
||||
'src/database.c',
|
||||
'src/db_get_all_users.c',
|
||||
'src/db_get_user_by_username.c',
|
||||
'src/db_get_users_from_file.c',
|
||||
'src/file.c',
|
||||
include_directories: include_dirs,
|
||||
dependencies: deps,
|
||||
)
|
||||
+11
-20
@@ -1,26 +1,17 @@
|
||||
#include "user.h"
|
||||
#include "jwt.h"
|
||||
#include "user.h"
|
||||
#include "utils.h"
|
||||
|
||||
void add_user(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
request_with_token *requestdata = check_body(hm);
|
||||
const bool valid = jwt_verifyJWT(requestdata->token, JWT_DEFAULT_SECRET);
|
||||
if (!valid) {
|
||||
mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("invalid token"));
|
||||
return;
|
||||
}
|
||||
char responsedata[2048] = {0};
|
||||
snprintf(
|
||||
responsedata,
|
||||
sizeof(responsedata),
|
||||
"{\"success\": true}"
|
||||
);
|
||||
request_with_token *requestdata = check_body(hm);
|
||||
const bool valid = jwt_verifyJWT(requestdata->token, JWT_DEFAULT_SECRET);
|
||||
if (!valid) {
|
||||
mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("invalid token"));
|
||||
return;
|
||||
}
|
||||
char responsedata[2048] = {0};
|
||||
snprintf(responsedata, sizeof(responsedata), "{\"success\": true}");
|
||||
|
||||
mg_http_reply(
|
||||
c,
|
||||
200,
|
||||
"Content-Type: application/json\r\n",
|
||||
responsedata
|
||||
);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", responsedata);
|
||||
}
|
||||
+11
-20
@@ -1,26 +1,17 @@
|
||||
#include "user.h"
|
||||
#include "jwt.h"
|
||||
#include "user.h"
|
||||
#include "utils.h"
|
||||
|
||||
void change_password(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
request_with_token *requestdata = check_body(hm);
|
||||
const bool valid = jwt_verifyJWT(requestdata->token, JWT_DEFAULT_SECRET);
|
||||
if (!valid) {
|
||||
mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("invalid token"));
|
||||
return;
|
||||
}
|
||||
char responsedata[2048] = {0};
|
||||
snprintf(
|
||||
responsedata,
|
||||
sizeof(responsedata),
|
||||
"{\"success\": true}"
|
||||
);
|
||||
request_with_token *requestdata = check_body(hm);
|
||||
const bool valid = jwt_verifyJWT(requestdata->token, JWT_DEFAULT_SECRET);
|
||||
if (!valid) {
|
||||
mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("invalid token"));
|
||||
return;
|
||||
}
|
||||
char responsedata[64] = {0};
|
||||
snprintf(responsedata, sizeof(responsedata), "{\"success\": true}");
|
||||
|
||||
mg_http_reply(
|
||||
c,
|
||||
200,
|
||||
"Content-Type: application/json\r\n",
|
||||
responsedata
|
||||
);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", responsedata);
|
||||
}
|
||||
+11
-20
@@ -1,26 +1,17 @@
|
||||
#include "user.h"
|
||||
#include "jwt.h"
|
||||
#include "user.h"
|
||||
#include "utils.h"
|
||||
|
||||
void change_user(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
request_with_token *requestdata = check_body(hm);
|
||||
const bool valid = jwt_verifyJWT(requestdata->token, JWT_DEFAULT_SECRET);
|
||||
if (!valid) {
|
||||
mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("invalid token"));
|
||||
return;
|
||||
}
|
||||
char responsedata[2048] = {0};
|
||||
snprintf(
|
||||
responsedata,
|
||||
sizeof(responsedata),
|
||||
"{\"success\": true}"
|
||||
);
|
||||
request_with_token *requestdata = check_body(hm);
|
||||
const bool valid = jwt_verifyJWT(requestdata->token, JWT_DEFAULT_SECRET);
|
||||
if (!valid) {
|
||||
mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("invalid token"));
|
||||
return;
|
||||
}
|
||||
char responsedata[2048] = {0};
|
||||
snprintf(responsedata, sizeof(responsedata), "{\"success\": true}");
|
||||
|
||||
mg_http_reply(
|
||||
c,
|
||||
200,
|
||||
"Content-Type: application/json\r\n",
|
||||
responsedata
|
||||
);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", responsedata);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "database.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "sql.h"
|
||||
#include <string.h>
|
||||
|
||||
sqlite3* db = nullptr;
|
||||
pthread_mutex_t db_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void init_db() {
|
||||
if (sqlite3_open("users.db", &db) != SQLITE_OK) {
|
||||
fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void migrate_db() {
|
||||
char *err_msg = 0;
|
||||
pthread_mutex_lock(&db_mutex);
|
||||
if (sqlite3_exec(db, CREATE_TABLE_USERS, nullptr, nullptr, &err_msg) !=
|
||||
SQLITE_OK) {
|
||||
fprintf(stderr, "SQL error: %s\n", err_msg);
|
||||
sqlite3_free(err_msg);
|
||||
sqlite3_close(db);
|
||||
exit(1);
|
||||
}
|
||||
pthread_mutex_unlock(&db_mutex);
|
||||
}
|
||||
|
||||
// Вспомогательная функция для экранирования специальных символов в JSON
|
||||
char* json_escape(const char* str) {
|
||||
if (!str) return NULL;
|
||||
|
||||
size_t len = strlen(str);
|
||||
// Выделяем память с запасом (каждый символ может быть экранирован)
|
||||
char* escaped = malloc(len * 6 + 1);
|
||||
if (!escaped) return NULL;
|
||||
|
||||
char* p = escaped;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
switch (str[i]) {
|
||||
case '\"': strcpy(p, "\\\""); p += 2; break;
|
||||
case '\\': strcpy(p, "\\\\"); p += 2; break;
|
||||
case '\b': strcpy(p, "\\b"); p += 2; break;
|
||||
case '\f': strcpy(p, "\\f"); p += 2; break;
|
||||
case '\n': strcpy(p, "\\n"); p += 2; break;
|
||||
case '\r': strcpy(p, "\\r"); p += 2; break;
|
||||
case '\t': strcpy(p, "\\t"); p += 2; break;
|
||||
default:
|
||||
if (str[i] < 0x20) {
|
||||
sprintf(p, "\\u%04x", (unsigned char)str[i]);
|
||||
p += 6;
|
||||
} else {
|
||||
*p++ = str[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
|
||||
return escaped;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <pthread.h>
|
||||
|
||||
extern sqlite3 *db;
|
||||
extern pthread_mutex_t db_mutex;
|
||||
|
||||
void init_db();
|
||||
void migrate_db();
|
||||
char* json_escape(const char* str);
|
||||
@@ -0,0 +1,99 @@
|
||||
#include "database.h"
|
||||
#include "sql.h"
|
||||
#include "user.h"
|
||||
#include <string.h>
|
||||
|
||||
char *db_get_all_users() {
|
||||
pthread_mutex_lock(&db_mutex);
|
||||
if (!db) {
|
||||
fprintf(stderr, "Database not initialized\n");
|
||||
pthread_mutex_unlock(&db_mutex);
|
||||
return nullptr;
|
||||
}
|
||||
sqlite3_stmt *stmt;
|
||||
int rc;
|
||||
|
||||
rc = sqlite3_prepare_v2(db, SELECT_ALL_USERS_SQL, -1, &stmt, nullptr);
|
||||
if (rc != SQLITE_OK) {
|
||||
fprintf(stderr, "Cannot prepare statement: %s\n", sqlite3_errmsg(db));
|
||||
pthread_mutex_unlock(&db_mutex);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char *result = malloc(1024);
|
||||
if (!result) {
|
||||
sqlite3_finalize(stmt);
|
||||
pthread_mutex_unlock(&db_mutex);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
strcpy(result, "[");
|
||||
size_t result_size = strlen(result);
|
||||
size_t result_capacity = 1024;
|
||||
|
||||
int first_record = 1;
|
||||
|
||||
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
|
||||
int id = sqlite3_column_int(stmt, 0);
|
||||
const unsigned char *username = sqlite3_column_text(stmt, 1);
|
||||
const unsigned char *email = sqlite3_column_text(stmt, 2);
|
||||
const unsigned char *group = sqlite3_column_text(stmt, 4);
|
||||
int is_superuser = sqlite3_column_int(stmt, 5);
|
||||
|
||||
char *escaped_username = json_escape((const char *) username);
|
||||
char *escaped_email = json_escape((const char *) email);
|
||||
char *escaped_group = json_escape((const char *) group);
|
||||
if (!escaped_username || !escaped_email || !escaped_group) {
|
||||
free(escaped_username);
|
||||
free(escaped_email);
|
||||
free(escaped_group);
|
||||
sqlite3_finalize(stmt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char record[512];
|
||||
if (sqlite3_column_type(stmt, 2) == SQLITE_NULL) {
|
||||
snprintf(record, sizeof(record),
|
||||
"%s{\"id\":%d,\"username\":\"%s\",\"email\":\"%s\",\"group\":"
|
||||
"\"%s\",\"is_superuser\":%s}",
|
||||
first_record ? "" : ",", id, escaped_username, escaped_email,
|
||||
escaped_group, is_superuser ? "true" : "false");
|
||||
} else {
|
||||
snprintf(record, sizeof(record),
|
||||
"%s{\"id\":%d,\"username\":\"%s\",\"email\":\"%s\",\"group\":"
|
||||
"\"%s\",\"is_superuser\":%s}",
|
||||
first_record ? "" : ",", id, escaped_username, escaped_email,
|
||||
escaped_group, is_superuser ? "true" : "false");
|
||||
}
|
||||
|
||||
free(escaped_username);
|
||||
free(escaped_email);
|
||||
free(escaped_group);
|
||||
|
||||
size_t record_len = strlen(record);
|
||||
if (result_size + record_len + 10 > result_capacity) {
|
||||
result_capacity *= 2;
|
||||
char *new_result = realloc(result, result_capacity);
|
||||
if (!new_result) {
|
||||
free(result);
|
||||
sqlite3_finalize(stmt);
|
||||
return nullptr;
|
||||
}
|
||||
result = new_result;
|
||||
}
|
||||
strcat(result, record);
|
||||
result_size += record_len;
|
||||
first_record = 0;
|
||||
}
|
||||
|
||||
if (rc != SQLITE_DONE) {
|
||||
fprintf(stderr, "Error reading data: %s\n", sqlite3_errmsg(db));
|
||||
free(result);
|
||||
sqlite3_finalize(stmt);
|
||||
return NULL;
|
||||
}
|
||||
strcat(result, "]");
|
||||
sqlite3_finalize(stmt);
|
||||
pthread_mutex_unlock(&db_mutex);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "database.h"
|
||||
#include "sql.h"
|
||||
#include "user.h"
|
||||
|
||||
User *db_get_user_by_username(const char *username) {
|
||||
User *user = nullptr;
|
||||
pthread_mutex_lock(&db_mutex);
|
||||
if (!db) {
|
||||
fprintf(stderr, "Database not initialized\n");
|
||||
pthread_mutex_unlock(&db_mutex);
|
||||
return nullptr;
|
||||
}
|
||||
sqlite3_stmt *stmt;
|
||||
int rc =
|
||||
sqlite3_prepare_v2(db, SELECT_USER_BY_USERNAME_SQL, -1, &stmt, nullptr);
|
||||
if (rc != SQLITE_OK) {
|
||||
fprintf(stderr, "Cannot prepare statement: %s\n", sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC);
|
||||
|
||||
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
|
||||
int id = sqlite3_column_int(stmt, 0);
|
||||
const unsigned char *db_username = sqlite3_column_text(stmt, 1);
|
||||
const unsigned char *db_email = sqlite3_column_text(stmt, 2);
|
||||
const unsigned char *db_password = sqlite3_column_text(stmt, 3);
|
||||
const unsigned char *db_group = sqlite3_column_text(stmt, 4);
|
||||
int db_is_superuser = sqlite3_column_int(stmt, 5);
|
||||
user = new_user(id, (char *) db_username, (char *) db_password,
|
||||
(char *) db_email, (char *) db_group, db_is_superuser);
|
||||
}
|
||||
|
||||
if (rc != SQLITE_DONE) {
|
||||
fprintf(stderr, "Error reading data: %s\n", sqlite3_errmsg(db));
|
||||
free_user(user);
|
||||
sqlite3_finalize(stmt);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&db_mutex);
|
||||
return user;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#include <cJSON.h>
|
||||
#include <sqlite3.h>
|
||||
#include "sql.h"
|
||||
#include "user.h"
|
||||
#include "file.h"
|
||||
#include "database.h"
|
||||
|
||||
void db_get_users_from_file(const char *path) {
|
||||
char *users_string = read_file(path);
|
||||
cJSON *json_array = cJSON_Parse(users_string);
|
||||
pthread_mutex_lock(&db_mutex);
|
||||
for (int i = 0; i < cJSON_GetArraySize(json_array); i++) {
|
||||
cJSON *json_object = cJSON_GetArrayItem(json_array, i);
|
||||
const char *username =
|
||||
cJSON_GetObjectItem(json_object, "username")->valuestring;
|
||||
const char *email = cJSON_GetObjectItem(json_object, "email")->valuestring;
|
||||
const char *password =
|
||||
cJSON_GetObjectItem(json_object, "password")->valuestring;
|
||||
const char *group = cJSON_GetObjectItem(json_object, "group")->valuestring;
|
||||
const bool is_superuser =
|
||||
cJSON_GetObjectItem(json_object, "is_superuser")->valueint;
|
||||
|
||||
sqlite3_stmt *stmt;
|
||||
int rc = sqlite3_prepare_v2(db, INSERT_USER_SQL, -1, &stmt, nullptr);
|
||||
if (rc != SQLITE_OK) {
|
||||
fprintf(stderr, "Cannot prepare statement: %s\n", sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 2, email, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 3, password, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 4, group, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_int(stmt, 5, is_superuser);
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
if (rc != SQLITE_DONE) {
|
||||
fprintf(stderr, "Cannot insert data: %s\n", sqlite3_errmsg(db));
|
||||
} else {
|
||||
printf("Record inserted successfully. Row ID: %lld\n",
|
||||
sqlite3_last_insert_rowid(db));
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
cJSON_Delete(json_array);
|
||||
free(users_string);
|
||||
pthread_mutex_unlock(&db_mutex);
|
||||
}
|
||||
+11
-20
@@ -1,26 +1,17 @@
|
||||
#include "user.h"
|
||||
#include "jwt.h"
|
||||
#include "user.h"
|
||||
#include "utils.h"
|
||||
|
||||
void delete_user(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
request_with_token *requestdata = check_body(hm);
|
||||
const bool valid = jwt_verifyJWT(requestdata->token, JWT_DEFAULT_SECRET);
|
||||
if (!valid) {
|
||||
mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("invalid token"));
|
||||
return;
|
||||
}
|
||||
char responsedata[2048] = {0};
|
||||
snprintf(
|
||||
responsedata,
|
||||
sizeof(responsedata),
|
||||
"{\"success\": true}"
|
||||
);
|
||||
request_with_token *requestdata = check_body(hm);
|
||||
const bool valid = jwt_verifyJWT(requestdata->token, JWT_DEFAULT_SECRET);
|
||||
if (!valid) {
|
||||
mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("invalid token"));
|
||||
return;
|
||||
}
|
||||
char responsedata[2048] = {0};
|
||||
snprintf(responsedata, sizeof(responsedata), "{\"success\": true}");
|
||||
|
||||
mg_http_reply(
|
||||
c,
|
||||
200,
|
||||
"Content-Type: application/json\r\n",
|
||||
responsedata
|
||||
);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", responsedata);
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
#include "file.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
char *read_file(const char *path) {
|
||||
FILE *fp = fopen(path, "rb");
|
||||
if (fp == NULL) {
|
||||
perror("Error opening file");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
long file_size = ftell(fp);
|
||||
rewind(fp);
|
||||
|
||||
char *buffer = (char *) malloc(file_size + 1);
|
||||
if (!buffer) {
|
||||
perror("Error allocating memory");
|
||||
fclose(fp);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t bytes_read = fread(buffer, 1, file_size, fp);
|
||||
if (bytes_read != file_size) {
|
||||
perror("Error reading file");
|
||||
free(buffer);
|
||||
fclose(fp);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
buffer[file_size] = '\0';
|
||||
fclose(fp);
|
||||
return buffer;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
char *read_file(const char *path);
|
||||
+16
-28
@@ -1,3 +1,4 @@
|
||||
#include "jwt.h"
|
||||
#include "user.h"
|
||||
#include "utils.h"
|
||||
|
||||
@@ -7,33 +8,20 @@ void get_all_users(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"), MG_ESC(data->error));
|
||||
return;
|
||||
}
|
||||
free_request_with_token(data);
|
||||
|
||||
User users[2] = {{.id = 1,
|
||||
.username = "tola",
|
||||
.email = "mail@example.com",
|
||||
.password = "passsword",
|
||||
.group = "root",
|
||||
.is_superuser = true},
|
||||
{.id = 2,
|
||||
.username = "lisa",
|
||||
.email = "mail@example.com",
|
||||
.password = "asdf",
|
||||
.group = "users",
|
||||
.is_superuser = false}};
|
||||
char msg[2048] = {0};
|
||||
strncpy(msg, "[", sizeof(msg));
|
||||
for (int i = 0; i < sizeof(users) / sizeof(User); i++) {
|
||||
snprintf(msg + strlen(msg), sizeof(msg) - strlen(msg),
|
||||
"{\"%s\":%d,\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":\"%"
|
||||
"s\",\"%s\":%d}",
|
||||
"id", users[i].id, "username", users[i].username, "email",
|
||||
users[i].email, "password", users[i].password, "group",
|
||||
users[i].group, "is_superuser", users[i].is_superuser);
|
||||
if (i < sizeof(users) / sizeof(User) - 1) {
|
||||
strncat(msg, ",", strlen(msg));
|
||||
}
|
||||
if (!jwt_verifyJWT(data->token, JWT_DEFAULT_SECRET)) {
|
||||
mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("invalid token"));
|
||||
return;
|
||||
}
|
||||
strncat(msg, "]\n", strlen(msg));
|
||||
mg_http_reply(c, 200, "Content-type: application/json\r\n", msg);
|
||||
cJSON *payload = jwt_get_payload(data->token);
|
||||
bool is_superuser = cJSON_GetObjectItem(payload, "is_superuser")->valueint;
|
||||
if (!is_superuser) {
|
||||
mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("user is not superuser"));
|
||||
return;
|
||||
}
|
||||
char *all_users = db_get_all_users();
|
||||
mg_http_reply(c, 200, "Content-type: application/json\r\n", all_users);
|
||||
free(all_users);
|
||||
free_request_with_token(data);
|
||||
}
|
||||
+22
-3
@@ -1,5 +1,5 @@
|
||||
#include "user.h"
|
||||
#include "jwt.h"
|
||||
#include "user.h"
|
||||
|
||||
void get_token(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
if (hm->body.len == 0) {
|
||||
@@ -20,9 +20,28 @@ void get_token(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
MG_ESC("must have username and password"));
|
||||
return;
|
||||
}
|
||||
User *db_user = db_get_user_by_username(username->valuestring);
|
||||
if (!db_user) {
|
||||
mg_http_reply(c, 400, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("couldn't find user"));
|
||||
return;
|
||||
}
|
||||
if (strcmp(db_user->password, password->valuestring)) {
|
||||
mg_http_reply(c, 400, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("wrong password"));
|
||||
return;
|
||||
}
|
||||
const char *header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}";
|
||||
const char *payload = "{\"sub\": \"1234567890\",\"username\": "
|
||||
"\"tola\",\"is_superuser\": true,\"iat\": 1516239022}";
|
||||
char payload[1024];
|
||||
snprintf(payload, sizeof(payload),
|
||||
"{\"id\": %d,\"username\": "
|
||||
"\"%s\",\"email\": "
|
||||
"\"%s\",\"group\": "
|
||||
"\"%s\",\"is_superuser\": %s}",
|
||||
db_user->id, db_user->username, db_user->email, db_user->group,
|
||||
db_user->is_superuser ? "true" : "false");
|
||||
char *token = jwt_createJWT(header, payload, JWT_DEFAULT_SECRET);
|
||||
mg_http_reply(c, 200, "", "{%m:%m}", MG_ESC("token"), MG_ESC(token));
|
||||
free_user(db_user);
|
||||
free(token);
|
||||
}
|
||||
+31
-30
@@ -1,36 +1,37 @@
|
||||
#include "user.h"
|
||||
#include "jwt.h"
|
||||
#include "user.h"
|
||||
#include "utils.h"
|
||||
|
||||
void get_user(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
request_with_token *requestdata = check_body(hm);
|
||||
const bool valid = jwt_verifyJWT(requestdata->token, JWT_DEFAULT_SECRET);
|
||||
if (!valid) {
|
||||
mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("invalid token"));
|
||||
return;
|
||||
}
|
||||
const User *user = new_user("username", "", "mail@example.com", "root", true);
|
||||
if (user == NULL) {
|
||||
mg_http_reply(c, 404, "", "{%m:%m}", MG_ESC("error"), MG_ESC("user not found"));
|
||||
return;
|
||||
}
|
||||
char responsedata[2048] = {0};
|
||||
snprintf(
|
||||
responsedata,
|
||||
sizeof(responsedata),
|
||||
"{\"id\": %d, \"username\": \"%s\", \"email\": \"%s\", \"group\": \"%s\", \"is_superuser\": %s}",
|
||||
user->id,
|
||||
user->username,
|
||||
user->email,
|
||||
user->group,
|
||||
user->is_superuser ? "true" : "false"
|
||||
);
|
||||
request_with_token *requestdata = check_body(hm);
|
||||
if (!jwt_verifyJWT(requestdata->token, JWT_DEFAULT_SECRET)) {
|
||||
free_request_with_token(requestdata);
|
||||
mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("invalid token"));
|
||||
return;
|
||||
}
|
||||
cJSON *payload = jwt_get_payload(requestdata->token);
|
||||
char *username =
|
||||
strdup(cJSON_GetObjectItem(payload, "username")->valuestring);
|
||||
User *user = db_get_user_by_username(username);
|
||||
if (!user) {
|
||||
free_request_with_token(requestdata);
|
||||
cJSON_Delete(payload);
|
||||
free(username);
|
||||
mg_http_reply(c, 404, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("user not found"));
|
||||
return;
|
||||
}
|
||||
char responsedata[2048] = {0};
|
||||
snprintf(responsedata, sizeof(responsedata),
|
||||
"{\"id\": %d, \"username\": \"%s\", \"email\": \"%s\", \"group\": "
|
||||
"\"%s\", \"is_superuser\": %s}",
|
||||
user->id, user->username, user->email, user->group,
|
||||
user->is_superuser ? "true" : "false");
|
||||
|
||||
mg_http_reply(
|
||||
c,
|
||||
200,
|
||||
"Content-Type: application/json\r\n",
|
||||
responsedata
|
||||
);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", responsedata);
|
||||
free_request_with_token(requestdata);
|
||||
free(username);
|
||||
free_user(user);
|
||||
cJSON_Delete(payload);
|
||||
}
|
||||
@@ -21,7 +21,7 @@ static void base64_to_base64url(char *str) {
|
||||
else if (*p == '/')
|
||||
*p = '_';
|
||||
}
|
||||
remove_padding(str); // Удаляем паддинг
|
||||
remove_padding(str); // Удаляем паддинг
|
||||
}
|
||||
|
||||
// Преобразует Base64URL в Base64
|
||||
@@ -57,28 +57,27 @@ char *jwt_base64url_encode(const unsigned char *input, const int length) {
|
||||
BUF_MEM *bufferPtr;
|
||||
BIO_get_mem_ptr(bio, &bufferPtr);
|
||||
|
||||
const auto result = (char *)malloc(bufferPtr->length + 1);
|
||||
const auto result = (char *) malloc(bufferPtr->length + 1);
|
||||
memcpy(result, bufferPtr->data, bufferPtr->length);
|
||||
result[bufferPtr->length] = '\0';
|
||||
|
||||
BIO_free_all(bio);
|
||||
|
||||
base64_to_base64url(result); // Преобразование в Base64URL
|
||||
base64_to_base64url(result); // Преобразование в Base64URL
|
||||
return result;
|
||||
}
|
||||
|
||||
// Base64URL декодирование
|
||||
unsigned char *jwt_base64url_decode(const char *input, int input_len,
|
||||
int *output_len) {
|
||||
if (input_len == 0)
|
||||
input_len = strlen(input);
|
||||
if (input_len == 0) input_len = strlen(input);
|
||||
|
||||
// Создаем копию для преобразования
|
||||
const auto input_copy = (char *)malloc(input_len + 1);
|
||||
const auto input_copy = (char *) malloc(input_len + 1);
|
||||
strncpy(input_copy, input, input_len);
|
||||
input_copy[input_len] = '\0';
|
||||
|
||||
base64url_to_base64(input_copy); // Преобразование в Base64
|
||||
base64url_to_base64(input_copy); // Преобразование в Base64
|
||||
|
||||
BIO *b64 = BIO_new(BIO_f_base64());
|
||||
BIO *bio = BIO_new_mem_buf(input_copy, -1);
|
||||
@@ -86,7 +85,7 @@ unsigned char *jwt_base64url_decode(const char *input, int input_len,
|
||||
|
||||
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
const auto buffer = (unsigned char *)malloc(input_len);
|
||||
const auto buffer = (unsigned char *) malloc(input_len);
|
||||
const int len = BIO_read(bio, buffer, input_len);
|
||||
|
||||
BIO_free_all(bio);
|
||||
@@ -105,13 +104,13 @@ unsigned char *jwt_base64url_decode(const char *input, int input_len,
|
||||
// Создание JWT токена
|
||||
char *jwt_createJWT(const char *header_json, const char *payload_json,
|
||||
const char *secret) {
|
||||
char *encodedHeader = jwt_base64url_encode((const unsigned char *)header_json,
|
||||
strlen(header_json));
|
||||
char *encodedHeader = jwt_base64url_encode(
|
||||
(const unsigned char *) header_json, strlen(header_json));
|
||||
char *encodedPayload = jwt_base64url_encode(
|
||||
(const unsigned char *)payload_json, strlen(payload_json));
|
||||
(const unsigned char *) payload_json, strlen(payload_json));
|
||||
|
||||
char *unsignedToken =
|
||||
(char *)malloc(strlen(encodedHeader) + strlen(encodedPayload) + 2);
|
||||
(char *) malloc(strlen(encodedHeader) + strlen(encodedPayload) + 2);
|
||||
sprintf(unsignedToken, "%s.%s", encodedHeader, encodedPayload);
|
||||
|
||||
unsigned int digest_len;
|
||||
@@ -120,7 +119,7 @@ char *jwt_createJWT(const char *header_json, const char *payload_json,
|
||||
char *encodedSignature = jwt_base64url_encode(digest, digest_len);
|
||||
|
||||
char *jwt =
|
||||
(char *)malloc(strlen(unsignedToken) + strlen(encodedSignature) + 2);
|
||||
(char *) malloc(strlen(unsignedToken) + strlen(encodedSignature) + 2);
|
||||
sprintf(jwt, "%s.%s", unsignedToken, encodedSignature);
|
||||
|
||||
free(encodedHeader);
|
||||
@@ -135,8 +134,8 @@ char *jwt_createJWT(const char *header_json, const char *payload_json,
|
||||
// Генерация HMAC-SHA256
|
||||
unsigned char *jwt_hmac_sha256(const char *key, int key_len, const char *data,
|
||||
int data_len, unsigned int *digest_len) {
|
||||
unsigned char *digest = (unsigned char *)malloc(EVP_MAX_MD_SIZE);
|
||||
HMAC(EVP_sha256(), key, key_len, (const unsigned char *)data, data_len,
|
||||
unsigned char *digest = (unsigned char *) malloc(EVP_MAX_MD_SIZE);
|
||||
HMAC(EVP_sha256(), key, key_len, (const unsigned char *) data, data_len,
|
||||
digest, digest_len);
|
||||
return digest;
|
||||
}
|
||||
@@ -145,24 +144,23 @@ unsigned char *jwt_hmac_sha256(const char *key, int key_len, const char *data,
|
||||
bool jwt_verifyJWT(const char *token, const char *secret) {
|
||||
const char *dot1 = strchr(token, '.');
|
||||
const char *dot2 = dot1 ? strchr(dot1 + 1, '.') : nullptr;
|
||||
if (!dot1 || !dot2)
|
||||
return false;
|
||||
if (!dot1 || !dot2) return false;
|
||||
|
||||
size_t header_len = dot1 - token;
|
||||
size_t payload_len = dot2 - dot1 - 1;
|
||||
size_t sig_len = strlen(dot2 + 1);
|
||||
|
||||
char *header = (char *)malloc(header_len + 1);
|
||||
char *header = (char *) malloc(header_len + 1);
|
||||
strncpy(header, token, header_len);
|
||||
header[header_len] = '\0';
|
||||
|
||||
char *payload = (char *)malloc(payload_len + 1);
|
||||
char *payload = (char *) malloc(payload_len + 1);
|
||||
strncpy(payload, dot1 + 1, payload_len);
|
||||
payload[payload_len] = '\0';
|
||||
|
||||
char *signature = strndup(dot2 + 1, sig_len);
|
||||
|
||||
char *signing_input = (char *)malloc(header_len + payload_len + 2);
|
||||
char *signing_input = (char *) malloc(header_len + payload_len + 2);
|
||||
sprintf(signing_input, "%s.%s", header, payload);
|
||||
|
||||
int expected_sig_len;
|
||||
@@ -183,7 +181,7 @@ bool jwt_verifyJWT(const char *token, const char *secret) {
|
||||
int payload_bin_len;
|
||||
unsigned char *payload_bin =
|
||||
jwt_base64url_decode(payload, payload_len, &payload_bin_len);
|
||||
char *payload_str = (char *)malloc(payload_bin_len + 1);
|
||||
char *payload_str = (char *) malloc(payload_bin_len + 1);
|
||||
memcpy(payload_str, payload_bin, payload_bin_len);
|
||||
payload_str[payload_bin_len] = '\0';
|
||||
|
||||
@@ -192,7 +190,7 @@ bool jwt_verifyJWT(const char *token, const char *secret) {
|
||||
cJSON *exp = cJSON_GetObjectItemCaseSensitive(json_payload, "exp");
|
||||
if (cJSON_IsNumber(exp)) {
|
||||
time_t now = time(nullptr);
|
||||
if (now >= (time_t)exp->valuedouble) {
|
||||
if (now >= (time_t) exp->valuedouble) {
|
||||
exp_valid = false;
|
||||
}
|
||||
}
|
||||
@@ -216,18 +214,17 @@ bool jwt_verifyJWT(const char *token, const char *secret) {
|
||||
cJSON *jwt_get_payload(const char *token) {
|
||||
const char *dot1 = strchr(token, '.');
|
||||
const char *dot2 = dot1 ? strchr(dot1 + 1, '.') : nullptr;
|
||||
if (!dot1 || !dot2)
|
||||
return nullptr;
|
||||
if (!dot1 || !dot2) return nullptr;
|
||||
|
||||
size_t payload_len = dot2 - dot1 - 1;
|
||||
char *payload = (char *)malloc(payload_len + 1);
|
||||
char *payload = (char *) malloc(payload_len + 1);
|
||||
strncpy(payload, dot1 + 1, payload_len);
|
||||
payload[payload_len] = '\0';
|
||||
|
||||
int payload_bin_len;
|
||||
unsigned char *payload_bin =
|
||||
jwt_base64url_decode(payload, payload_len, &payload_bin_len);
|
||||
char *payload_str = (char *)malloc(payload_bin_len + 1);
|
||||
char *payload_str = (char *) malloc(payload_bin_len + 1);
|
||||
memcpy(payload_str, payload_bin, payload_bin_len);
|
||||
payload_str[payload_bin_len] = '\0';
|
||||
|
||||
@@ -243,18 +240,17 @@ cJSON *jwt_get_payload(const char *token) {
|
||||
// Получение header из токена
|
||||
cJSON *jwt_get_header(const char *token) {
|
||||
const char *dot1 = strchr(token, '.');
|
||||
if (!dot1)
|
||||
return nullptr;
|
||||
if (!dot1) return nullptr;
|
||||
|
||||
size_t header_len = dot1 - token;
|
||||
char *header = (char *)malloc(header_len + 1);
|
||||
char *header = (char *) malloc(header_len + 1);
|
||||
strncpy(header, token, header_len);
|
||||
header[header_len] = '\0';
|
||||
|
||||
int header_bin_len;
|
||||
unsigned char *header_bin =
|
||||
jwt_base64url_decode(header, header_len, &header_bin_len);
|
||||
char *header_str = (char *)malloc(header_bin_len + 1);
|
||||
char *header_str = (char *) malloc(header_bin_len + 1);
|
||||
memcpy(header_str, header_bin, header_bin_len);
|
||||
header_str[header_bin_len] = '\0';
|
||||
|
||||
|
||||
@@ -21,4 +21,4 @@ bool jwt_verifyJWT(const char *token, const char *secret);
|
||||
cJSON *jwt_get_payload(const char *token);
|
||||
cJSON *jwt_get_header(const char *token);
|
||||
|
||||
#endif // JWT_H
|
||||
#endif // JWT_H
|
||||
+20
-12
@@ -1,10 +1,13 @@
|
||||
#include "user.h"
|
||||
#include <mongoose.h>
|
||||
#include <sqlite3.h>
|
||||
#include "database.h"
|
||||
#include "route.h"
|
||||
#include "sql.h"
|
||||
#include "user.h"
|
||||
|
||||
static void root_handler(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
struct mg_http_serve_opts opts = {.root_dir = "./web/"};
|
||||
mg_http_serve_dir(c, hm, &opts);
|
||||
struct mg_http_serve_opts opts = {.root_dir = "./web/"};
|
||||
mg_http_serve_dir(c, hm, &opts);
|
||||
}
|
||||
|
||||
static const struct route routes[] = {
|
||||
@@ -18,28 +21,33 @@ static const struct route routes[] = {
|
||||
{"POST", "/api/users/change", change_password},
|
||||
{"POST", "/api/users/add", add_user},
|
||||
{"POST", "/api/register", register_user},
|
||||
{nullptr, nullptr, nullptr}
|
||||
};
|
||||
{nullptr, nullptr, nullptr}};
|
||||
|
||||
void ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
const auto hm = (struct mg_http_message *)ev_data;
|
||||
const auto hm = (struct mg_http_message *) ev_data;
|
||||
bool route_found = false;
|
||||
|
||||
for (int i = 0; routes[i].path != nullptr; i++) {
|
||||
if (mg_match(hm->uri, mg_str(routes[i].path), nullptr) && mg_match(hm->method, mg_str(routes[i].method), nullptr)) {
|
||||
routes[i].handler(c, hm);
|
||||
route_found = true;
|
||||
break;
|
||||
}
|
||||
if (mg_match(hm->uri, mg_str(routes[i].path), nullptr) &&
|
||||
mg_match(hm->method, mg_str(routes[i].method), nullptr)) {
|
||||
routes[i].handler(c, hm);
|
||||
route_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!route_found) {
|
||||
mg_http_reply(c, 404, "", "{%m:%m}", MG_ESC("error"), MG_ESC("URI not found"));
|
||||
mg_http_reply(c, 404, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("URI not found"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
init_db();
|
||||
migrate_db();
|
||||
db_get_users_from_file("users.json");
|
||||
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0:8222", ev_handler, nullptr);
|
||||
|
||||
+39
-50
@@ -1,55 +1,44 @@
|
||||
#include "user.h"
|
||||
|
||||
void register_user(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
if (hm->body.len == 0) {
|
||||
mg_http_reply(c, 400, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("must have <username>, <password>, <email>, <group, optional>, <is_superuser, optional>"));
|
||||
return;
|
||||
}
|
||||
cJSON *jsonbody = cJSON_Parse(hm->body.buf);
|
||||
cJSON *username = cJSON_GetObjectItem(jsonbody, "username");
|
||||
cJSON *password = cJSON_GetObjectItem(jsonbody, "password");
|
||||
cJSON *email = cJSON_GetObjectItem(jsonbody, "email");
|
||||
cJSON *group = cJSON_GetObjectItem(jsonbody, "group");
|
||||
cJSON *is_superuser = cJSON_GetObjectItem(jsonbody, "is_superuser");
|
||||
if (username == nullptr || password == nullptr || email == nullptr) {
|
||||
mg_http_reply(c, 400, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("must have <username>, <password>, <email>, <group, optional>, <is_superuser, optional>"));
|
||||
return;
|
||||
}
|
||||
if (group == nullptr) {
|
||||
group = cJSON_CreateString("users");
|
||||
}
|
||||
if (is_superuser == nullptr) {
|
||||
is_superuser = cJSON_CreateBool(false);
|
||||
}
|
||||
const User *new_user_data = new_user(
|
||||
username->valuestring,
|
||||
password->valuestring,
|
||||
email->valuestring,
|
||||
group->valuestring,
|
||||
is_superuser->valueint
|
||||
);
|
||||
if (new_user_data == nullptr) {
|
||||
mg_http_reply(c, 500, "", "{%m:%m}", MG_ESC("error"), MG_ESC("failed to create user"));
|
||||
return;
|
||||
}
|
||||
char responsedata[2048] = {0};
|
||||
snprintf(
|
||||
responsedata,
|
||||
sizeof(responsedata),
|
||||
"{\"id\": %d, \"username\": \"%s\", \"email\": \"%s\", \"group\": \"%s\", \"is_superuser\": %d}",
|
||||
new_user_data->id,
|
||||
new_user_data->username,
|
||||
new_user_data->email,
|
||||
new_user_data->group,
|
||||
new_user_data->is_superuser
|
||||
);
|
||||
if (hm->body.len == 0) {
|
||||
mg_http_reply(c, 400, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("must have <username>, <password>, <email>, <group, "
|
||||
"optional>, <is_superuser, optional>"));
|
||||
return;
|
||||
}
|
||||
cJSON *jsonbody = cJSON_Parse(hm->body.buf);
|
||||
cJSON *username = cJSON_GetObjectItem(jsonbody, "username");
|
||||
cJSON *password = cJSON_GetObjectItem(jsonbody, "password");
|
||||
cJSON *email = cJSON_GetObjectItem(jsonbody, "email");
|
||||
cJSON *group = cJSON_GetObjectItem(jsonbody, "group");
|
||||
cJSON *is_superuser = cJSON_GetObjectItem(jsonbody, "is_superuser");
|
||||
if (username == nullptr || password == nullptr || email == nullptr) {
|
||||
mg_http_reply(c, 400, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("must have <username>, <password>, <email>, <group, "
|
||||
"optional>, <is_superuser, optional>"));
|
||||
return;
|
||||
}
|
||||
if (group == nullptr) {
|
||||
group = cJSON_CreateString("users");
|
||||
}
|
||||
if (is_superuser == nullptr) {
|
||||
is_superuser = cJSON_CreateBool(false);
|
||||
}
|
||||
const User *new_user_data =
|
||||
new_user(0, username->valuestring, password->valuestring, email->valuestring,
|
||||
group->valuestring, is_superuser->valueint);
|
||||
if (new_user_data == nullptr) {
|
||||
mg_http_reply(c, 500, "", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("failed to create user"));
|
||||
return;
|
||||
}
|
||||
char responsedata[2048] = {0};
|
||||
snprintf(responsedata, sizeof(responsedata),
|
||||
"{\"id\": %d, \"username\": \"%s\", \"email\": \"%s\", \"group\": "
|
||||
"\"%s\", \"is_superuser\": %d}",
|
||||
new_user_data->id, new_user_data->username, new_user_data->email,
|
||||
new_user_data->group, new_user_data->is_superuser);
|
||||
|
||||
mg_http_reply(
|
||||
c,
|
||||
200,
|
||||
"Content-Type: application/json\r\n",
|
||||
responsedata
|
||||
);
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", responsedata);
|
||||
}
|
||||
+5
-4
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
typedef void (*route_handler_t)(struct mg_connection *c, struct mg_http_message *hm);
|
||||
typedef void (*route_handler_t)(struct mg_connection *c,
|
||||
struct mg_http_message *hm);
|
||||
|
||||
struct route {
|
||||
char *method;
|
||||
char *path;
|
||||
route_handler_t handler;
|
||||
char *method;
|
||||
char *path;
|
||||
route_handler_t handler;
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#define CREATE_TABLE_USERS \
|
||||
"create table if not exists users(" \
|
||||
"id integer primary key autoincrement," \
|
||||
"username text unique," \
|
||||
"email char(50) unique," \
|
||||
"password char(150) not null," \
|
||||
"user_group char(50) default 'users'," \
|
||||
"is_superuser boolean default false" \
|
||||
");"
|
||||
|
||||
#define INSERT_USER_SQL \
|
||||
"INSERT INTO users (username, email, password, user_group, is_superuser) " \
|
||||
"VALUES (?, ?, ?, ?, ?)"
|
||||
|
||||
#define SELECT_ALL_USERS_SQL "select * from users"
|
||||
#define SELECT_USER_BY_USERNAME_SQL "select * from users where username = ?"
|
||||
|
||||
+21
-13
@@ -1,6 +1,4 @@
|
||||
#include "user.h"
|
||||
#include "jwt.h"
|
||||
#include "utils.h"
|
||||
#include <cJSON.h>
|
||||
#include <mongoose.h>
|
||||
|
||||
@@ -26,15 +24,25 @@ void free_request_with_token(request_with_token *data) {
|
||||
free(data);
|
||||
}
|
||||
|
||||
User *new_user(const char *username, const char *password, const char *email, const char *group, bool is_superuser) {
|
||||
User *user = malloc(sizeof(User));
|
||||
if (user == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
user->username = strdup(username);
|
||||
user->password = strdup(password);
|
||||
user->email = strdup(email);
|
||||
user->group = strdup(group);
|
||||
user->is_superuser = is_superuser;
|
||||
return user;
|
||||
User *new_user(int id, const char *username, const char *password, const char *email,
|
||||
const char *group, bool is_superuser) {
|
||||
User *user = malloc(sizeof(User));
|
||||
if (user == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
user->id = id;
|
||||
user->username = strdup(username);
|
||||
user->password = strdup(password);
|
||||
user->email = strdup(email);
|
||||
user->group = strdup(group);
|
||||
user->is_superuser = is_superuser;
|
||||
return user;
|
||||
}
|
||||
|
||||
void free_user(User *user) {
|
||||
free(user->username);
|
||||
free(user->password);
|
||||
free(user->email);
|
||||
free(user->group);
|
||||
free(user);
|
||||
}
|
||||
+14
-7
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <cJSON.h>
|
||||
#include <mongoose.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
typedef struct User {
|
||||
int id;
|
||||
@@ -12,15 +13,18 @@ typedef struct User {
|
||||
bool is_superuser;
|
||||
} User;
|
||||
|
||||
User *new_user(const char *username, const char *password, const char *email, const char *group, bool is_superuser);
|
||||
User *new_user(int id, const char *username, const char *password, const char *email,
|
||||
const char *group, bool is_superuser);
|
||||
|
||||
void free_user(User *user);
|
||||
|
||||
typedef struct register_request {
|
||||
char *username;
|
||||
char *email;
|
||||
char *password;
|
||||
char *group;
|
||||
bool is_superuser;
|
||||
char *error;
|
||||
char *username;
|
||||
char *email;
|
||||
char *password;
|
||||
char *group;
|
||||
bool is_superuser;
|
||||
char *error;
|
||||
} register_request;
|
||||
|
||||
typedef struct request_with_token {
|
||||
@@ -48,3 +52,6 @@ void change_password(struct mg_connection *c, struct mg_http_message *hm);
|
||||
void register_user(struct mg_connection *c, struct mg_http_message *hm);
|
||||
void get_token(struct mg_connection *c, struct mg_http_message *hm);
|
||||
void verify_token(struct mg_connection *c, struct mg_http_message *hm);
|
||||
void db_get_users_from_file(const char *filename);
|
||||
char *db_get_all_users();
|
||||
User *db_get_user_by_username(const char *username);
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
#include "utils.h"
|
||||
#include "user.h"
|
||||
#include <cJSON.h>
|
||||
#include <mongoose.h>
|
||||
#include "user.h"
|
||||
|
||||
request_with_token *check_body(const struct mg_http_message *hm) {
|
||||
if (hm->body.len == 0) {
|
||||
return new_request_with_token(nullptr, nullptr, (char *)"must have token");
|
||||
return new_request_with_token(nullptr, nullptr, (char *) "must have token");
|
||||
}
|
||||
|
||||
cJSON *json_body = cJSON_Parse(hm->body.buf);
|
||||
@@ -13,9 +13,9 @@ request_with_token *check_body(const struct mg_http_message *hm) {
|
||||
if (token == NULL) {
|
||||
const char *error_ptr = cJSON_GetErrorPtr();
|
||||
if (error_ptr != NULL) {
|
||||
return new_request_with_token(nullptr, nullptr, (char *)error_ptr);
|
||||
return new_request_with_token(nullptr, nullptr, (char *) error_ptr);
|
||||
}
|
||||
return new_request_with_token(nullptr, nullptr, (char *)"must have token");
|
||||
return new_request_with_token(nullptr, nullptr, (char *) "must have token");
|
||||
}
|
||||
return new_request_with_token(strdup(token->valuestring), json_body, nullptr);
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#include "user.h"
|
||||
#include "jwt.h"
|
||||
#include "user.h"
|
||||
#include "utils.h"
|
||||
|
||||
void verify_token(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
[
|
||||
{
|
||||
"username": "tola",
|
||||
"email": "mail@example.com",
|
||||
"password": "2808",
|
||||
"group": "root",
|
||||
"is_superuser": true
|
||||
},
|
||||
{
|
||||
"username": "lisa",
|
||||
"email": "lisa@example.com",
|
||||
"password": "asdf",
|
||||
"group": "users",
|
||||
"is_superuser": false
|
||||
}
|
||||
]
|
||||
Reference in new issue
Block a user