From c4ea7a4293af29a71bfd4d3daaeaf05cd67d84ac Mon Sep 17 00:00:00 2001 From: TolaMironcenko Date: Tue, 19 Aug 2025 00:01:17 +0700 Subject: [PATCH] added endpoints end refactor --- .gitignore | 1 + Makefile | 2 +- meson.build | 11 ++++- src/add_user.c | 26 ++++++++++++ src/change_password.c | 26 ++++++++++++ src/change_user.c | 26 ++++++++++++ src/delete_user.c | 26 ++++++++++++ src/get_all_users.c | 39 ++++++++++++++++++ src/get_token.c | 28 +++++++++++++ src/get_user.c | 36 +++++++++++++++++ src/main.c | 6 +++ src/register_user.c | 55 +++++++++++++++++++++++++ src/user.c | 93 ++++++------------------------------------- src/user.h | 27 ++++++++++--- src/verify_token.c | 18 +++++++++ 15 files changed, 333 insertions(+), 87 deletions(-) create mode 100644 src/add_user.c create mode 100644 src/change_password.c create mode 100644 src/change_user.c create mode 100644 src/delete_user.c create mode 100644 src/get_all_users.c create mode 100644 src/get_token.c create mode 100644 src/get_user.c create mode 100644 src/register_user.c create mode 100644 src/verify_token.c diff --git a/.gitignore b/.gitignore index 9437b88..543b94f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .cache .idea build +fmongoose diff --git a/Makefile b/Makefile index 2cecf57..a0439b6 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC = gcc -CFLAGS = -Wall -g -std=gnu23 +CFLAGS = -Wall -g -std=gnu2x LDFLAGS = LIBS = -lpthread -lcrypto INCLUDES = -I./src/lib -I./src diff --git a/meson.build b/meson.build index a6eb339..1b50727 100644 --- a/meson.build +++ b/meson.build @@ -1,10 +1,19 @@ -project('fmongoose', 'c', default_options : ['c_std=gnu23']) +project('fmongoose', 'c', default_options: ['c_std=gnu2x']) include_dirs = include_directories('src', 'src/lib') deps = dependency('openssl') executable( 'fmongoose', 'src/main.c', 'src/user.c', + 'src/add_user.c', + 'src/change_password.c', + 'src/change_user.c', + 'src/delete_user.c', + 'src/get_all_users.c', + 'src/get_token.c', + 'src/get_user.c', + 'src/register_user.c', + 'src/verify_token.c', 'src/utils.c', 'src/jwt.c', 'src/lib/mongoose.c', diff --git a/src/add_user.c b/src/add_user.c new file mode 100644 index 0000000..113a4d6 --- /dev/null +++ b/src/add_user.c @@ -0,0 +1,26 @@ +#include "user.h" +#include "jwt.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}" + ); + + mg_http_reply( + c, + 200, + "Content-Type: application/json\r\n", + responsedata + ); +} diff --git a/src/change_password.c b/src/change_password.c new file mode 100644 index 0000000..894e9d6 --- /dev/null +++ b/src/change_password.c @@ -0,0 +1,26 @@ +#include "user.h" +#include "jwt.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}" + ); + + mg_http_reply( + c, + 200, + "Content-Type: application/json\r\n", + responsedata + ); +} diff --git a/src/change_user.c b/src/change_user.c new file mode 100644 index 0000000..cbacc7c --- /dev/null +++ b/src/change_user.c @@ -0,0 +1,26 @@ +#include "user.h" +#include "jwt.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}" + ); + + mg_http_reply( + c, + 200, + "Content-Type: application/json\r\n", + responsedata + ); +} diff --git a/src/delete_user.c b/src/delete_user.c new file mode 100644 index 0000000..a291d25 --- /dev/null +++ b/src/delete_user.c @@ -0,0 +1,26 @@ +#include "user.h" +#include "jwt.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}" + ); + + mg_http_reply( + c, + 200, + "Content-Type: application/json\r\n", + responsedata + ); +} diff --git a/src/get_all_users.c b/src/get_all_users.c new file mode 100644 index 0000000..4dbe711 --- /dev/null +++ b/src/get_all_users.c @@ -0,0 +1,39 @@ +#include "user.h" +#include "utils.h" + +void get_all_users(struct mg_connection *c, struct mg_http_message *hm) { + request_with_token *data = check_body(hm); + if (data->error != NULL) { + 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)); + } + } + strncat(msg, "]\n", strlen(msg)); + mg_http_reply(c, 200, "Content-type: application/json\r\n", msg); +} diff --git a/src/get_token.c b/src/get_token.c new file mode 100644 index 0000000..d232241 --- /dev/null +++ b/src/get_token.c @@ -0,0 +1,28 @@ +#include "user.h" +#include "jwt.h" + +void get_token(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 and password")); + return; + } + cJSON *jsonbody = cJSON_Parse(hm->body.buf); + cJSON *username = cJSON_GetObjectItem(jsonbody, "username"); + cJSON *password = cJSON_GetObjectItem(jsonbody, "password"); + if (username == NULL || password == NULL) { + const char *error_ptr = cJSON_GetErrorPtr(); + if (error_ptr != NULL) { + mg_http_reply(c, 400, "", "{%m:%m}", MG_ESC("error"), MG_ESC(error_ptr)); + return; + } + mg_http_reply(c, 400, "", "{%m:%m}", MG_ESC("error"), + MG_ESC("must have username and password")); + return; + } + const char *header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}"; + const char *payload = "{\"sub\": \"1234567890\",\"username\": " + "\"tola\",\"is_superuser\": true,\"iat\": 1516239022}"; + char *token = jwt_createJWT(header, payload, JWT_DEFAULT_SECRET); + mg_http_reply(c, 200, "", "{%m:%m}", MG_ESC("token"), MG_ESC(token)); +} diff --git a/src/get_user.c b/src/get_user.c new file mode 100644 index 0000000..248355b --- /dev/null +++ b/src/get_user.c @@ -0,0 +1,36 @@ +#include "user.h" +#include "jwt.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" + ); + + mg_http_reply( + c, + 200, + "Content-Type: application/json\r\n", + responsedata + ); +} diff --git a/src/main.c b/src/main.c index d3fea22..bf30e03 100644 --- a/src/main.c +++ b/src/main.c @@ -12,6 +12,12 @@ static const struct route routes[] = { {"POST", "/api/token", get_token}, {"POST", "/api/token/verify", verify_token}, {"POST", "/api/users", get_all_users}, + {"POST", "/api/users/user", get_user}, + {"POST", "/api/users/delete", delete_user}, + {"POST", "/api/users/password", change_password}, + {"POST", "/api/users/change", change_password}, + {"POST", "/api/users/add", add_user}, + {"POST", "/api/register", register_user}, {nullptr, nullptr, nullptr} }; diff --git a/src/register_user.c b/src/register_user.c new file mode 100644 index 0000000..52054b3 --- /dev/null +++ b/src/register_user.c @@ -0,0 +1,55 @@ +#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 , , , , ")); + 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 , , , , ")); + 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 + ); + + mg_http_reply( + c, + 200, + "Content-Type: application/json\r\n", + responsedata + ); +} diff --git a/src/user.c b/src/user.c index 1a87d4e..f1ee3bc 100644 --- a/src/user.c +++ b/src/user.c @@ -4,86 +4,6 @@ #include #include -#define JWT_SECRET_KEY "secret" - -void get_all_users(struct mg_connection *c, struct mg_http_message *hm) { - request_with_token *data = check_body(hm); - if (data->error != NULL) { - 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 = 1}, - {.id = 2, - .username = "lisa", - .email = "mail@example.com", - .password = "asdf", - .group = "users", - .is_superuser = 0}}; - 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)); - } - } - strncat(msg, "]\n", strlen(msg)); - mg_http_reply(c, 200, "Content-type: application/json\r\n", msg); -} - -void get_token(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 and password")); - return; - } - cJSON *jsonbody = cJSON_Parse(hm->body.buf); - cJSON *username = cJSON_GetObjectItem(jsonbody, "username"); - cJSON *password = cJSON_GetObjectItem(jsonbody, "password"); - if (username == NULL || password == NULL) { - const char *error_ptr = cJSON_GetErrorPtr(); - if (error_ptr != NULL) { - mg_http_reply(c, 400, "", "{%m:%m}", MG_ESC("error"), MG_ESC(error_ptr)); - return; - } - mg_http_reply(c, 400, "", "{%m:%m}", MG_ESC("error"), - MG_ESC("must have username and password")); - return; - } - const char *header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}"; - const char *payload = "{\"sub\": \"1234567890\",\"username\": " - "\"tola\",\"is_superuser\": true,\"iat\": 1516239022}"; - char *token = jwt_createJWT(header, payload, JWT_SECRET_KEY); - mg_http_reply(c, 200, "", "{%m:%m}", MG_ESC("token"), MG_ESC(token)); -} - -void verify_token(struct mg_connection *c, struct mg_http_message *hm) { - const request_with_token *data = check_body(hm); - if (data->error != nullptr) { - mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"), MG_ESC(data->error)); - return; - } - const bool valid = jwt_verifyJWT(data->token, JWT_SECRET_KEY); - if (!valid) { - mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"), - MG_ESC("invalid token")); - return; - } - mg_http_reply(c, 200, "", "{%m:%m}", MG_ESC("valid"), MG_ESC("true")); -} - request_with_token *new_request_with_token(char *token, cJSON *body, char *error) { request_with_token *data = malloc(sizeof(request_with_token)); @@ -105,3 +25,16 @@ 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; +} diff --git a/src/user.h b/src/user.h index a1e2a3e..6b37af7 100644 --- a/src/user.h +++ b/src/user.h @@ -5,13 +5,24 @@ typedef struct User { int id; - char username[256]; - char email[256]; - char password[256]; - char group[256]; - int is_superuser; + char *username; + char *email; + char *password; + char *group; + bool is_superuser; } User; +User *new_user(const char *username, const char *password, const char *email, const char *group, bool is_superuser); + +typedef struct register_request { + char *username; + char *email; + char *password; + char *group; + bool is_superuser; + char *error; +} register_request; + typedef struct request_with_token { char *token; cJSON *body; @@ -29,5 +40,11 @@ request_with_token *new_request_with_token(char *token, cJSON *body, void free_request_with_token(request_with_token *data); void get_all_users(struct mg_connection *c, struct mg_http_message *hm); +void get_user(struct mg_connection *c, struct mg_http_message *hm); +void delete_user(struct mg_connection *c, struct mg_http_message *hm); +void add_user(struct mg_connection *c, struct mg_http_message *hm); +void change_user(struct mg_connection *c, struct mg_http_message *hm); +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); diff --git a/src/verify_token.c b/src/verify_token.c new file mode 100644 index 0000000..9993b12 --- /dev/null +++ b/src/verify_token.c @@ -0,0 +1,18 @@ +#include "user.h" +#include "jwt.h" +#include "utils.h" + +void verify_token(struct mg_connection *c, struct mg_http_message *hm) { + const request_with_token *data = check_body(hm); + if (data->error != nullptr) { + mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"), MG_ESC(data->error)); + return; + } + const bool valid = jwt_verifyJWT(data->token, JWT_DEFAULT_SECRET); + if (!valid) { + mg_http_reply(c, 403, "", "{%m:%m}", MG_ESC("error"), + MG_ESC("invalid token")); + return; + } + mg_http_reply(c, 200, "", "{%m:%m}", MG_ESC("valid"), MG_ESC("true")); +}