From 20faf38a0d5096263fe086e0c1bc6b29a67bca2f Mon Sep 17 00:00:00 2001 From: Torsten Martinsen Date: Thu, 13 Jun 2024 22:07:08 +0200 Subject: [PATCH] Use cert bundle. Add global HTTP mutex to avoid memory peaks. --- frontend/esp32/main/CMakeLists.txt | 1 - frontend/esp32/main/cardcache.cpp | 4 +- frontend/esp32/main/foreninglet.cpp | 4 +- frontend/esp32/main/gateway.cpp | 9 +- .../esp32/main/howsmyssl_com_root_cert.pem | 31 ------- frontend/esp32/main/http.cpp | 2 + frontend/esp32/main/http.h | 8 +- frontend/esp32/main/logger.cpp | 6 +- frontend/esp32/main/otafwu.cpp | 2 +- frontend/esp32/main/slack.cpp | 90 ++++++++++++------- frontend/esp32/main/slack.h | 14 ++- frontend/esp32/version.txt | 2 +- 12 files changed, 89 insertions(+), 84 deletions(-) delete mode 100644 frontend/esp32/main/howsmyssl_com_root_cert.pem diff --git a/frontend/esp32/main/CMakeLists.txt b/frontend/esp32/main/CMakeLists.txt index 045b6a96..f24ef3d6 100644 --- a/frontend/esp32/main/CMakeLists.txt +++ b/frontend/esp32/main/CMakeLists.txt @@ -20,7 +20,6 @@ idf_component_register(SRCS sntp.cpp util.cpp INCLUDE_DIRS "." "../../../include" - EMBED_TXTFILES howsmyssl_com_root_cert.pem ) #add_definitions(-DSIMULATE) diff --git a/frontend/esp32/main/cardcache.cpp b/frontend/esp32/main/cardcache.cpp index fe8d4bd8..5ede0985 100644 --- a/frontend/esp32/main/cardcache.cpp +++ b/frontend/esp32/main/cardcache.cpp @@ -64,10 +64,10 @@ Card_cache::Result Card_cache::has_access(Card_cache::Card_id id) esp_http_client_config_t config { .host = "panopticon.hal9k.dk", .path = "/api/v1/permissions", - .cert_pem = howsmyssl_com_root_cert_pem_start, .event_handler = http_event_handler, .transport_type = HTTP_TRANSPORT_OVER_SSL, .user_data = &http_data, + .crt_bundle_attach = esp_crt_bundle_attach, }; esp_http_client_handle_t client = esp_http_client_init(&config); Http_client_wrapper w(client); @@ -139,10 +139,10 @@ void Card_cache::thread_body() esp_http_client_config_t config { .host = "panopticon.hal9k.dk", .path = "/api/v2/permissions/", - .cert_pem = howsmyssl_com_root_cert_pem_start, .event_handler = http_event_handler, .transport_type = HTTP_TRANSPORT_OVER_SSL, .user_data = &http_data, + .crt_bundle_attach = esp_crt_bundle_attach, }; esp_http_client_handle_t client = esp_http_client_init(&config); Http_client_wrapper w(client); diff --git a/frontend/esp32/main/foreninglet.cpp b/frontend/esp32/main/foreninglet.cpp index d498a5fa..3722b721 100644 --- a/frontend/esp32/main/foreninglet.cpp +++ b/frontend/esp32/main/foreninglet.cpp @@ -60,6 +60,8 @@ void ForeningLet::thread_body() continue; } + std::lock_guard g(http_mutex); + const auto path = format("/api/member/id/%d/?version=1", item.user_id); esp_http_client_config_t config { .host = "foreninglet.dk", @@ -67,9 +69,9 @@ void ForeningLet::thread_body() .password = forening_let_password.c_str(), .auth_type = HTTP_AUTH_TYPE_BASIC, .path = path.c_str(), - .cert_pem = howsmyssl_com_root_cert_pem_start, .event_handler = http_event_handler, .transport_type = HTTP_TRANSPORT_OVER_SSL, + .crt_bundle_attach = esp_crt_bundle_attach, }; esp_http_client_handle_t client = esp_http_client_init(&config); Http_client_wrapper w(client); diff --git a/frontend/esp32/main/gateway.cpp b/frontend/esp32/main/gateway.cpp index f622fefb..a20324d2 100644 --- a/frontend/esp32/main/gateway.cpp +++ b/frontend/esp32/main/gateway.cpp @@ -96,12 +96,14 @@ bool Gateway::post_status() strcpy(buffer.get(), current_status.c_str()); } + std::lock_guard g(http_mutex); + esp_http_client_config_t config { .host = "acsgateway.hal9k.dk", .path = "/acsstatus", - .cert_pem = howsmyssl_com_root_cert_pem_start, .event_handler = http_event_handler, .transport_type = HTTP_TRANSPORT_OVER_SSL, + .crt_bundle_attach = esp_crt_bundle_attach, }; esp_http_client_handle_t client = esp_http_client_init(&config); Http_client_wrapper w(client); @@ -132,11 +134,12 @@ void Gateway::check_action() esp_http_client_config_t config { .host = "acsgateway.hal9k.dk", .path = "/acsquery", - .cert_pem = howsmyssl_com_root_cert_pem_start, .event_handler = http_event_handler, .transport_type = HTTP_TRANSPORT_OVER_SSL, - .user_data = &http_data + .user_data = &http_data, + .crt_bundle_attach = esp_crt_bundle_attach, }; + std::lock_guard g(http_mutex); esp_http_client_handle_t client = esp_http_client_init(&config); if (!client) { diff --git a/frontend/esp32/main/howsmyssl_com_root_cert.pem b/frontend/esp32/main/howsmyssl_com_root_cert.pem deleted file mode 100644 index 123d192c..00000000 --- a/frontend/esp32/main/howsmyssl_com_root_cert.pem +++ /dev/null @@ -1,31 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/ -MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT -DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC -ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL -wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D -LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK -4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5 -bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y -sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ -Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4 -FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc -SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql -PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND -TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw -SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1 -c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx -+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB -ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu -b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E -U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu -MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC -5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW -9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG -WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O -he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC -Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5 ------END CERTIFICATE----- diff --git a/frontend/esp32/main/http.cpp b/frontend/esp32/main/http.cpp index ec3dcea8..a99c1ea4 100644 --- a/frontend/esp32/main/http.cpp +++ b/frontend/esp32/main/http.cpp @@ -72,3 +72,5 @@ Http_client_wrapper::~Http_client_wrapper() esp_http_client_close(handle); esp_http_client_cleanup(handle); } + +std::mutex http_mutex; diff --git a/frontend/esp32/main/http.h b/frontend/esp32/main/http.h index 3a5c3535..4ebb2f8a 100644 --- a/frontend/esp32/main/http.h +++ b/frontend/esp32/main/http.h @@ -1,5 +1,8 @@ #pragma once +#include + +#include "esp_crt_bundle.h" #include "esp_http_client.h" #include "esp_system.h" @@ -17,9 +20,6 @@ struct Http_data int output_len = 0; }; -extern const char howsmyssl_com_root_cert_pem_start[] asm("_binary_howsmyssl_com_root_cert_pem_start"); -extern const char howsmyssl_com_root_cert_pem_end[] asm("_binary_howsmyssl_com_root_cert_pem_end"); - /// RAII class to ensure calling esp_http_client_cleanup() on a handle. class Http_client_wrapper { @@ -31,3 +31,5 @@ class Http_client_wrapper private: esp_http_client_handle_t handle; }; + +extern std::mutex http_mutex; diff --git a/frontend/esp32/main/logger.cpp b/frontend/esp32/main/logger.cpp index 416600ba..29f3adde 100644 --- a/frontend/esp32/main/logger.cpp +++ b/frontend/esp32/main/logger.cpp @@ -114,9 +114,9 @@ void Logger::log_sync_start() esp_http_client_config_t config { .host = "acsgateway.hal9k.dk", .path = "/acslog", - .cert_pem = howsmyssl_com_root_cert_pem_start, .event_handler = http_event_handler, .transport_type = HTTP_TRANSPORT_OVER_SSL, + .crt_bundle_attach = esp_crt_bundle_attach, }; debug_client = esp_http_client_init(&config); esp_http_client_set_method(debug_client, HTTP_METHOD_POST); @@ -213,9 +213,9 @@ void Logger::thread_body() esp_http_client_config_t config { .host = "panopticon.hal9k.dk", .path = "/api/v1/logs", - .cert_pem = howsmyssl_com_root_cert_pem_start, .event_handler = http_event_handler, .transport_type = HTTP_TRANSPORT_OVER_SSL, + .crt_bundle_attach = esp_crt_bundle_attach, }; esp_http_client_handle_t client = esp_http_client_init(&config); Http_client_wrapper w(client); @@ -265,9 +265,9 @@ void Logger::thread_body() esp_http_client_config_t config { .host = "panopticon.hal9k.dk", .path = "/api/v1/unknown_cards", - .cert_pem = howsmyssl_com_root_cert_pem_start, .event_handler = http_event_handler, .transport_type = HTTP_TRANSPORT_OVER_SSL, + .crt_bundle_attach = esp_crt_bundle_attach, }; esp_http_client_handle_t client = esp_http_client_init(&config); Http_client_wrapper w(client); diff --git a/frontend/esp32/main/otafwu.cpp b/frontend/esp32/main/otafwu.cpp index 58f65aa3..2eed2fc9 100644 --- a/frontend/esp32/main/otafwu.cpp +++ b/frontend/esp32/main/otafwu.cpp @@ -91,10 +91,10 @@ bool check_ota_update(class Display& display) esp_http_client_config_t config = { .host = "acsgateway.hal9k.dk", .path = path, - .cert_pem = howsmyssl_com_root_cert_pem_start, .timeout_ms = 3000, .event_handler = http_event_handler, .transport_type = HTTP_TRANSPORT_OVER_SSL, + .crt_bundle_attach = esp_crt_bundle_attach, .keep_alive_enable = true, }; diff --git a/frontend/esp32/main/slack.cpp b/frontend/esp32/main/slack.cpp index 1dcfef08..d3a74700 100644 --- a/frontend/esp32/main/slack.cpp +++ b/frontend/esp32/main/slack.cpp @@ -83,10 +83,13 @@ void Slack_writer::thread_body() { vTaskDelay(100 / portTICK_PERIOD_MS); - if (q.empty()) - continue; - item = q.back(); - q.pop_back(); + { + std::lock_guard g(mutex); + if (q.empty()) + continue; + item = q.back(); + q.pop_back(); + } if (api_token.empty()) { @@ -94,50 +97,69 @@ void Slack_writer::thread_body() continue; } + std::lock_guard g(http_mutex); + esp_http_client_config_t config { .host = "slack.com", .path = "/api/chat.postMessage", - .cert_pem = howsmyssl_com_root_cert_pem_start, .event_handler = http_event_handler, .transport_type = HTTP_TRANSPORT_OVER_SSL, + .crt_bundle_attach = esp_crt_bundle_attach, }; esp_http_client_handle_t client = esp_http_client_init(&config); Http_client_wrapper w(client); - esp_http_client_set_method(client, HTTP_METHOD_POST); - auto payload = cJSON_CreateObject(); - cJSON_wrapper jw(payload); - auto jchannel = cJSON_CreateString(item.channel.c_str()); - cJSON_AddItemToObject(payload, "channel", jchannel); - auto emoji = cJSON_CreateString(":panopticon:"); - cJSON_AddItemToObject(payload, "icon_emoji", emoji); - auto full = cJSON_CreateString("full"); - cJSON_AddItemToObject(payload, "parse", full); - auto text = cJSON_CreateString(item.message.c_str()); - cJSON_AddItemToObject(payload, "text", text); - - char* data = cJSON_Print(payload); - if (!data) + + while (1) { - ESP_LOGE(TAG, "Slack: cJSON_Print() returned nullptr"); - return; + do_post(client, item); + + { + std::lock_guard g(mutex); + if (q.empty()) + break; + item = q.back(); + q.pop_back(); + } } - cJSON_Print_wrapper pw(data); - esp_http_client_set_post_field(client, data, strlen(data)); - - const char* content_type = "application/json"; - esp_http_client_set_header(client, "Content-Type", content_type); - const auto auth = std::string("Bearer ") + api_token; - esp_http_client_set_header(client, "Authorization", auth.c_str()); - const esp_err_t err = esp_http_client_perform(client); - - if (err == ESP_OK) - ESP_LOGI(TAG, "Slack: HTTP %d", esp_http_client_get_status_code(client)); - else - ESP_LOGE(TAG, "Slack: error %s", esp_err_to_name(err)); } } +void Slack_writer::do_post(esp_http_client_handle_t client, const Item& item) +{ + ESP_LOGI(TAG, "Slack: do_post(%s)", item.message.c_str()); + + auto payload = cJSON_CreateObject(); + cJSON_wrapper jw(payload); + auto jchannel = cJSON_CreateString(item.channel.c_str()); + cJSON_AddItemToObject(payload, "channel", jchannel); + auto emoji = cJSON_CreateString(":panopticon:"); + cJSON_AddItemToObject(payload, "icon_emoji", emoji); + auto full = cJSON_CreateString("full"); + cJSON_AddItemToObject(payload, "parse", full); + auto text = cJSON_CreateString(item.message.c_str()); + cJSON_AddItemToObject(payload, "text", text); + + char* data = cJSON_Print(payload); + if (!data) + { + ESP_LOGE(TAG, "Slack: cJSON_Print() returned nullptr"); + return; + } + cJSON_Print_wrapper pw(data); + esp_http_client_set_post_field(client, data, strlen(data)); + + esp_http_client_set_header(client, "Content-Type", "application/json"); + const auto auth = std::string("Bearer ") + api_token; + esp_http_client_set_header(client, "Authorization", auth.c_str()); + const esp_err_t err = esp_http_client_perform(client); + + if (err == ESP_OK) + ESP_LOGI(TAG, "Slack: HTTP %d", esp_http_client_get_status_code(client)); + else + ESP_LOGE(TAG, "Slack: error %s", esp_err_to_name(err)); +} + void slack_task(void*) { Slack_writer::instance().thread_body(); diff --git a/frontend/esp32/main/slack.h b/frontend/esp32/main/slack.h index 167c471f..5dbf347d 100644 --- a/frontend/esp32/main/slack.h +++ b/frontend/esp32/main/slack.h @@ -6,6 +6,8 @@ #include "util.h" +#include "esp_http_client.h" + extern "C" void slack_task(void*); /// Slack_writer singleton @@ -42,6 +44,11 @@ class Slack_writer Channels channels = Channels::defaults()); private: + struct Item { + std::string channel; + std::string message; + }; + Slack_writer() = default; ~Slack_writer() = default; @@ -51,10 +58,9 @@ class Slack_writer void thread_body(); - struct Item { - std::string channel; - std::string message; - }; + void do_post(esp_http_client_handle_t client, + const Item& item); + std::deque q; std::mutex mutex; bool is_test_mode = false; diff --git a/frontend/esp32/version.txt b/frontend/esp32/version.txt index 4fc01ac9..3c59b404 100644 --- a/frontend/esp32/version.txt +++ b/frontend/esp32/version.txt @@ -1 +1 @@ -1.3.19 +1.3.20