From: Patrick Date: Fri, 13 Oct 2023 13:59:29 +0000 (+0200) Subject: working examples for esp X-Git-Url: https://gitweb.ps.run/matrix_esp_thesis/commitdiff_plain/8ceca98f04b88798794748572fce184b92144d2d?ds=inline working examples for esp --- diff --git a/esp32/esp_project/components/matrix/CMakeLists.txt b/esp32/esp_project/components/matrix/CMakeLists.txt new file mode 100644 index 0000000..485b3c6 --- /dev/null +++ b/esp32/esp_project/components/matrix/CMakeLists.txt @@ -0,0 +1,17 @@ +idf_component_register(SRCS + "../../../../src/matrix.c" + "../../../../src/matrix_http_esp32.c" + "../../../../ext/mjson/src/mjson.c" + INCLUDE_DIRS + "../../../../ext/olm/include" + "../../../../ext/olm/lib" + "../../../../ext/mjson/src" + "../../../../src" + REQUIRES + esp-tls + esp_http_client + esp_netif + nvs_flash) + +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") +SET(CMAKE_CXX_COMPILER "C:/Espressif/tools/xtensa-esp32-elf/esp-12.2.0_20230208/xtensa-esp32-elf/bin/xtensa-esp32-elf-gcc.exe") diff --git a/esp32/esp_project/main/SendEncrypted.c b/esp32/esp_project/main/SendEncrypted.c new file mode 100644 index 0000000..900856d --- /dev/null +++ b/esp32/esp_project/main/SendEncrypted.c @@ -0,0 +1,80 @@ +#define OLMLIB_VERSION_MAJOR 3 +#define OLMLIB_VERSION_MINOR 2 +#define OLMLIB_VERSION_PATCH 15 + +#define OLM_STATIC_DEFINE + +#include +#include + +#define SERVER "https://matrix.org" +#define USER_ID "@pscho:matrix.org" +#define ROOM_ID "!XKFUjAsGrSSrpDFIxB:matrix.org" + +int +main(void) +{ + // static MatrixClient _client; + // MatrixClient * client = &_client; + MatrixClient * client = (MatrixClient*)malloc(sizeof(MatrixClient)); + MatrixClientInit(client); + + MatrixHttpInit(&client->hc, SERVER); + MatrixClientSetUserId(client, USER_ID); + + static char key[1024]; + MatrixOlmAccountGetDeviceKey(&client->olmAccount, key, 1024); + printf("key: %s\n", key); + + //MatrixClientSetUserId(client, USER_ID); + + MatrixClientLoginPassword(client, + "pscho", + "Wc23EbmB9G3faMq", + "Test1"); + + // MatrixClientSendEvent(client, + // ROOM_ID, + // "m.room.message", + // "{\"body\":\"Hello\",\"msgtype\":\"m.text\"}"); + + MatrixClientUploadDeviceKey(client); + MatrixClientGenerateOnetimeKeys(client, 10); + MatrixClientUploadOnetimeKeys(client); + + // create megolmsession + MatrixMegolmOutSession * megolmOutSession; + MatrixClientNewMegolmOutSession(client, + ROOM_ID, + &megolmOutSession); + printf("megolm session id: %.10s... key: %.10s...\n", megolmOutSession->id, megolmOutSession->key); + + // heap_caps_get_free_size(); + // xPortGetFreeHeapSize(); + + MatrixClientShareMegolmOutSession(client, + USER_ID, + "ULZZOKJBYN", + megolmOutSession); + + MatrixClientSendEventEncrypted(client, + ROOM_ID, + "m.room.message", + "{\"body\":\"Hello\",\"msgtype\":\"m.text\"}"); + + MatrixClientDeleteDevice(client); + + MatrixHttpDeinit(&client->hc); + + return 0; +} + +#include "wifi.h" + +void +app_main(void) +{ + wifi_init("Hundehuette", "Affensicherespw55"); + + main(); +} diff --git a/esp32/esp_project/main/Verify.c b/esp32/esp_project/main/Verify.c new file mode 100644 index 0000000..124ddd2 --- /dev/null +++ b/esp32/esp_project/main/Verify.c @@ -0,0 +1,541 @@ +#include +#include +#include + +#include + +#define SERVER "https://matrix.org" +#define USER_ID "@pscho:matrix.org" + +#define DEVICE_ID "ULZZOKJBYN" +#define SENDER_KEY "cjP41XzRlY+pd8DoiBuKQJj9o15mrx6gkrpqTkAPZ2c" +#define ROOM_ID "!XKFUjAsGrSSrpDFIxB:matrix.org" +#define EVENT_ID "$vOS09eUaI0CduqAcaIU5ZVk6ljLQfLspz7UThP8vaUM" +#define SESSION_ID "90UbGLue3ADVhvW7hFjoA2c6yg0JJKs/lPdMDZXnZAk" + +// main stack size: 3584 + +bool verified = false; +char transactionId[64]; +OlmSAS * olmSas = NULL; + +#define STATIC static + +STATIC char encrypted[2048]; +STATIC char decrypted[2048]; + +void +HandleEvent( + MatrixClient * client, + const char * event, int eventLen +) { + STATIC char eventType[128]; + memset(eventType, 0, sizeof(eventType)); + mjson_get_string(event, eventLen, "$.type", eventType, 128); + + if (strcmp(eventType, "m.key.verification.request") == 0) { + mjson_get_string(event, eventLen, "$.content.transaction_id", transactionId, 256); + + char verificationReadyBuffer[2048]; + snprintf(verificationReadyBuffer, 2048, + "{" + "\"from_device\":\"%s\"," + "\"methods\":[\"m.sas.v1\"]," + "\"transaction_id\":\"%s\"" + "}", + client->deviceId, + transactionId); + + MatrixClientSendToDevice(client, + USER_ID, + DEVICE_ID, + verificationReadyBuffer, + "m.key.verification.ready"); + } + else if (strcmp(eventType, "m.key.verification.start") == 0) { + olmSas = olm_sas(malloc(olm_sas_size())); + void * sasRandomBytes = malloc(olm_create_sas_random_length(olmSas)); + olm_create_sas(olmSas, + sasRandomBytes, + olm_create_sas_random_length(olmSas)); + + OlmUtility * olmUtil = olm_utility(malloc(olm_utility_size())); + + STATIC char publicKey[64]; + STATIC char keyStartJsonCanonical[128]; + STATIC char concat[128+64]; + STATIC char commitment[256]; + olm_sas_get_pubkey(olmSas, + publicKey, + 64); + printf("public key: %.*s\n", olm_sas_pubkey_length(olmSas), publicKey); + + const char * keyStartJson; + int keyStartJsonLen; + mjson_find(event, eventLen, "$.content", &keyStartJson, &keyStartJsonLen); + JsonCanonicalize(keyStartJson, keyStartJsonLen, keyStartJsonCanonical, 128); + + printf("json:\n%.*s\ncanonical json:\n%s\n", keyStartJsonLen, keyStartJson, keyStartJsonCanonical); + + int concatLen = + snprintf(concat, 128+64, "%.*s%s", olm_sas_pubkey_length(olmSas), publicKey, keyStartJsonCanonical); + + int commitmentLen = + olm_sha256(olmUtil, concat, concatLen, commitment, 256); + + STATIC char verificationAcceptBuffer[512]; + snprintf(verificationAcceptBuffer, 512, + "{" + "\"commitment\":\"%.*s\"," + "\"hash\":\"sha256\"," + "\"key_agreement_protocol\":\"curve25519\"," + "\"message_authentication_code\":\"hkdf-hmac-sha256.v2\"," + "\"method\":\"m.sas.v1\"," + "\"short_authentication_string\":[\"decimal\"]," + "\"transaction_id\":\"%s\"" + "}", + commitmentLen, commitment, + transactionId); + + MatrixClientSendToDevice(client, + USER_ID, + DEVICE_ID, + verificationAcceptBuffer, + "m.key.verification.accept"); + } + else if (strcmp(eventType, "m.key.verification.key") == 0) { + STATIC char publicKey[128]; + olm_sas_get_pubkey(olmSas, + publicKey, + 128); + + STATIC char theirPublicKey[128]; + int theirPublicKeyLen = + mjson_get_string(event, eventLen, "$.content.key", theirPublicKey, 128); + + printf("event: %.*s\n", eventLen, event); + printf("theirPublicKey: %.*s\n", theirPublicKeyLen, theirPublicKey); + printf("publicKey: %.*s\n", olm_sas_pubkey_length(olmSas), publicKey); + + olm_sas_set_their_key(olmSas, theirPublicKey, theirPublicKeyLen); + + STATIC char verificationKeyBuffer[256]; + snprintf(verificationKeyBuffer, 256, + "{" + "\"key\":\"%.*s\"," + "\"transaction_id\":\"%s\"" + "}", + olm_sas_pubkey_length(olmSas), publicKey, + transactionId); + + MatrixClientSendToDevice(client, + USER_ID, + DEVICE_ID, + verificationKeyBuffer, + "m.key.verification.key"); + + // sas + STATIC char hkdfInfo[1024]; + int hkdfInfoLen = + snprintf(hkdfInfo, 1024, + "MATRIX_KEY_VERIFICATION_SAS%s%s%s%s%s", + USER_ID, + DEVICE_ID, + USER_ID, + client->deviceId, + transactionId); + + unsigned char sasBytes[5]; + olm_sas_generate_bytes(olmSas, + hkdfInfo, hkdfInfoLen, + sasBytes, 5); + int b0 = sasBytes[0]; + int b1 = sasBytes[1]; + int b2 = sasBytes[2]; + int b3 = sasBytes[3]; + int b4 = sasBytes[4]; + + printf("%d %d %d %d %d\n", b0, b1, b2, b3, b4); + + // https://spec.matrix.org/v1.7/client-server-api/#sas-method-decimal + printf("%d | %d | %d\n", + (b0 << 5 | b1 >> 3) + 1000, + ((b1 & 0x7) << 10 | b2 << 2 | b3 >> 6) + 1000, + ((b3 & 0x3F) << 7 | b4 >> 1) + 1000); + printf("%d | %d | %d\n", + ((b0 << 5) | (b1 >> 3)) + 1000, + (((b1 & 0x7) << 10) | (b2 << 2) | (b3 >> 6)) + 1000, + (((b3 & 0x3F) << 7) | (b4 >> 1)) + 1000); + } + else if (strcmp(eventType, "m.key.verification.mac") == 0) { + // mac + const char * masterKey = "vt8tJ5/SxqkvXS+XoGxr+4rJNe8fJfZT3/e/FTwlFsI"; + + STATIC char keyList[256]; + STATIC char keyListMac[256]; + STATIC char key1Id[128]; + STATIC char key1[128]; + STATIC char key1Mac[128]; + STATIC char key2Id[128]; + STATIC char key2[128]; + STATIC char key2Mac[128]; + + if (strcmp(masterKey, client->deviceId) < 0) { + snprintf(key1Id, 1024, "ed25519:%s", masterKey); + strcpy(key1, masterKey); + snprintf(key2Id, 1024, "ed25519:%s", client->deviceId); + MatrixOlmAccountGetSigningKey(&client->olmAccount, key2, 1024); + } + else { + snprintf(key1Id, 1024, "ed25519:%s", client->deviceId); + MatrixOlmAccountGetSigningKey(&client->olmAccount, key1, 1024); + snprintf(key2Id, 1024, "ed25519:%s", masterKey); + strcpy(key2, masterKey); + } + + snprintf(keyList, 1024, + "%s,%s", key1Id, key2Id); + + STATIC char macInfo[1024]; + int macInfoLen; + { + macInfoLen = + snprintf(macInfo, 1024, + "MATRIX_KEY_VERIFICATION_MAC%s%s%s%s%s%s", + USER_ID, + client->deviceId, + USER_ID, + DEVICE_ID, + transactionId, + "KEY_IDS"); + olm_sas_calculate_mac_fixed_base64(olmSas, keyList, strlen(keyList), macInfo, macInfoLen, keyListMac, 1024); + } + { + macInfoLen = + snprintf(macInfo, 1024, + "MATRIX_KEY_VERIFICATION_MAC%s%s%s%s%s%s", + USER_ID, + client->deviceId, + USER_ID, + DEVICE_ID, + transactionId, + key1Id); + olm_sas_calculate_mac_fixed_base64(olmSas, key1, strlen(key1), macInfo, macInfoLen, key1Mac, 1024); + } + { + macInfoLen = + snprintf(macInfo, 1024, + "MATRIX_KEY_VERIFICATION_MAC%s%s%s%s%s%s", + USER_ID, + client->deviceId, + USER_ID, + DEVICE_ID, + transactionId, + key2Id); + olm_sas_calculate_mac_fixed_base64(olmSas, key2, strlen(key2), macInfo, macInfoLen, key2Mac, 1024); + } + + STATIC char verificationMacBuffer[1024]; + snprintf(verificationMacBuffer, 1024, + "{" + "\"keys\":\"%s\"," + "\"mac\":{" + "\"%s\":\"%s\"," + "\"%s\":\"%s\"" + "}," + "\"transaction_id\":\"%s\"" + "}", + keyListMac, + key1Id, + key1Mac, + key2Id, + key2Mac, + transactionId); + + MatrixClientSendToDevice(client, + USER_ID, + DEVICE_ID, + verificationMacBuffer, + "m.key.verification.mac"); + + STATIC char verificationDoneBuffer[128]; + snprintf(verificationDoneBuffer, 128, + "{" + "\"transaction_id\":\"%s\"" + "}", + transactionId); + + MatrixClientSendToDevice(client, + USER_ID, + DEVICE_ID, + verificationDoneBuffer, + "m.key.verification.done"); + + verified = true; + } + else if (strcmp(eventType, "m.room.encrypted") == 0) { + STATIC char algorithm[128]; + mjson_get_string(event, eventLen, "$.content.algorithm", algorithm, 128); + + if (strcmp(algorithm, "m.olm.v1.curve25519-aes-sha2") == 0) { + STATIC char thisDeviceKey[DEVICE_KEY_SIZE]; + MatrixOlmAccountGetDeviceKey(&client->olmAccount, thisDeviceKey, DEVICE_KEY_SIZE); + + STATIC char jp[128]; + snprintf(jp, 128, "$.content.ciphertext.%s.type", thisDeviceKey); + + double messageType; + mjson_get_number(event, eventLen, jp, &messageType); + int messageTypeInt = (int)messageType; + + snprintf(jp, 128, "$.content.ciphertext.%s.body", thisDeviceKey); + + mjson_get_string(event, eventLen, jp, encrypted, 2048); + + MatrixOlmSession * olmSession; + if (messageTypeInt == 0) { + MatrixClientGetOlmSessionIn(client, + USER_ID, + DEVICE_ID, + &olmSession); + } else { + MatrixClientGetOlmSessionOut(client, + USER_ID, + DEVICE_ID, + &olmSession); + } + + printf("event: %.*s\n", eventLen, event); + printf("encrypted: %s\n", encrypted); + + MatrixOlmSessionDecrypt(olmSession, + messageTypeInt, encrypted, decrypted, 2048); + + printf("decrypted: %s\n", decrypted); + + HandleEvent(client, decrypted, strlen(decrypted)); + } + } + else if (strcmp(eventType, "m.room_key") == 0 || + strcmp(eventType, "m.forwarded_room_key") == 0) { + STATIC char roomId[128]; + STATIC char sessionId[128]; + STATIC char sessionKey[1024]; + mjson_get_string(event, eventLen, "$.content.room_id", roomId, 128); + mjson_get_string(event, eventLen, "$.content.session_id", sessionId, 128); + mjson_get_string(event, eventLen, "$.content.session_key", sessionKey, 1024); + + printf("sessionId: %s\n", sessionId); + printf("sessionKey: %s\n", sessionKey); + + MatrixMegolmInSession * megolmInSession; + MatrixClientNewMegolmInSession(client, roomId, sessionId, sessionKey, &megolmInSession); + } +} + +void +HandleRoomEvent( + MatrixClient * client, + const char * room, int roomLen, + const char * event, int eventLen) +{ + STATIC char eventType[128]; + memset(eventType, 0, sizeof(eventType)); + mjson_get_string(event, eventLen, "$.type", eventType, 128); + + if (strcmp(eventType, "m.room.encrypted") == 0) { + STATIC char algorithm[128]; + mjson_get_string(event, eventLen, "$.content.algorithm", algorithm, 128); + + if (strcmp(algorithm, "m.megolm.v1.aes-sha2") == 0) { + STATIC char sessionId[128]; + int sessionIdLen = + mjson_get_string(event, eventLen, "$.content.session_id", sessionId, 128); + + bool res; + + MatrixMegolmInSession * megolmInSession; + res = MatrixClientGetMegolmInSession(client, + room, roomLen, + sessionId, sessionIdLen, + &megolmInSession); + + if (res) { + mjson_get_string(event, eventLen, "$.content.ciphertext", encrypted, 2048); + + MatrixMegolmInSessionDecrypt(megolmInSession, encrypted, strlen(encrypted), decrypted, 2048); + + printf("decrypted: %s\n", decrypted); + + HandleEvent(client, decrypted, strlen(decrypted)); + } + else { + printf("megolm session not known\n"); + } + } + } + HandleEvent(client, event, eventLen); +} + +void +Sync( + MatrixClient * client, + char * syncBuffer +) { + STATIC char nextBatch[1024] = {0}; + + MatrixClientSync(client, syncBuffer, 1024, nextBatch); + + int res; + + const char * s = syncBuffer; + int slen = strlen(syncBuffer); + + // { + // int koff, klen, voff, vlen, vtype, off = 0; + // for (off = 0; (off = mjson_next(s, slen, off, &koff, &klen, + // &voff, &vlen, &vtype)) != 0; ) { + // const char * k = s + koff; + // const char * v = s + voff; + + // printf("%.*s: %.100s\n", klen, k, v); + // } + // } + + mjson_get_string(s, slen, "$.next_batch", nextBatch, 1024); + + // to_device + + const char * events; + int eventsLen; + res = + mjson_find(s, slen, "$.to_device.events", &events, &eventsLen); + + if (res != MJSON_TOK_INVALID) { + { + int koff, klen, voff, vlen, vtype, off = 0; + for (off = 0; (off = mjson_next(events, eventsLen, off, &koff, &klen, + &voff, &vlen, &vtype)) != 0; ) { + const char * v = events + voff; + + HandleEvent(client, v, vlen); + } + } + } + + // rooms + + const char * rooms; + int roomsLen; + res = + mjson_find(s, slen, "$.rooms.join", &rooms, &roomsLen); + + if (res != MJSON_TOK_INVALID) { + { + int koff, klen, voff, vlen, vtype, off = 0; + for (off = 0; (off = mjson_next(rooms, roomsLen, off, &koff, &klen, + &voff, &vlen, &vtype)) != 0; ) { + const char * k = rooms + koff; + const char * v = rooms + voff; + + const char * events; + int eventsLen; + res = + mjson_find(v, vlen, "$.timeline.events", &events, &eventsLen); + + if (res != MJSON_TOK_INVALID) { + { + int koff2, klen2, voff2, vlen2, vtype2, off2 = 0; + for (off2 = 0; (off2 = mjson_next(events, eventsLen, off2, &koff2, &klen2, + &voff2, &vlen2, &vtype2)) != 0; ) { + const char * v2 = events + voff2; + + HandleRoomEvent(client, + k+1, klen-2, + v2, vlen2); + } + } + } + } + } + } +} + + +int +main(void) +{ + STATIC MatrixClient _client; + MatrixClient * client = &_client; + // MatrixClient * client = (MatrixClient*)malloc(sizeof(MatrixClient)); + MatrixClientInit(client); + + MatrixHttpInit(&client->hc, SERVER); + MatrixClientSetUserId(client, USER_ID); + + MatrixClientLoginPassword(client, + "pscho", + "Wc23EbmB9G3faMq", + "Test1"); + printf("deviceId: %s\n", client->deviceId); + MatrixClientGenerateOnetimeKeys(client, 10); + MatrixClientUploadOnetimeKeys(client); + MatrixClientUploadDeviceKey(client); + + STATIC char eventBuffer[1024]; + MatrixClientGetRoomEvent(client, + ROOM_ID, + EVENT_ID, + eventBuffer, 1024); + printf("event: %s\n", eventBuffer); + + char * syncBuffer = (char*)malloc(1024*40); + // STATIC char syncBuffer[1024]; + + while (! verified) + Sync(client, syncBuffer); + + // while (getchar() != 'q') + // Sync(client, syncBuffer); + + MatrixClientRequestMegolmInSession(client, + ROOM_ID, + SESSION_ID, + SENDER_KEY, + USER_ID, + DEVICE_ID); + + MatrixMegolmInSession * megolmInSession; + while (! MatrixClientGetMegolmInSession(client, + ROOM_ID, strlen(ROOM_ID), + SESSION_ID, strlen(SESSION_ID), + &megolmInSession)) + Sync(client, syncBuffer); + + int encryptedLen = + mjson_get_string(eventBuffer, strlen(eventBuffer), "$.content.ciphertext", encrypted, 1024); + + printf("encrypted: [%.*s]\n", encryptedLen, encrypted); + + MatrixMegolmInSessionDecrypt(megolmInSession, + encrypted, encryptedLen, + decrypted, 1024); + + printf("decrypted: %s\n", decrypted); + + MatrixClientDeleteDevice(client); + + MatrixHttpDeinit(&client->hc); + + return 0; +} + +#include "wifi.h" + +void +app_main(void) +{ + wifi_init("Hundehuette", "Affensicherespw55"); + + main(); +} diff --git a/esp32/esp_project/main/wifi.h b/esp32/esp_project/main/wifi.h new file mode 100644 index 0000000..750a197 --- /dev/null +++ b/esp32/esp_project/main/wifi.h @@ -0,0 +1 @@ +void wifi_init(const char *ssid, const char *pass); \ No newline at end of file diff --git a/src/matrix_http_esp32.c b/src/matrix_http_esp32.c new file mode 100644 index 0000000..3faf9f5 --- /dev/null +++ b/src/matrix_http_esp32.c @@ -0,0 +1,315 @@ +#include +#include +#include +#include +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_event.h" +#include "esp_netif.h" +// #include "protocol_examples_common.h" +// #include "protocol_examples_utils.h" +#include "esp_tls.h" +#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE +#include "esp_crt_bundle.h" +#endif + +#if !CONFIG_IDF_TARGET_LINUX +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#endif + +#include "esp_http_client.h" + +/* Root cert for howsmyssl.com, taken from howsmyssl_com_root_cert.pem + + The PEM file was extracted from the output of this command: + openssl s_client -showcerts -connect www.howsmyssl.com:443 user_data; + switch(evt->event_id) { + case HTTP_EVENT_ERROR: + ESP_LOGD(TAG, "HTTP_EVENT_ERROR"); + break; + case HTTP_EVENT_ON_CONNECTED: + ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED"); + break; + case HTTP_EVENT_HEADER_SENT: + ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT"); + break; + case HTTP_EVENT_ON_HEADER: + ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value); + break; + case HTTP_EVENT_ON_DATA: + ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len); + /* + * Check for chunked encoding is added as the URL for chunked encoding used in this example returns binary data. + * However, event handler can also be used in case chunked encoding is used. + */ + if (!esp_http_client_is_chunked_response(evt->client)) { + ESP_LOGD(TAG, "Non-Chunked Encoding"); + } + else { + ESP_LOGD(TAG, "Chunked Encoding"); + } + + int copy_len = 0; + + // const int64_t buffer_len = esp_http_client_get_content_length(evt->client); + // if (buffer_len < hc->dataCap) { + // ESP_LOGE(TAG, "Output buffer too small: %" PRIu64 ", data_len: %d", buffer_len, evt->data_len); + // return ESP_FAIL; + // } + copy_len = MIN(evt->data_len, (hc->dataCap - hc->dataLen)); + if (copy_len) { + memcpy(hc->data + hc->dataLen, evt->data, copy_len); + } + + hc->dataLen += copy_len; + + break; + case HTTP_EVENT_ON_FINISH: + ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH"); + break; + case HTTP_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED"); + int mbedtls_err = 0; + esp_err_t err = esp_tls_get_and_clear_last_error((esp_tls_error_handle_t)evt->data, &mbedtls_err, NULL); + if (err != 0) { + ESP_LOGI(TAG, "Last esp error code: 0x%x", err); + ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err); + } + break; + case HTTP_EVENT_REDIRECT: + ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT"); + // esp_http_client_set_header(evt->client, "From", "user@example.com"); + // esp_http_client_set_header(evt->client, "Accept", "text/html"); + // esp_http_client_set_redirection(evt->client); + break; + } + return ESP_OK; +} + +void +MatrixHttpConnect( + MatrixHttpConnection * hc) +{ + esp_http_client_config_t config = { + .url = hc->host, + // .query = "esp", + .event_handler = _http_event_handler, + .user_data = hc, + .disable_auto_redirect = true, + .crt_bundle_attach = esp_crt_bundle_attach, + }; + + hc->client = esp_http_client_init(&config); + + esp_http_client_set_timeout_ms(hc->client, 10000); +} + +void +MatrixHttpDisconnect( + MatrixHttpConnection * hc) +{ + esp_http_client_cleanup(hc->client); + hc->client = NULL; +} + +bool +MatrixHttpInit( + MatrixHttpConnection ** hc, + const char * host) +{ + *hc = (MatrixHttpConnection *)calloc(1, sizeof(MatrixHttpConnection)); + + (*hc)->host = host; + (*hc)->dataLen = 0; + + MatrixHttpConnect(*hc); + + return true; +} + +bool +MatrixHttpDeinit( + MatrixHttpConnection ** hc) +{ + MatrixHttpDisconnect(*hc); + + free(*hc); + *hc = NULL; + + return true; +} + +bool +MatrixHttpSetAccessToken( + MatrixHttpConnection * hc, + const char * accessToken) +{ + hc->accessToken = accessToken; + + return true; +} + +bool +MatrixHttpGet( + MatrixHttpConnection * hc, + const char * url, + char * outResponseBuffer, int outResponseCap, + bool authenticated) +{ + static char authorizationHeader[AUTHORIZATION_HEADER_LEN]; + if (authenticated) + snprintf(authorizationHeader, AUTHORIZATION_HEADER_LEN, + "Bearer %s", hc->accessToken); + else + authorizationHeader[0] = '\0'; + + printf("GET %s%s\n", hc->host, url); + + hc->data = outResponseBuffer; + hc->dataCap = outResponseCap; + hc->dataLen = 0; + + static char hostAndUrl[MAX_URL_LEN]; + snprintf(hostAndUrl, MAX_URL_LEN, "%s%s", hc->host, url); + + esp_http_client_set_url(hc->client, hostAndUrl); + esp_http_client_set_method(hc->client, HTTP_METHOD_GET); + if (authenticated) + esp_http_client_set_header(hc->client, "Authorization", authorizationHeader); + esp_err_t err = esp_http_client_perform(hc->client); + if (err == ESP_OK) { + ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %"PRIu64, + esp_http_client_get_status_code(hc->client), + esp_http_client_get_content_length(hc->client)); + } else { + ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err)); + } + // ESP_LOG_BUFFER_HEX(TAG, hc->data, hc->dataLen); + + return true; +} + +bool +MatrixHttpPost( + MatrixHttpConnection * hc, + const char * url, + const char * requestBuffer, + char * outResponseBuffer, int outResponseCap, + bool authenticated) +{ + static char authorizationHeader[AUTHORIZATION_HEADER_LEN]; + if (authenticated) + snprintf(authorizationHeader, AUTHORIZATION_HEADER_LEN, + "Bearer %s", hc->accessToken); + else + authorizationHeader[0] = '\0'; + + printf("POST %s%s\n%s\n", hc->host, url, requestBuffer); + + hc->data = outResponseBuffer; + hc->dataCap = outResponseCap; + hc->dataLen = 0; + + static char hostAndUrl[MAX_URL_LEN]; + snprintf(hostAndUrl, MAX_URL_LEN, "%s%s", hc->host, url); + + esp_http_client_set_url(hc->client, hostAndUrl); + esp_http_client_set_method(hc->client, HTTP_METHOD_POST); + if (authenticated) + esp_http_client_set_header(hc->client, "Authorization", authorizationHeader); + esp_http_client_set_header(hc->client, "Content-Type", "application/json"); + esp_http_client_set_post_field(hc->client, requestBuffer, strlen(requestBuffer)); + esp_err_t err = esp_http_client_perform(hc->client); + if (err == ESP_OK) { + ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %"PRIu64, + esp_http_client_get_status_code(hc->client), + esp_http_client_get_content_length(hc->client)); + } else { + ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err)); + } + // ESP_LOG_BUFFER_HEX(TAG, hc->data, hc->dataLen); + + return true; +} + +bool +MatrixHttpPut( + MatrixHttpConnection * hc, + const char * url, + const char * requestBuffer, + char * outResponseBuffer, int outResponseCap, + bool authenticated) +{ + static char authorizationHeader[AUTHORIZATION_HEADER_LEN]; + if (authenticated) + snprintf(authorizationHeader, AUTHORIZATION_HEADER_LEN, + "Bearer %s", hc->accessToken); + else + authorizationHeader[0] = '\0'; + + printf("PUT %s%s\n%s\n", hc->host, url, requestBuffer); + + hc->data = outResponseBuffer; + hc->dataCap = outResponseCap; + hc->dataLen = 0; + + static char hostAndUrl[MAX_URL_LEN]; + snprintf(hostAndUrl, MAX_URL_LEN, "%s%s", hc->host, url); + + esp_http_client_set_url(hc->client, hostAndUrl); + esp_http_client_set_method(hc->client, HTTP_METHOD_PUT); + if (authenticated) + esp_http_client_set_header(hc->client, "Authorization", authorizationHeader); + esp_http_client_set_header(hc->client, "Content-Type", "application/json"); + esp_http_client_set_post_field(hc->client, requestBuffer, strlen(requestBuffer)); + esp_err_t err = esp_http_client_perform(hc->client); + if (err == ESP_OK) { + ESP_LOGI(TAG, "HTTP PUT Status = %d, content_length = %"PRIu64, + esp_http_client_get_status_code(hc->client), + esp_http_client_get_content_length(hc->client)); + } else { + ESP_LOGE(TAG, "HTTP PUT request failed: %s", esp_err_to_name(err)); + } + // ESP_LOG_BUFFER_HEX(TAG, hc->data, hc->dataLen); + + return true; +}