From b3198429e2d8fac12eaa0309ce0eab6d4eab2e30 Mon Sep 17 00:00:00 2001 From: Francesco Date: Wed, 27 May 2026 00:43:26 +0200 Subject: [PATCH] refactor: code hardening --- src/json.c | 34 ++++++++++++++++++-- src/parse.c | 91 ++++++++++++++++++++++++++++++++++++----------------- src/tgbot.c | 29 +++++++++++++++-- src/types.c | 30 +++++++++++++----- 4 files changed, 141 insertions(+), 43 deletions(-) diff --git a/src/json.c b/src/json.c index f269dcc..293f31a 100644 --- a/src/json.c +++ b/src/json.c @@ -6,6 +6,10 @@ #include "tg_types.h" json_object *json_builder(tgbot_option_s *options, size_t optionslen) { + if (!options && optionslen > 0) { + return NULL; + } + json_object *rjson = json_object_new_object(); if (!rjson) { return NULL; @@ -14,6 +18,9 @@ json_object *json_builder(tgbot_option_s *options, size_t optionslen) { for (size_t i = 0; i < optionslen; ++i) { switch (options[i].type) { case tgbot_opt_int: { + if (!options[i].value) { + break; + } json_object_object_add(rjson, options[i].key, json_object_new_int(*((int32_t *)options[i].value))); break; } @@ -25,12 +32,19 @@ json_object *json_builder(tgbot_option_s *options, size_t optionslen) { break; } case tgbot_opt_int64: { + if (!options[i].value) { + break; + } json_object_object_add(rjson, options[i].key, json_object_new_int64(*((int64_t *)options[i].value))); break; } case tgbot_opt_inlinekeyboard: { if (options[i].value != NULL) { json_object *reply_markup = json_ikb_new((tgbot_inlinekeyboard_s *)options[i].value); + if (!reply_markup) { + json_object_put(rjson); + return NULL; + } json_object_object_add(rjson, options[i].key, reply_markup); } break; @@ -45,6 +59,10 @@ json_object *json_builder(tgbot_option_s *options, size_t optionslen) { } json_object *json_ikb_new(tgbot_inlinekeyboard_s *keyboard) { + if (!keyboard) { + return NULL; + } + json_object *reply_markup = json_object_new_object(); if (!reply_markup) { return NULL; @@ -58,9 +76,15 @@ json_object *json_ikb_new(tgbot_inlinekeyboard_s *keyboard) { for (size_t i = 0; i < keyboard->rows; ++i) { json_object *row = json_object_new_array(); + if (!row) { + json_object_put(inline_keyboard_array); + json_object_put(reply_markup); + return NULL; + } + for (size_t j = 0; j < keyboard->columns; ++j) { tgbot_inlinekeyboardbutton_s *kbbutton = tgbot_inlinekb_button_at(keyboard, i, j); - if (strcmp(kbbutton->text, "") == 0) { + if (!kbbutton || kbbutton->text[0] == '\0') { continue; } @@ -70,8 +94,12 @@ json_object *json_ikb_new(tgbot_inlinekeyboard_s *keyboard) { } json_object_object_add(button, "text", json_object_new_string(kbbutton->text)); - json_object_object_add(button, "url", json_object_new_string(kbbutton->url)); - json_object_object_add(button, "callback_data", json_object_new_string(kbbutton->callback_data)); + if (kbbutton->url[0] != '\0') { + json_object_object_add(button, "url", json_object_new_string(kbbutton->url)); + } + if (kbbutton->callback_data[0] != '\0') { + json_object_object_add(button, "callback_data", json_object_new_string(kbbutton->callback_data)); + } json_object_array_add(row, button); } diff --git a/src/parse.c b/src/parse.c index 6b77c28..b884db5 100644 --- a/src/parse.c +++ b/src/parse.c @@ -2,41 +2,56 @@ #include "internal/common.h" int tgbot_parse_message(tgbot_s *bot, tgbot_update_s *update, json_object *result) { + if (!bot || !update || !result) { + return -1; + } + json_object *update_id = json_object_object_get(result, "update_id"); + if (!update_id) { + return -1; + } + bot->offset = json_object_get_int(update_id) + 1; update->update_id = json_object_get_int(update_id); json_object *message = json_object_object_get(result, "message"); + if (!message) { + return -1; + } + json_object *message_id = json_object_object_get(message, "message_id"); if (message_id) { - update->message_id = json_object_get_int(message_id); + update->message_id = json_object_get_int64(message_id); } json_object *chat = json_object_object_get(message, "chat"); - json_object *chat_id = json_object_object_get(chat, "id"); - if (chat_id) { - update->chat_id = json_object_get_int64(chat_id); - } + if (chat) { + json_object *chat_id = json_object_object_get(chat, "id"); + if (chat_id) { + update->chat_id = json_object_get_int64(chat_id); + } - json_object *chat_first_name = json_object_object_get(chat, "first_name"); - if (chat_first_name) { - snprintf(update->chat_first_name, sizeof(update->chat_first_name), "%s", - json_object_get_string(chat_first_name)); - } + json_object *chat_first_name = json_object_object_get(chat, "first_name"); + if (chat_first_name) { + snprintf(update->chat_first_name, sizeof(update->chat_first_name), "%s", + json_object_get_string(chat_first_name)); + } - json_object *chat_last_name = json_object_object_get(chat, "last_name"); - if (chat_last_name) { - snprintf(update->chat_last_name, sizeof(update->chat_last_name), "%s", json_object_get_string(chat_last_name)); - } + json_object *chat_last_name = json_object_object_get(chat, "last_name"); + if (chat_last_name) { + snprintf(update->chat_last_name, sizeof(update->chat_last_name), "%s", + json_object_get_string(chat_last_name)); + } - json_object *chat_username = json_object_object_get(chat, "username"); - if (chat_username != NULL) { - snprintf(update->chat_username, sizeof(update->chat_username), "%s", json_object_get_string(chat_username)); - } + json_object *chat_username = json_object_object_get(chat, "username"); + if (chat_username) { + snprintf(update->chat_username, sizeof(update->chat_username), "%s", json_object_get_string(chat_username)); + } - json_object *chat_type = json_object_object_get(chat, "type"); - if (chat_type) { - snprintf(update->chat_type, sizeof(update->chat_type), "%s", json_object_get_string(chat_type)); + json_object *chat_type = json_object_object_get(chat, "type"); + if (chat_type) { + snprintf(update->chat_type, sizeof(update->chat_type), "%s", json_object_get_string(chat_type)); + } } json_object *date = json_object_object_get(message, "date"); @@ -53,26 +68,44 @@ int tgbot_parse_message(tgbot_s *bot, tgbot_update_s *update, json_object *resul } int tgbot_parse_cbquery(tgbot_s *bot, tgbot_cbquery_s *query, json_object *result, Callback cbq_handler) { + if (!bot || !query || !result || !cbq_handler) { + return -1; + } + json_object *update_id = json_object_object_get(result, "update_id"); + if (!update_id) { + return -1; + } + bot->offset = json_object_get_int(update_id) + 1; query->update_id = json_object_get_int(update_id); json_object *callback_query = json_object_object_get(result, "callback_query"); + if (!callback_query) { + return -1; + } + json_object *message = json_object_object_get(callback_query, "message"); + if (!message) { + return -1; + } + json_object *message_id = json_object_object_get(message, "message_id"); if (message_id) { - query->message_id = json_object_get_int(message_id); + query->message_id = json_object_get_int64(message_id); } json_object *chat = json_object_object_get(message, "chat"); - json_object *chat_id = json_object_object_get(chat, "id"); - if (chat_id) { - query->chat_id = json_object_get_int64(chat_id); - } + if (chat) { + json_object *chat_id = json_object_object_get(chat, "id"); + if (chat_id) { + query->chat_id = json_object_get_int64(chat_id); + } - json_object *chat_username = json_object_object_get(chat, "username"); - if (chat_username) { - snprintf(query->chat_username, sizeof(query->chat_username), "%s", json_object_get_string(chat_username)); + json_object *chat_username = json_object_object_get(chat, "username"); + if (chat_username) { + snprintf(query->chat_username, sizeof(query->chat_username), "%s", json_object_get_string(chat_username)); + } } json_object *date = json_object_object_get(message, "date"); diff --git a/src/tgbot.c b/src/tgbot.c index 198ff78..8e9c5a7 100644 --- a/src/tgbot.c +++ b/src/tgbot.c @@ -8,21 +8,44 @@ #include "tgbot.h" tgbot_s *tgbot_new(const char *token) { + if (!token || token[0] == '\0') { + return NULL; + } + tgbot_s *bot = malloc(sizeof(tgbot_s)); if (!bot) { return NULL; } - curl_global_init(CURL_GLOBAL_DEFAULT); + if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) { + free(bot); + return NULL; + } + + int chars = snprintf(bot->api, sizeof(bot->api), "https://api.telegram.org/bot%s/", token); + if (chars < 0 || (size_t)chars >= sizeof(bot->api)) { + curl_global_cleanup(); + free(bot); + return NULL; + } + + chars = snprintf(bot->token, sizeof(bot->token), "%s", token); + if (chars < 0 || (size_t)chars >= sizeof(bot->token)) { + curl_global_cleanup(); + free(bot); + return NULL; + } - snprintf(bot->api, sizeof(bot->api), "https://api.telegram.org/bot%s/", token); - snprintf(bot->token, sizeof(bot->token), "%s", token); bot->offset = 0; return bot; } void tgbot_free(tgbot_s *bot) { + if (!bot) { + return; + } + curl_global_cleanup(); free(bot); } diff --git a/src/types.c b/src/types.c index 34125f1..a159d8e 100644 --- a/src/types.c +++ b/src/types.c @@ -1,35 +1,46 @@ +#include +#include #include #include #include "types.h" tgbot_inlinekeyboard_s *tgbot_inlinekb_new(size_t rows, size_t columns) { - tgbot_inlinekeyboard_s *keyboard = (tgbot_inlinekeyboard_s *)malloc(sizeof(tgbot_inlinekeyboard_s)); + if (rows == 0 || columns == 0 || rows > SIZE_MAX / columns) { + return NULL; + } + + tgbot_inlinekeyboard_s *keyboard = malloc(sizeof(tgbot_inlinekeyboard_s)); if (!keyboard) { return NULL; } keyboard->rows = rows; keyboard->columns = columns; - keyboard->buttons = (tgbot_inlinekeyboardbutton_s *)malloc(rows * columns * sizeof(tgbot_inlinekeyboardbutton_s)); + + size_t count = rows * columns; + keyboard->buttons = malloc(count * sizeof(tgbot_inlinekeyboardbutton_s)); if (!keyboard->buttons) { free(keyboard); - return NULL; } - memset(keyboard->buttons, 0, rows * columns * sizeof(tgbot_inlinekeyboardbutton_s)); + memset(keyboard->buttons, 0, count * sizeof(tgbot_inlinekeyboardbutton_s)); return keyboard; } void tgbot_inlinekb_free(tgbot_inlinekeyboard_s *keyboard) { + if (!keyboard) { + return; + } + free(keyboard->buttons); free(keyboard); } tgbot_inlinekeyboardbutton_s *tgbot_inlinekb_button_at(tgbot_inlinekeyboard_s *keyboard, size_t row, size_t column) { - if (row >= keyboard->rows || column >= keyboard->columns) { + if (!keyboard || row >= keyboard->rows || column >= keyboard->columns) { return NULL; } @@ -39,10 +50,13 @@ tgbot_inlinekeyboardbutton_s *tgbot_inlinekb_button_at(tgbot_inlinekeyboard_s *k int tgbot_inlinekb_button(tgbot_inlinekeyboard_s *keyboard, size_t row, size_t column, const char *text, const char *url, const char *callback_data) { tgbot_inlinekeyboardbutton_s *button = tgbot_inlinekb_button_at(keyboard, row, column); + if (!button) { + return -1; + } - strncpy(button->text, text, sizeof(button->text) - 1); - strncpy(button->url, url, sizeof(button->url) - 1); - strncpy(button->callback_data, callback_data, sizeof(button->callback_data) - 1); + snprintf(button->text, sizeof(button->text), "%s", text ? text : ""); + snprintf(button->url, sizeof(button->url), "%s", url ? url : ""); + snprintf(button->callback_data, sizeof(button->callback_data), "%s", callback_data ? callback_data : ""); return 0; }