abouttreesummaryrefslogcommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--examples/Decrypt.c45
-rw-r--r--examples/Login.c10
-rw-r--r--examples/Send.c2
-rw-r--r--examples/SendEncrypted.c40
-rw-r--r--examples/Sync.c31
-rw-r--r--src/fixedbuffer.c43
-rw-r--r--src/fixedbuffer.h19
-rw-r--r--src/matrix.c566
-rw-r--r--src/matrix.h173
-rw-r--r--src/matrix_http_mongoose.c31
11 files changed, 829 insertions, 135 deletions
diff --git a/Makefile b/Makefile
index 82c259a..88b1941 100644
--- a/Makefile
+++ b/Makefile
@@ -9,11 +9,12 @@ C_OPTS+=-I src/
C_OPTS+=-I ext/olm/include/
C_OPTS+=-I ext/mjson/src/
C_OPTS+=-I ext/mongoose/
+C_OPTS+=-L out/olm/
C_OPTS+=-l ws2_32
C_OPTS+=-l ssl
C_OPTS+=-l crypto
+C_OPTS+=-l olm
C_OPTS+=-D MG_ENABLE_OPENSSL=1
-C_OPTS+=-g
# C_OPTS+=-I ext/curl/include/
# C_OPTS+=-L ext/curl/build/lib/
# C_OPTS+=-l curl
@@ -23,7 +24,6 @@ C_OPTS+=-g
out/examples/%: examples/%.c src/*
$(CC) -o out/examples/$* examples/$*.c $(C_OPTS)
-
.PHONY: examples
examples: out/examples/Login out/examples/Send out/examples/SendEncrypted out/examples/Sync \ No newline at end of file
diff --git a/examples/Decrypt.c b/examples/Decrypt.c
new file mode 100644
index 0000000..b496780
--- /dev/null
+++ b/examples/Decrypt.c
@@ -0,0 +1,45 @@
+#include <matrix.h>
+#include <stdio.h>
+
+#define SERVER "https://matrix.org"
+#define ACCESS_TOKEN "syt_cHNjaG8_yBvTjVTquGCikvsAenOJ_49mBMO"
+#define DEVICE_ID "MAZNCCZLBR"
+#define ROOM_ID "!koVStwyiiKcBVbXZYz:matrix.org"
+#define EVENT_ID ""
+
+int
+main(void)
+{
+ MatrixClient client;
+ MatrixClientInit(&client,
+ SERVER);
+
+ MatrixHttpInit(&client);
+
+ MatrixClientSetAccessToken(&client,
+ ACCESS_TOKEN);
+
+ static char eventBuffer[1024];
+ MatrixClientGetRoomEvent(&client,
+ ROOM_ID,
+ EVENT_ID,
+ eventBuffer, 1024);
+
+ MatrixMegolmInSession megolmSession;
+
+ MatrixClientRequestMegolmSession(&client,
+ ROOM_ID,
+ EVENT_ID,
+ &megolmSession);
+
+ static char decryptedBuffer[1024];
+ MatrixMegolmSessionDecrypt(&megolmSession,
+ eventBuffer,
+ decryptedBuffer, 1024);
+
+ printf("%s\n", decryptedBuffer);
+
+ MatrixHttpDeinit(&client);
+
+ return 0;
+} \ No newline at end of file
diff --git a/examples/Login.c b/examples/Login.c
index 45204fc..1ffbbc0 100644
--- a/examples/Login.c
+++ b/examples/Login.c
@@ -8,7 +8,7 @@
int
-main()
+main(void)
{
MatrixClient client;
MatrixClientInit(&client,
@@ -21,10 +21,10 @@ main()
PASSWORD,
DISPLAYNAME);
- printf("Access Token: %s\n", client.accessTokenBuffer);
- printf("Device ID: %s\n", client.deviceIdBuffer);
- printf("Expires in (ms): %s\n", client.expireMsBuffer);
- printf("Refresh Token: %s\n", client.refreshTokenBuffer);
+ printf("Access Token: %s\n", client.accessToken);
+ printf("Device ID: %s\n", client.deviceId);
+ printf("Expires in (ms): %s\n", client.expireMs);
+ printf("Refresh Token: %s\n", client.refreshToken);
MatrixHttpDeinit(&client);
diff --git a/examples/Send.c b/examples/Send.c
index e595ba7..cddb966 100644
--- a/examples/Send.c
+++ b/examples/Send.c
@@ -6,7 +6,7 @@
#define ROOM_ID "!koVStwyiiKcBVbXZYz:matrix.org"
int
-main()
+main(void)
{
MatrixClient client;
MatrixClientInit(&client,
diff --git a/examples/SendEncrypted.c b/examples/SendEncrypted.c
index 2d3bd74..db2f83c 100644
--- a/examples/SendEncrypted.c
+++ b/examples/SendEncrypted.c
@@ -1,32 +1,36 @@
#include <matrix.h>
+#include <stdio.h>
-#define SERVER FixedBuf("matrix.org")
-#define ACCESS_TOKEN FixedBuf("abc")
-#define ROOM_ID FixedBuf("!jhpZBTbckszblMYjMK:matrix.org")
+#define SERVER "https://matrix.org"
+#define ACCESS_TOKEN "syt_cHNjaG8_yBvTjVTquGCikvsAenOJ_49mBMO"
+#define DEVICE_ID "MAZNCCZLBR"
+#define ROOM_ID "!koVStwyiiKcBVbXZYz:matrix.org"
int
-main(
- int argc,
- char **argv)
+main(void)
{
MatrixClient client;
- MatrixClientCreate(&client,
+ MatrixClientInit(&client,
SERVER);
+
+ MatrixHttpInit(&client);
MatrixClientSetAccessToken(&client,
ACCESS_TOKEN);
- MatrixMegolmSession megolm;
- MatrixMegolmSessionInit(&megolm);
-
- MatrixRoomShareMegolmSession(&client,
- ROOM_ID,
- megolm);
-
- MatrixClientSendGroupEncrypted(&client,
+ // MatrixMegolmOutSession megolmOutSession;
+ // MatrixMegolmOutSessionInit(&megolmOutSession);
+
+ // MatrixClientSetMegolmOutSession(&client,
+ // ROOM_ID,
+ // megolmOutSession);
+
+ MatrixClientSendEventEncrypted(&client,
ROOM_ID,
- FixedBuf("m.room.message"),
- FixedBuf("{\"body\":\"Hello\",\"msgtype\":\"m.text\"}"));
+ "m.room.message",
+ "{\"body\":\"Hello\",\"msgtype\":\"m.text\"}");
+
+ MatrixHttpDeinit(&client);
return 0;
-} \ No newline at end of file
+}
diff --git a/examples/Sync.c b/examples/Sync.c
index 5043884..a49cf65 100644
--- a/examples/Sync.c
+++ b/examples/Sync.c
@@ -1,31 +1,28 @@
#include <matrix.h>
+#include <stdio.h>
-#define SERVER "matrix.org"
-#define ACCESS_TOKEN "abc"
-#define ROOM_ID "!jhpZBTbckszblMYjMK:matrix.org"
+#define SERVER "https://matrix.org"
+#define ACCESS_TOKEN "syt_cHNjaG8_yBvTjVTquGCikvsAenOJ_49mBMO"
+#define DEVICE_ID "MAZNCCZLBR"
int
-main(
- int argc,
- char **argv)
+main(void)
{
MatrixClient client;
- MatrixClientCreate(&client,
+ MatrixClientInit(&client,
SERVER);
+
+ MatrixHttpInit(&client);
MatrixClientSetAccessToken(&client,
ACCESS_TOKEN);
- static char syncCharBuffer[1024];
- FixedBuffer syncBuffer = { syncCharBuffer, 1024, 0 };
- int syncN = 1;
-
- while (syncN > 0)
- {
- MatrixClientSyncN(&client, &syncBuffer, &syncN);
- printf("%.*s", syncBuffer.len, (char *)syncBuffer.ptr);
- }
- printf("\n");
+ static char syncBuffer[20000];
+ MatrixClientSync(&client,
+ syncBuffer, 20000);
+ printf("%s", syncBuffer);
+
+ MatrixHttpDeinit(&client);
return 0;
} \ No newline at end of file
diff --git a/src/fixedbuffer.c b/src/fixedbuffer.c
deleted file mode 100644
index ad99897..0000000
--- a/src/fixedbuffer.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include "fixedbuffer.h"
-
-#include <string.h>
-
-FixedBuffer
-FixedBuf(const char * str)
-{
- int len = strlen(str);
- FixedBuffer result;
- result.ptr = (char *)str;
- result.cap = len;
- result.len = len;
- return result;
-}
-
-bool
-FixedBufferToInt(FixedBuffer fb, int * outInt)
-{
- bool valid = false;
- int result = 0;
-
- bool negative = false;
-
- for (int i = 0; i < fb.len; i++)
- {
- if (i == 0 && fb.ptr[i] == '-')
- {
- negative = true;
- continue;
- }
-
- int val = fb.ptr[i] - '0';
- if (val < 0 || val > 9)
- return false;
-
- result *= 10;
- result += val;
- valid = true;
- }
-
- *outInt = result;
- return valid;
-} \ No newline at end of file
diff --git a/src/fixedbuffer.h b/src/fixedbuffer.h
deleted file mode 100644
index d8055cb..0000000
--- a/src/fixedbuffer.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef FIXEDBUFFER__H
-#define FIXEDBUFFER__H
-
-#include <stdbool.h>
-
-typedef struct FixedBuffer {
- char * ptr;
- int cap;
- int len;
-} FixedBuffer;
-
-FixedBuffer
-FixedBuf(const char * str);
-
-bool
-FixedBufferToInt(FixedBuffer fb, int * outInt);
-
-
-#endif \ No newline at end of file
diff --git a/src/matrix.c b/src/matrix.c
index 7cc4de9..28e7634 100644
--- a/src/matrix.c
+++ b/src/matrix.c
@@ -9,21 +9,153 @@
#define LOGIN_RESPONSE_SIZE 1024
#define LOGIN_URL "/_matrix/client/v3/login"
-#define ROOMEVENT_REQUEST_SIZE 1024
+#define ENCRYPTED_REQUEST_SIZE 512
+#define ENCRYPTED_EVENT_SIZE 1024
+#define ROOMEVENT_REQUEST_SIZE 256
#define ROOMEVENT_RESPONSE_SIZE 1024
#define ROOMEVENT_URL "/_matrix/client/v3/rooms/%s/send/%s/%d"
+#define TODEVICE_EVENT_SIZE 512
+#define TODEVICE_URL "/_matrix/client/v3/sendToDevice/%s/%d"
+
+#define KEYS_QUERY_URL "/_matrix/client/v3/keys/query"
+#define KEYS_QUERY_REQUEST_SIZE 256
+#define KEYS_QUERY_RESPONSE_SIZE 1024
+
+#define JSON_QUERY_SIZE 128
+
+
+
+void
+Randomize(uint8_t * random, int randomLen)
+{
+ static bool first = false;
+ if (first) { srand(time(0)); first = false; }
+
+ for (int i = 0; i < randomLen; i++)
+ {
+ random[i] = rand() % 256;
+ }
+}
+
+bool
+JsonEscape(
+ char * sIn, int sInLen,
+ char * sOut, int sOutCap)
+{
+ int sOutIndex = 0;
+
+ for (int i = 0; i < sInLen; i++)
+ {
+ if (i >= sOutCap)
+ return false;
+
+ if (sIn[i] == '.' ||
+ sIn[i] == '[' ||
+ sIn[i] == ']'
+ ) {
+ sOut[sOutIndex++] = '\\';
+ }
+ sOut[sOutIndex++] = sIn[i];
+ }
+
+ if (sOutIndex < sOutCap)
+ sOut[sOutIndex] = '\0';
+
+ return true;
+}
+
+// TODO: in/outbound sessions
+bool
+MatrixOlmSessionInit(
+ MatrixOlmSession * session,
+ const char * deviceId)
+{
+ memset(session, 0, sizeof(MatrixOlmSession));
+
+ static uint8_t random[MEGOLM_INIT_RANDOM_SIZE];
+ Randomize(random, MEGOLM_INIT_RANDOM_SIZE);
+
+ session->deviceId = deviceId;
+
+ session->session =
+ olm_session(session->memory);
+
+ return session->session != NULL;
+}
+
+bool
+MatrixOlmSessionEncrypt(
+ MatrixOlmSession * session,
+ const char * plaintext,
+ char * outBuffer, int outBufferCap)
+{
+ static uint8_t random[OLM_ENCRYPT_RANDOM_SIZE];
+ Randomize(random, OLM_ENCRYPT_RANDOM_SIZE);
+
+ size_t res = olm_encrypt(session->session,
+ plaintext, strlen(plaintext),
+ random, OLM_ENCRYPT_RANDOM_SIZE,
+ outBuffer, outBufferCap);
+
+ return res != olm_error();
+}
+
+// https://matrix.org/docs/guides/end-to-end-encryption-implementation-guide#starting-a-megolm-session
+bool
+MatrixMegolmOutSessionInit(
+ MatrixMegolmOutSession * session,
+ const char * roomId)
+{
+ memset(session, 0, sizeof(MatrixMegolmOutSession));
+
+ static uint8_t random[MEGOLM_INIT_RANDOM_SIZE];
+ Randomize(random, MEGOLM_INIT_RANDOM_SIZE);
+
+ session->roomId = roomId;
+
+ session->session =
+ olm_outbound_group_session(session->memory);
+
+ olm_init_outbound_group_session(
+ session->session,
+ random,
+ MEGOLM_INIT_RANDOM_SIZE);
+
+ olm_outbound_group_session_id(session->session,
+ (uint8_t *)session->id,
+ MEGOLM_SESSION_ID_SIZE);
+
+ olm_outbound_group_session_key(session->session,
+ (uint8_t *)session->key,
+ MEGOLM_SESSION_KEY_SIZE);
+
+ return true;
+}
+
+bool
+MatrixMegolmOutSessionEncrypt(
+ MatrixMegolmOutSession * session,
+ const char * plaintext,
+ char * outBuffer, int outBufferCap)
+{
+ size_t res = olm_group_encrypt(session->session,
+ (uint8_t *)plaintext, strlen(plaintext),
+ (uint8_t *)outBuffer, outBufferCap);
+
+ return res != olm_error();
+}
+
+
bool
MatrixClientInit(
MatrixClient * client,
const char * server)
{
- strcpy_s(
- client->server,
- SERVER_SIZE,
- server
- );
+ memset(client, 0, sizeof(MatrixClient));
+
+ strcpy(client->server, server);
return true;
}
@@ -39,7 +171,7 @@ MatrixClientSetAccessToken(
return false;
for (int i = 0; i < accessTokenLen; i++)
- client->accessTokenBuffer[i] = accessToken[i];
+ client->accessToken[i] = accessToken[i];
return true;
}
@@ -83,20 +215,21 @@ MatrixClientLoginPassword(
mjson_get_string(responseBuffer, responseLen,
"$.access_token",
- client->accessTokenBuffer, ACCESS_TOKEN_SIZE);
+ client->accessToken, ACCESS_TOKEN_SIZE);
mjson_get_string(responseBuffer, responseLen,
"$.device_id",
- client->deviceIdBuffer, DEVICE_ID_SIZE);
+ client->deviceId, DEVICE_ID_SIZE);
mjson_get_string(responseBuffer, responseLen,
"$.expires_in_ms",
- client->expireMsBuffer, EXPIRE_MS_SIZE);
+ client->expireMs, EXPIRE_MS_SIZE);
mjson_get_string(responseBuffer, responseLen,
"$.refresh_token",
- client->refreshTokenBuffer, REFRESH_TOKEN_SIZE);
+ client->refreshToken, REFRESH_TOKEN_SIZE);
return true;
}
-
+
+// https://spec.matrix.org/v1.6/client-server-api/#put_matrixclientv3roomsroomidsendeventtypetxnid
bool
MatrixClientSendEvent(
MatrixClient * client,
@@ -105,8 +238,8 @@ MatrixClientSendEvent(
const char * msgBody)
{
static char requestUrl[MAX_URL_LEN];
- sprintf_s(requestUrl, MAX_URL_LEN,
- ROOMEVENT_URL, roomId, msgType, time(NULL));
+ sprintf(requestUrl,
+ ROOMEVENT_URL, roomId, msgType, (int)time(NULL));
static char responseBuffer[ROOMEVENT_RESPONSE_SIZE];
bool result =
@@ -119,3 +252,408 @@ MatrixClientSendEvent(
return result;
}
+// https://spec.matrix.org/v1.6/client-server-api/#mroomencrypted
+// https://matrix.org/docs/guides/end-to-end-encryption-implementation-guide#sending-an-encrypted-message-event
+bool
+MatrixClientSendEventEncrypted(
+ MatrixClient * client,
+ const char * roomId,
+ const char * msgType,
+ const char * msgBody)
+{
+ // event json
+ static char requestBuffer[ROOMEVENT_REQUEST_SIZE];
+ sprintf(requestBuffer,
+ "{"
+ "\"type\":\"%s\","
+ "\"content\":%s,"
+ "\"room_id\":\"%s\""
+ "}",
+ msgType,
+ msgBody,
+ roomId);
+
+ // get megolm session
+ MatrixMegolmOutSession * outSession;
+ MatrixClientGetMegolmOutSession(client, roomId, &outSession);
+
+ // encrypt
+ static char encryptedBuffer[ENCRYPTED_REQUEST_SIZE];
+ MatrixMegolmOutSessionEncrypt(outSession,
+ requestBuffer,
+ encryptedBuffer, ENCRYPTED_REQUEST_SIZE);
+
+ // encrypted event json
+ const char * senderKey = client->deviceKey;
+ const char * sessionId = outSession->id;
+ const char * deviceId = client->deviceId;
+
+ static char encryptedEventBuffer[ENCRYPTED_EVENT_SIZE];
+ sprintf(encryptedEventBuffer,
+ "{"
+ "\"algorithm\":\"m.megolm.v1.aes-sha2\","
+ "\"sender_key\":\"%s\","
+ "\"ciphertext\":\"%s\","
+ "\"session_id\":%s,"
+ "\"device_id\":\"%s\""
+ "}",
+ senderKey,
+ encryptedBuffer,
+ sessionId,
+ deviceId);
+
+ // send
+ return MatrixClientSendEvent(client,
+ roomId,
+ "m.room.encrypted",
+ encryptedEventBuffer);
+}
+
+// https://spec.matrix.org/v1.6/client-server-api/#get_matrixclientv3sync
+bool
+MatrixClientSync(
+ MatrixClient * client,
+ char * outSyncBuffer, int outSyncCap)
+{
+ return
+ MatrixHttpGet(client,
+ "/_matrix/client/v3/sync",
+ outSyncBuffer, outSyncCap,
+ true);
+}
+
+bool
+MatrixClientShareMegolmOutSession(
+ MatrixClient * client,
+ const char * deviceId,
+ MatrixMegolmOutSession * session)
+{
+ // generate room key event
+ char eventBuffer[KEY_SHARE_EVENT_LEN];
+ sprintf(eventBuffer,
+ "{"
+ "\"algorithm\":\"m.megolm.v1.aes-sha2\","
+ "\"room_id\":\"%s\","
+ "\"session_id\":\"%s\","
+ "\"session_key\":\"%s\""
+ "}",
+ session->roomId,
+ session->id,
+ session->key
+ );
+
+ // get olm session
+ MatrixOlmSession * olmSession;
+ MatrixClientGetOlmSession(client, deviceId, &olmSession);
+
+ // encrypt
+ char encryptedBuffer[KEY_SHARE_EVENT_LEN];
+ MatrixOlmSessionEncrypt(olmSession,
+ eventBuffer,
+ encryptedBuffer, KEY_SHARE_EVENT_LEN);
+
+ // send
+ MatrixClientSendToDeviceEncrypted(client,
+ client->userId,
+ deviceId,
+ encryptedBuffer,
+ "m.room_key");
+
+ return true;
+}
+
+// bool
+// MatrixClientSetMegolmOutSession(
+// MatrixClient * client,
+// const char * roomId,
+// MatrixMegolmOutSession session)
+// {
+// if (client->numMegolmOutSessions < 10)
+// {
+// session.roomId = roomId;
+// client->megolmOutSessions[client->numMegolmOutSessions] = session;
+// client->numMegolmOutSessions++;
+
+// return true;
+// }
+// return false;
+// }
+
+bool
+MatrixClientGetMegolmOutSession(
+ MatrixClient * client,
+ const char * roomId,
+ MatrixMegolmOutSession ** outSession)
+{
+ for (int i = 0; i < client->numMegolmOutSessions; i++)
+ {
+ if (strcmp(client->megolmOutSessions[i].roomId, roomId) == 0)
+ {
+ *outSession = &client->megolmOutSessions[i];
+ return true;
+ }
+ }
+
+ if (client->numMegolmOutSessions < NUM_MEGOLM_SESSIONS)
+ {
+ MatrixMegolmOutSessionInit(
+ &client->megolmOutSessions[client->numMegolmOutSessions],
+ roomId);
+
+ *outSession = &client->megolmOutSessions[client->numMegolmOutSessions];
+
+ client->numMegolmOutSessions++;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool
+MatrixClientGetOlmSession(
+ MatrixClient * client,
+ const char * deviceId,
+ MatrixOlmSession ** outSession)
+{
+ for (int i = 0; i < client->numOlmSessions; i++)
+ {
+ if (strcmp(client->olmSessions[i].deviceId, deviceId) == 0)
+ {
+ *outSession = &client->olmSessions[i];
+ return true;
+ }
+ }
+
+ if (client->numOlmSessions < NUM_OLM_SESSIONS)
+ {
+ MatrixOlmSessionInit(
+ &client->olmSessions[client->numOlmSessions],
+ deviceId);
+
+ *outSession = &client->olmSessions[client->numOlmSessions];
+
+ client->numOlmSessions++;
+
+ return true;
+ }
+
+ return false;
+}
+
+// https://spec.matrix.org/v1.6/client-server-api/#put_matrixclientv3sendtodeviceeventtypetxnid
+bool
+MatrixClientSendToDevice(
+ MatrixClient * client,
+ const char * userId,
+ const char * deviceId,
+ const char * message,
+ const char * msgType)
+{
+ static char requestUrl[MAX_URL_LEN];
+ sprintf(requestUrl,
+ TODEVICE_URL, msgType, (int)time(NULL));
+
+ static char eventBuffer[TODEVICE_EVENT_SIZE];
+ snprintf(eventBuffer, TODEVICE_EVENT_SIZE,
+ "{"
+ "\"messages\": {"
+ "\"%s\": {"
+ "\"%s\":%s"
+ "}"
+ "}"
+ "}",
+ userId,
+ deviceId,
+ message);
+
+ static char responseBuffer[ROOMEVENT_RESPONSE_SIZE];
+ bool result =
+ MatrixHttpPut(client,
+ requestUrl,
+ eventBuffer,
+ responseBuffer, ROOMEVENT_RESPONSE_SIZE,
+ true);
+
+ return result;
+}
+
+bool
+MatrixClientSendToDeviceEncrypted(
+ MatrixClient * client,
+ const char * userId,
+ const char * deviceId,
+ const char * message,
+ const char * msgType)
+{
+ // get olm session
+ MatrixOlmSession * olmSession;
+ MatrixClientGetOlmSession(client, deviceId, &olmSession);
+
+ // create event json
+ char deviceKey[DEVICE_KEY_SIZE];
+ MatrixClientGetDeviceKey(client, deviceId, deviceKey, DEVICE_KEY_SIZE);
+ const char * senderKey = client->deviceKey;
+
+ static char eventBuffer[TODEVICE_EVENT_SIZE];
+ sprintf(eventBuffer,
+ "{"
+ "\"type\": \"%s\","
+ "\"content\": \"%s\","
+ "\"sender\": \"%s\","
+ "\"recipient\": \"%s\","
+ "\"recipient_keys\": {"
+ "\"ed25519\": \"%s\""
+ "},"
+ "\"keys\": {"
+ "\"ed25519\": \"%s\""
+ "}"
+ "}",
+ msgType,
+ message,
+ client->userId,
+ userId, // recipient user id
+ deviceKey, // recipient device key
+ client->deviceKey);
+
+ // encrypt
+ static char encryptedBuffer[ENCRYPTED_REQUEST_SIZE];
+ MatrixOlmSessionEncrypt(olmSession,
+ eventBuffer,
+ encryptedBuffer, ENCRYPTED_REQUEST_SIZE);
+
+ static char encryptedEventBuffer[ENCRYPTED_EVENT_SIZE];
+ sprintf(encryptedEventBuffer,
+ "{"
+ "\"algorithm\":\"m.megolm.v1.aes-sha2\","
+ "\"sender_key\":\"%s\","
+ "\"ciphertext\":{"
+ "\"%s\":{"
+ "\"body\":\"%s\","
+ "\"type\":\"%d\""
+ "}"
+ "}"
+ "}",
+ senderKey,
+ deviceKey,
+ encryptedBuffer,
+ olmSession->type);
+
+ // send
+ return MatrixClientSendToDevice(
+ client,
+ userId,
+ deviceId,
+ encryptedEventBuffer,
+ "m.room.encrypted");
+}
+
+bool
+MatrixClientFindDevice(
+ MatrixClient * client,
+ const char * deviceId,
+ MatrixDevice ** outDevice)
+{
+ MatrixClientRequestDeviceKeys(client);
+
+ for (int i = 0; i < client->numDevices; i++)
+ {
+ if (strcmp(client->devices[i].deviceId, deviceId) == 0)
+ {
+ *outDevice = &client->devices[i];
+ return true;
+ }
+ }
+
+ *outDevice = NULL;
+ return false;
+}
+
+bool
+MatrixClientGetDeviceKey(
+ MatrixClient * client,
+ const char * deviceId,
+ char * outDeviceKey, int outDeviceKeyCap)
+{
+ MatrixClientRequestDeviceKeys(client);
+
+ MatrixDevice * device;
+ if (MatrixClientFindDevice(client, deviceId, &device))
+ {
+ strncpy(outDeviceKey, device->deviceKey, outDeviceKeyCap);
+ return true;
+ }
+
+ return false;
+}
+
+// https://spec.matrix.org/v1.6/client-server-api/#post_matrixclientv3keysquery
+bool
+MatrixClientRequestDeviceKeys(
+ MatrixClient * client)
+{
+ char userIdEscaped[USER_ID_SIZE];
+ JsonEscape(client->userId, strlen(client->userId),
+ userIdEscaped, USER_ID_SIZE);
+
+ char request[KEYS_QUERY_REQUEST_SIZE];
+ snprintf(request, KEYS_QUERY_REQUEST_SIZE,
+ "{\"device_keys\":{\"%s\":[]}}", userIdEscaped);
+
+ char responseBuffer[KEYS_QUERY_RESPONSE_SIZE];
+ bool requestResult = MatrixHttpPost(client,
+ KEYS_QUERY_URL,
+ request,
+ responseBuffer, KEYS_QUERY_RESPONSE_SIZE,
+ true);
+
+ if (requestResult)
+ {
+ // query for retrieving device keys for user id
+ char query[JSON_QUERY_SIZE];
+ snprintf(query, JSON_QUERY_SIZE,
+ "$.device_keys.%s", userIdEscaped);
+
+ const char * s;
+ int slen;
+ mjson_find(responseBuffer, strlen(responseBuffer),
+ query, &s, &slen);
+
+ // loop over keys
+
+ int koff, klen, voff, vlen, vtype, off;
+ for (off = 0; (off = mjson_next(s, slen, off, &koff, &klen,
+ &voff, &vlen, &vtype)) != 0; ) {
+ const char * key = s + koff;
+ const char * val = s + voff;
+
+ // set device id, "key" is the JSON key
+ MatrixDevice d;
+ strncpy(d.deviceId, key, klen);
+
+ // look for device key in value
+ char deviceKeyQuery[JSON_QUERY_SIZE];
+ snprintf(deviceKeyQuery, JSON_QUERY_SIZE,
+ "$.keys.curve25519:%.*s", klen, key);
+ mjson_get_string(val, vlen,
+ deviceKeyQuery, d.deviceKey, DEVICE_KEY_SIZE);
+
+ // add device
+ if (client->numDevices < NUM_DEVICES)
+ {
+ client->devices[client->numDevices] = d;
+ client->numDevices++;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
diff --git a/src/matrix.h b/src/matrix.h
index 2e7f6e0..6538e12 100644
--- a/src/matrix.h
+++ b/src/matrix.h
@@ -2,13 +2,15 @@
#define MATRIX__H
#include <stdbool.h>
+#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <olm/olm.h>
-// TODO: fix
+#define USER_ID_SIZE 64
#define SERVER_SIZE 20
#define ACCESS_TOKEN_SIZE 40
#define DEVICE_ID_SIZE 20
@@ -16,16 +18,105 @@
#define REFRESH_TOKEN_SIZE 20
#define MAX_URL_LEN 128
+#define DEVICE_KEY_SIZE 20
+
+#define KEY_SHARE_EVENT_LEN 1024
+
+#define OLM_SESSION_MEMORY_SIZE 3352
+#define OLM_ENCRYPT_RANDOM_SIZE 32
+
+#define MEGOLM_OUTBOUND_SESSION_MEMORY_SIZE 232
+#define MEGOLM_SESSION_ID_SIZE 44
+#define MEGOLM_SESSION_KEY_SIZE 306
+#define MEGOLM_INIT_RANDOM_SIZE (4*32 + 32)
+
+#define NUM_MEGOLM_SESSIONS 10
+#define NUM_OLM_SESSIONS 10
+#define NUM_DEVICES 10
+
+void
+Randomize(uint8_t * random, int randomLen);
+
+bool
+JsonEscape(
+ char * sIn, int sInLen,
+ char * sOut, int sOutCap);
+
+typedef struct MatrixDevice {
+ char deviceId[DEVICE_ID_SIZE];
+ char deviceKey[DEVICE_KEY_SIZE];
+} MatrixDevice;
+
+typedef struct MatrixOlmSession {
+ const char * deviceId;
+
+ int type;
+ OlmSession * session;
+ char memory[OLM_SESSION_MEMORY_SIZE];
+} MatrixOlmSession;
+
+bool
+MatrixOlmSessionInit(
+ MatrixOlmSession * session,
+ const char * deviceId);
+
+bool
+MatrixOlmSessionEncrypt(
+ MatrixOlmSession * session,
+ const char * plaintext,
+ char * outBuffer, int outBufferCap);
+
+
+
+typedef struct MatrixMegolmInSession {
+ OlmInboundGroupSession * session;
+} MatrixMegolmInSession;
+
+typedef struct MatrixMegolmOutSession {
+ const char * roomId;
+
+ OlmOutboundGroupSession * session;
+ char memory[MEGOLM_OUTBOUND_SESSION_MEMORY_SIZE];
+
+ char id[MEGOLM_SESSION_ID_SIZE];
+ char key[MEGOLM_SESSION_KEY_SIZE];
+} MatrixMegolmOutSession;
+
+bool
+MatrixMegolmOutSessionInit(
+ MatrixMegolmOutSession * session,
+ const char * roomId);
+
+bool
+MatrixMegolmOutSessionEncrypt(
+ MatrixMegolmOutSession * session,
+ const char * plaintext,
+ char * outBuffer, int outBufferCap);
+
+
typedef struct MatrixClient {
OlmAccount * olmAccount;
OlmSession * olmSession;
+
+ MatrixMegolmInSession megolmInSessions[NUM_MEGOLM_SESSIONS];
+ int numMegolmInSessions;
+ MatrixMegolmOutSession megolmOutSessions[NUM_MEGOLM_SESSIONS];
+ int numMegolmOutSessions;
+ MatrixOlmSession olmSessions[NUM_OLM_SESSIONS];
+ int numOlmSessions;
- char server[SERVER_SIZE+1];
- char accessTokenBuffer[ACCESS_TOKEN_SIZE];
- char deviceIdBuffer[DEVICE_ID_SIZE];
- char expireMsBuffer[EXPIRE_MS_SIZE];
- char refreshTokenBuffer[REFRESH_TOKEN_SIZE];
+ MatrixDevice devices[NUM_DEVICES];
+ int numDevices;
+
+ char deviceKey[DEVICE_KEY_SIZE];
+
+ char userId[USER_ID_SIZE];
+ char server[SERVER_SIZE];
+ char accessToken[ACCESS_TOKEN_SIZE];
+ char deviceId[DEVICE_ID_SIZE];
+ char expireMs[EXPIRE_MS_SIZE];
+ char refreshToken[REFRESH_TOKEN_SIZE];
void * httpUserData;
} MatrixClient;
@@ -53,6 +144,76 @@ MatrixClientSendEvent(
const char * roomId,
const char * msgType,
const char * msgBody);
+
+bool
+MatrixClientSendEventEncrypted(
+ MatrixClient * client,
+ const char * roomId,
+ const char * msgType,
+ const char * msgBody);
+
+bool
+MatrixClientSync(
+ MatrixClient * client,
+ char * outSyncBuffer, int outSyncCap);
+
+bool
+MatrixClientShareMegolmOutSession(
+ MatrixClient * client,
+ const char * deviceId,
+ MatrixMegolmOutSession * session);
+
+bool
+MatrixClientGetMegolmOutSession(
+ MatrixClient * client,
+ const char * roomId,
+ MatrixMegolmOutSession ** outSession);
+
+bool
+MatrixClientSetMegolmOutSession(
+ MatrixClient * client,
+ const char * roomId,
+ MatrixMegolmOutSession session);
+
+bool
+MatrixClientGetOlmSession(
+ MatrixClient * client,
+ const char * deviceId,
+ MatrixOlmSession ** outSession);
+
+bool
+MatrixClientSendToDevice(
+ MatrixClient * client,
+ const char * userId,
+ const char * deviceId,
+ const char * message,
+ const char * msgType);
+
+bool
+MatrixClientSendToDeviceEncrypted(
+ MatrixClient * client,
+ const char * userId,
+ const char * deviceId,
+ const char * message,
+ const char * msgType);
+
+bool
+MatrixClientGetDeviceKey(
+ MatrixClient * client,
+ const char * deviceId,
+ char * outDeviceKey, int outDeviceKeyCap);
+
+bool
+MatrixClientGetDeviceKey(
+ MatrixClient * client,
+ const char * deviceId,
+ char * outDeviceKey, int outDeviceKeyCap);
+
+bool
+MatrixClientRequestDeviceKeys(
+ MatrixClient * client);
+
+
bool
MatrixHttpInit(
diff --git a/src/matrix_http_mongoose.c b/src/matrix_http_mongoose.c
index 8d575e5..020b4c8 100644
--- a/src/matrix_http_mongoose.c
+++ b/src/matrix_http_mongoose.c
@@ -1,4 +1,5 @@
#include "matrix.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -35,7 +36,8 @@ MatrixHttpCallback(
// If s_url is https://, tell client connection to use TLS
if (mg_url_is_ssl(client->server))
{
- struct mg_tls_opts opts = {.srvname = host};
+ struct mg_tls_opts opts;
+ opts.srvname = host;
mg_tls_init(c, &opts);
}
@@ -48,10 +50,13 @@ MatrixHttpCallback(
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
// memcpy_s(client->data, 1024, hm->message.ptr, hm->message.len);
// client->dataLen = hm->message.len;
- memcpy_s(conn->data, conn->dataCap, hm->body.ptr, hm->body.len);
+ memcpy(conn->data, hm->body.ptr, hm->body.len);
+ // memcpy_s(conn->data, conn->dataCap, hm->body.ptr, hm->body.len);
conn->data[hm->body.len] = '\0';
conn->dataLen = hm->body.len;
conn->dataReceived = true;
+
+ printf("received[%d]:\n%.*s\n", conn->dataLen, conn->dataLen, conn->data);
}
}
@@ -100,10 +105,14 @@ MatrixHttpGet(
struct mg_str host = mg_url_host(client->server);
- static char authorizationHeader[AUTHORIZATION_HEADER_LEN] = "\0";
+ static char authorizationHeader[AUTHORIZATION_HEADER_LEN];
if (authenticated)
- sprintf_s(authorizationHeader, AUTHORIZATION_HEADER_LEN,
- "Authorization: Bearer %s\r\n", client->accessTokenBuffer);
+ sprintf(authorizationHeader,
+ "Authorization: Bearer %s\r\n", client->accessToken);
+ // sprintf_s(authorizationHeader, AUTHORIZATION_HEADER_LEN,
+ // "Authorization: Bearer %s\r\n", client->accessToken);
+ else
+ authorizationHeader[0] = '\0';
mg_printf(conn->connection,
"GET %s HTTP/1.1\r\n"
@@ -137,10 +146,12 @@ MatrixHttpPost(
struct mg_str host = mg_url_host(client->server);
- static char authorizationHeader[AUTHORIZATION_HEADER_LEN] = "\0";
+ static char authorizationHeader[AUTHORIZATION_HEADER_LEN];
if (authenticated)
- sprintf_s(authorizationHeader, AUTHORIZATION_HEADER_LEN,
- "Authorization: Bearer %s\r\n", client->accessTokenBuffer);
+ sprintf(authorizationHeader,
+ "Authorization: Bearer %s\r\n", client->accessToken);
+ else
+ authorizationHeader[0] = '\0';
mg_printf(conn->connection,
"POST %s HTTP/1.0\r\n"
@@ -182,8 +193,8 @@ MatrixHttpPut(
static char authorizationHeader[AUTHORIZATION_HEADER_LEN];
if (authenticated)
- sprintf_s(authorizationHeader, AUTHORIZATION_HEADER_LEN,
- "Authorization: Bearer %s\r\n", client->accessTokenBuffer);
+ sprintf(authorizationHeader,
+ "Authorization: Bearer %s\r\n", client->accessToken);
else
authorizationHeader[0] = '\0';