]> gitweb.ps.run Git - matrix_esp_thesis/commitdiff
working examples for esp
authorPatrick <patrick.schoenberger@posteo.de>
Fri, 13 Oct 2023 13:59:29 +0000 (15:59 +0200)
committerPatrick <patrick.schoenberger@posteo.de>
Fri, 13 Oct 2023 13:59:29 +0000 (15:59 +0200)
esp32/esp_project/components/matrix/CMakeLists.txt [new file with mode: 0644]
esp32/esp_project/main/SendEncrypted.c [new file with mode: 0644]
esp32/esp_project/main/Verify.c [new file with mode: 0644]
esp32/esp_project/main/wifi.h [new file with mode: 0644]
src/matrix_http_esp32.c [new file with mode: 0644]

diff --git a/esp32/esp_project/components/matrix/CMakeLists.txt b/esp32/esp_project/components/matrix/CMakeLists.txt
new file mode 100644 (file)
index 0000000..485b3c6
--- /dev/null
@@ -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 (file)
index 0000000..900856d
--- /dev/null
@@ -0,0 +1,80 @@
+#define OLMLIB_VERSION_MAJOR 3
+#define OLMLIB_VERSION_MINOR 2
+#define OLMLIB_VERSION_PATCH 15
+
+#define OLM_STATIC_DEFINE
+
+#include <stdio.h>
+#include <matrix.h>
+
+#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 (file)
index 0000000..124ddd2
--- /dev/null
@@ -0,0 +1,541 @@
+#include <matrix.h>
+#include <mjson.h>
+#include <olm/sas.h>
+
+#include <stdio.h>
+
+#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 (file)
index 0000000..750a197
--- /dev/null
@@ -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 (file)
index 0000000..3faf9f5
--- /dev/null
@@ -0,0 +1,315 @@
+#include <string.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <ctype.h>
+#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 </dev/null
+
+   The CA root cert is the last cert given in the chain of certs.
+
+   To embed it in the app binary, the PEM file is named
+   in the component.mk COMPONENT_EMBED_TXTFILES variable.
+*/
+// 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");
+
+// extern const char postman_root_cert_pem_start[] asm("_binary_postman_root_cert_pem_start");
+// extern const char postman_root_cert_pem_end[]   asm("_binary_postman_root_cert_pem_end");
+
+#include "matrix.h"
+
+#define HTTP_CONNECTION_DATA_SIZE 1024*64
+#define AUTHORIZATION_HEADER_LEN 64
+
+struct MatrixHttpConnection {
+    esp_http_client_handle_t client;
+
+    const char * host;
+    const char * accessToken;
+
+    // char data[HTTP_CONNECTION_DATA_SIZE];
+    char * data;
+    int dataCap;
+    int dataLen;
+};
+
+
+static const char *TAG = "HTTP_CLIENT";
+
+esp_err_t _http_event_handler(esp_http_client_event_t *evt)
+{
+    vTaskDelay(10/portTICK_PERIOD_MS);
+
+    MatrixHttpConnection * hc = (MatrixHttpConnection *)evt->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;
+}