8 #include <esp_random.h>
\r
11 #define STATIC static
\r
13 #define LOGIN_REQUEST_SIZE 1024
\r
14 #define LOGIN_RESPONSE_SIZE 1024
\r
15 #define LOGIN_URL "/_matrix/client/v3/login"
\r
17 #define ENCRYPTED_REQUEST_SIZE (1024*5)
\r
18 STATIC char g_EncryptedRequestBuffer[ENCRYPTED_REQUEST_SIZE];
\r
19 #define ENCRYPTED_EVENT_SIZE (1024*10)
\r
20 STATIC char g_EncryptedEventBuffer[ENCRYPTED_EVENT_SIZE];
\r
21 #define ROOM_SEND_REQUEST_SIZE 256
\r
22 #define ROOM_SEND_RESPONSE_SIZE 1024
\r
23 #define ROOM_SEND_URL "/_matrix/client/v3/rooms/%s/send/%s/%d"
\r
25 #define ROOMKEY_REQUEST_SIZE (1024*4)
\r
27 #define TODEVICE_EVENT_SIZE (1024*5)
\r
28 STATIC char g_TodeviceEventBuffer[TODEVICE_EVENT_SIZE];
\r
29 #define TODEVICE_URL "/_matrix/client/v3/sendToDevice/%s/%d"
\r
31 #define KEYS_QUERY_URL "/_matrix/client/v3/keys/query"
\r
32 #define KEYS_QUERY_REQUEST_SIZE 256
\r
33 #define KEYS_QUERY_RESPONSE_SIZE (1024*5)
\r
35 #define KEYS_UPLOAD_URL "/_matrix/client/v3/keys/upload"
\r
36 #define KEYS_UPLOAD_REQUEST_SIZE 1024*4
\r
37 STATIC char g_KeysUploadRequestBuffer[KEYS_UPLOAD_REQUEST_SIZE];
\r
38 #define KEYS_UPLOAD_REQUEST_SIGNED_SIZE 2048*4
\r
39 STATIC char g_KeysUploadRequestSignedBuffer[KEYS_UPLOAD_REQUEST_SIGNED_SIZE];
\r
40 #define KEYS_UPLOAD_RESPONSE_SIZE 2048
\r
42 #define KEYS_CLAIM_URL "/_matrix/client/v3/keys/claim"
\r
43 #define KEYS_CLAIM_REQUEST_SIZE 1024
\r
44 #define KEYS_CLAIM_RESPONSE_SIZE 1024
\r
46 #define SYNC_TIMEOUT 5000
\r
48 #define JSON_QUERY_SIZE 128
\r
49 #define JSON_MAX_INDICES 100
\r
50 #define JSON_MAX_ENTRY_SIZE 1024
\r
52 #define MAX(a,b) ((a) > (b) ? (a) : (b))
\r
53 #define MIN(a,b) ((a) < (b) ? (a) : (b))
\r
62 for (int i = 0; i < randomLen; i++)
\r
64 random[i] = esp_random() % 256;
\r
69 STATIC bool first = true;
\r
70 if (first) { srand(time(0)); first = false; }
\r
72 for (int i = 0; i < randomLen; i++)
\r
74 random[i] = rand() % 256;
\r
82 const char * sIn, int sInLen,
\r
83 char * sOut, int sOutCap)
\r
87 for (int i = 0; i < sInLen; i++)
\r
92 if (sIn[i] == '.' ||
\r
96 sOut[sOutIndex++] = '\\';
\r
98 sOut[sOutIndex++] = sIn[i];
\r
101 if (sOutIndex < sOutCap)
\r
102 sOut[sOutIndex] = '\0';
\r
109 const char * sIn, int sInLen,
\r
110 char * sOut, int sOutCap)
\r
112 snprintf(sOut, sOutCap, "{}");
\r
114 int koff, klen, voff, vlen, vtype, off;
\r
121 struct Key keys[JSON_MAX_INDICES];
\r
124 for (off = 0; (off = mjson_next(sIn, sInLen, off, &koff, &klen, &voff, &vlen, &vtype)) != 0; ) {
\r
125 keys[numKeys].ptr = sIn + koff;
\r
126 keys[numKeys].len = klen;
\r
130 for (int i = 0; i < numKeys; i++) {
\r
131 for (int j = i; j < numKeys; j++) {
\r
136 MIN(keys[i].len, keys[j].len)
\r
139 struct Key k = keys[i];
\r
146 for (int i = 0; i < numKeys; i++) {
\r
147 char jp[JSON_QUERY_SIZE];
\r
148 snprintf(jp, JSON_QUERY_SIZE, "$.%.*s", keys[i].len-2, keys[i].ptr+1);
\r
150 const char * valPtr;
\r
152 mjson_find(sIn, sInLen, jp, &valPtr, &valLen);
\r
154 STATIC char newEntry[JSON_MAX_ENTRY_SIZE];
\r
155 snprintf(newEntry, JSON_MAX_ENTRY_SIZE, "{%.*s:%.*s}", keys[i].len, keys[i].ptr, valLen, valPtr);
\r
157 char * buffer = strdup(sOut);
\r
159 struct mjson_fixedbuf fb = { sOut, sOutCap, 0 };
\r
160 mjson_merge(buffer, strlen(buffer), newEntry, strlen(newEntry), mjson_print_fixed_buf, &fb);
\r
165 // TODO: recursively sort entries
\r
171 MatrixClient * client,
\r
172 const char * sIn, int sInLen,
\r
173 char * sOut, int sOutCap)
\r
175 STATIC char signature[OLM_SIGNATURE_SIZE];
\r
177 olm_account_sign(client->olmAccount.account,
\r
179 signature, OLM_SIGNATURE_SIZE);
\r
181 int signatureLen = res;
\r
183 STATIC char thisSigningKey[SIGNING_KEY_SIZE];
\r
184 MatrixOlmAccountGetSigningKey(&client->olmAccount, thisSigningKey, SIGNING_KEY_SIZE);
\r
186 STATIC char signatureJson[JSON_SIGNATURE_SIZE];
\r
187 int signatureJsonLen =
\r
188 mjson_snprintf(signatureJson, JSON_SIGNATURE_SIZE,
\r
192 "\"ed25519:%s\":\"%.*s\""
\r
199 signatureLen, signature);
\r
201 struct mjson_fixedbuf result = { sOut, sOutCap, 0 };
\r
204 signatureJson, signatureJsonLen,
\r
205 mjson_print_fixed_buf,
\r
213 MatrixOlmAccountInit(
\r
214 MatrixOlmAccount * account)
\r
216 account->account = olm_account(account->memory);
\r
218 STATIC uint8_t random[OLM_ACCOUNT_RANDOM_SIZE];
\r
219 Randomize(random, OLM_ACCOUNT_RANDOM_SIZE);
\r
221 size_t res = olm_create_account(
\r
224 OLM_ACCOUNT_RANDOM_SIZE);
\r
226 return res != olm_error();
\r
230 MatrixOlmAccountUnpickle(
\r
231 MatrixOlmAccount * account,
\r
232 void * pickled, int pickledLen,
\r
233 const void * key, int keyLen)
\r
236 res = olm_unpickle_account(account->account,
\r
238 pickled, pickledLen);
\r
239 if (res == olm_error()) {
\r
240 printf("error unpickling olm account:%s\n",
\r
241 olm_account_last_error(account->account));
\r
243 return res != olm_error();
\r
247 MatrixOlmAccountGetDeviceKey(
\r
248 MatrixOlmAccount * account,
\r
249 char * key, int keyCap)
\r
251 STATIC char deviceKeysJson[OLM_IDENTITY_KEYS_JSON_SIZE];
\r
253 olm_account_identity_keys(account->account,
\r
254 deviceKeysJson, OLM_IDENTITY_KEYS_JSON_SIZE);
\r
255 mjson_get_string(deviceKeysJson, res,
\r
262 MatrixOlmAccountGetSigningKey(
\r
263 MatrixOlmAccount * account,
\r
264 char * key, int keyCap)
\r
266 STATIC char deviceKeysJson[OLM_IDENTITY_KEYS_JSON_SIZE];
\r
268 olm_account_identity_keys(account->account,
\r
269 deviceKeysJson, OLM_IDENTITY_KEYS_JSON_SIZE);
\r
270 mjson_get_string(deviceKeysJson, res,
\r
277 MatrixOlmSessionFrom(
\r
278 MatrixOlmSession * session,
\r
279 OlmAccount * olmAccount,
\r
280 const char * deviceId,
\r
281 const char * deviceKey,
\r
282 const char * encrypted)
\r
284 memset(session, 0, sizeof(MatrixOlmSession));
\r
286 session->deviceId = deviceId;
\r
289 olm_session(session->memory);
\r
291 char * encryptedCopy = strdup(encrypted);
\r
294 olm_create_inbound_session_from(session->session, olmAccount,
\r
295 deviceKey, strlen(deviceKey),
\r
296 encryptedCopy, strlen(encryptedCopy));
\r
298 if (res == olm_error()) {
\r
299 printf("error olm:%s\n", olm_session_last_error(session->session));
\r
302 return res != olm_error();
\r
306 MatrixOlmSessionTo(
\r
307 MatrixOlmSession * session,
\r
308 OlmAccount * olmAccount,
\r
309 const char * deviceId,
\r
310 const char * deviceKey,
\r
311 const char * deviceOnetimeKey)
\r
313 memset(session, 0, sizeof(MatrixOlmSession));
\r
315 session->deviceId = deviceId;
\r
318 olm_session(session->memory);
\r
320 STATIC uint8_t random[OLM_OUTBOUND_SESSION_RANDOM_SIZE];
\r
321 Randomize(random, OLM_OUTBOUND_SESSION_RANDOM_SIZE);
\r
324 olm_create_outbound_session(session->session,
\r
326 deviceKey, strlen(deviceKey),
\r
327 deviceOnetimeKey, strlen(deviceOnetimeKey),
\r
328 random, OLM_OUTBOUND_SESSION_RANDOM_SIZE);
\r
330 if (res == olm_error()) {
\r
331 printf("error olm:%s\n", olm_session_last_error(session->session));
\r
334 return res != olm_error();
\r
338 MatrixOlmSessionUnpickle(
\r
339 MatrixOlmSession * session,
\r
340 const char * deviceId,
\r
341 void * pickled, int pickledLen,
\r
342 const void * key, int keyLen)
\r
344 memset(session, 0, sizeof(MatrixOlmSession));
\r
346 session->deviceId = deviceId;
\r
349 olm_session(session->memory);
\r
352 res = olm_unpickle_session(session->session,
\r
354 pickled, pickledLen);
\r
356 if (res == olm_error()) {
\r
357 printf("error unpickling olm session:%s\n", olm_session_last_error(session->session));
\r
360 return res != olm_error();
\r
364 MatrixOlmSessionEncrypt(
\r
365 MatrixOlmSession * session,
\r
366 const char * plaintext,
\r
367 char * outBuffer, int outBufferCap)
\r
369 STATIC uint8_t random[OLM_ENCRYPT_RANDOM_SIZE];
\r
370 Randomize(random, OLM_ENCRYPT_RANDOM_SIZE);
\r
372 size_t res = olm_encrypt(session->session,
\r
373 plaintext, strlen(plaintext),
\r
374 random, OLM_ENCRYPT_RANDOM_SIZE,
\r
375 outBuffer, outBufferCap);
\r
377 return res != olm_error();
\r
381 MatrixOlmSessionDecrypt(
\r
382 MatrixOlmSession * session,
\r
383 size_t messageType,
\r
385 char * outBuffer, int outBufferCap)
\r
387 STATIC uint8_t random[OLM_ENCRYPT_RANDOM_SIZE];
\r
388 Randomize(random, OLM_ENCRYPT_RANDOM_SIZE);
\r
391 olm_decrypt(session->session,
\r
393 encrypted, strlen(encrypted),
\r
394 outBuffer, outBufferCap);
\r
396 if (res != olm_error() && res < outBufferCap)
\r
397 outBuffer[res] = '\0';
\r
399 return res != olm_error();
\r
403 MatrixMegolmInSessionInit(
\r
404 MatrixMegolmInSession * session,
\r
405 const char * roomId,
\r
406 const char * sessionId,
\r
407 const char * sessionKey, int sessionKeyLen)
\r
409 memset(session, 0, sizeof(MatrixMegolmInSession));
\r
411 strncpy(session->roomId, roomId, sizeof(session->roomId));
\r
412 strncpy(session->id, sessionId, sizeof(session->id));
\r
413 strncpy(session->key, sessionKey, sizeof(session->key));
\r
416 olm_inbound_group_session(session->memory);
\r
419 olm_init_inbound_group_session(
\r
420 // olm_import_inbound_group_session(
\r
422 (const uint8_t *)sessionKey, sessionKeyLen);
\r
423 if (res == olm_error()) {
\r
424 printf("Error initializing Megolm session: %s\n", olm_inbound_group_session_last_error(session->session));
\r
427 return res != olm_error();
\r
431 MatrixMegolmInSessionDecrypt(
\r
432 MatrixMegolmInSession * session,
\r
433 const char * encrypted, int encryptedLen,
\r
434 char * outDecrypted, int outDecryptedCap)
\r
436 // uint8_t buffer[1024];
\r
437 // memcpy(buffer, encrypted, encryptedLen);
\r
439 uint32_t megolmInMessageIndex;
\r
442 olm_group_decrypt(session->session,
\r
443 (uint8_t *)encrypted, encryptedLen,
\r
444 (uint8_t *)outDecrypted, outDecryptedCap,
\r
445 &megolmInMessageIndex);
\r
447 printf("message index: %d\n", (int)megolmInMessageIndex);
\r
449 if (res == olm_error()) {
\r
450 printf("error decrypting megolm message: %s\n", olm_inbound_group_session_last_error(session->session));
\r
453 printf("decrypted len: %d\n", res);
\r
459 // https://matrix.org/docs/guides/end-to-end-encryption-implementation-guide#starting-a-megolm-session
\r
461 MatrixMegolmOutSessionInit(
\r
462 MatrixMegolmOutSession * session,
\r
463 const char * roomId)
\r
465 memset(session, 0, sizeof(MatrixMegolmOutSession));
\r
467 STATIC uint8_t random[MEGOLM_INIT_RANDOM_SIZE];
\r
468 Randomize(random, MEGOLM_INIT_RANDOM_SIZE);
\r
470 strncpy(session->roomId, roomId, ROOM_ID_SIZE);
\r
473 olm_outbound_group_session(session->memory);
\r
475 olm_init_outbound_group_session(
\r
478 MEGOLM_INIT_RANDOM_SIZE);
\r
480 olm_outbound_group_session_id(session->session,
\r
481 (uint8_t *)session->id,
\r
482 MEGOLM_SESSION_ID_SIZE);
\r
484 olm_outbound_group_session_key(session->session,
\r
485 (uint8_t *)session->key,
\r
486 MEGOLM_SESSION_KEY_SIZE);
\r
492 MatrixMegolmOutSessionEncrypt(
\r
493 MatrixMegolmOutSession * session,
\r
494 const char * plaintext,
\r
495 char * outBuffer, int outBufferCap)
\r
497 size_t res = olm_group_encrypt(session->session,
\r
498 (uint8_t *)plaintext, strlen(plaintext),
\r
499 (uint8_t *)outBuffer, outBufferCap);
\r
501 return res != olm_error();
\r
505 MatrixMegolmOutSessionSave(
\r
506 MatrixMegolmOutSession * session,
\r
507 const char * filename,
\r
510 FILE * f = fopen(filename, "w");
\r
512 size_t roomIdLen = strlen(session->roomId);
\r
513 fwrite(&roomIdLen, sizeof(size_t), 1, f);
\r
514 fwrite(session->roomId, 1, roomIdLen, f);
\r
516 size_t pickleBufferLen =
\r
517 olm_pickle_outbound_group_session_length(
\r
519 void * pickleBuffer = malloc(pickleBufferLen);
\r
521 olm_pickle_outbound_group_session(
\r
524 pickleBuffer, pickleBufferLen);
\r
526 fwrite(&pickleBufferLen, sizeof(size_t), 1, f);
\r
527 fwrite(pickleBuffer, 1, pickleBufferLen, f);
\r
528 free(pickleBuffer);
\r
536 MatrixMegolmOutSessionLoad(
\r
537 MatrixMegolmOutSession * session,
\r
538 const char * filename,
\r
541 FILE * f = fopen(filename, "r");
\r
544 fread(&roomIdLen, sizeof(size_t), 1, f);
\r
545 fread(session->roomId, 1, roomIdLen, f);
\r
546 for (int i = roomIdLen; i < ROOM_ID_SIZE; i++)
\r
547 session->roomId[i] = '\0';
\r
549 size_t pickleBufferLen;
\r
550 fread(&pickleBufferLen, sizeof(size_t), 1, f);
\r
552 void * pickleBuffer = malloc(pickleBufferLen);
\r
553 fread(pickleBuffer, 1, pickleBufferLen, f);
\r
555 olm_unpickle_outbound_group_session(
\r
558 pickleBuffer, pickleBufferLen);
\r
560 free(pickleBuffer);
\r
562 olm_outbound_group_session_id(session->session, (uint8_t *)session->id, MEGOLM_SESSION_ID_SIZE);
\r
563 olm_outbound_group_session_key(session->session, (uint8_t *)session->key, MEGOLM_SESSION_KEY_SIZE);
\r
574 MatrixClient * client)
\r
576 memset(client, 0, sizeof(MatrixClient));
\r
578 // init olm account
\r
579 MatrixOlmAccountInit(&client->olmAccount);
\r
586 MatrixClient * client,
\r
587 const char * filename)
\r
589 FILE * f = fopen(filename, "w");
\r
592 char thisDeviceKey[DEVICE_KEY_SIZE];
\r
593 MatrixOlmAccountGetDeviceKey(&client->olmAccount, thisDeviceKey, DEVICE_KEY_SIZE);
\r
594 char thisSigningKey[DEVICE_KEY_SIZE];
\r
595 MatrixOlmAccountGetSigningKey(&client->olmAccount, thisSigningKey, DEVICE_KEY_SIZE);
\r
598 fwrite(thisDeviceKey, 1, DEVICE_KEY_SIZE, f);
\r
599 fwrite(thisSigningKey, 1, DEVICE_KEY_SIZE, f);
\r
600 fwrite(client->userId, 1, USER_ID_SIZE, f);
\r
601 fwrite(client->accessToken, 1, ACCESS_TOKEN_SIZE, f);
\r
602 fwrite(client->deviceId, 1, DEVICE_ID_SIZE, f);
\r
603 fwrite(client->expireMs, 1, EXPIRE_MS_SIZE, f);
\r
604 fwrite(client->refreshToken, 1, REFRESH_TOKEN_SIZE, f);
\r
606 fwrite(&client->numDevices, sizeof(int), 1, f);
\r
607 for (int i = 0; i < client->numDevices; i++) {
\r
608 fwrite(client->devices[i].deviceId, 1, DEVICE_ID_SIZE, f);
\r
609 fwrite(client->devices[i].deviceKey, 1, DEVICE_KEY_SIZE, f);
\r
618 MatrixClient * client,
\r
619 const char * filename)
\r
621 FILE * f = fopen(filename, "r");
\r
624 char thisDeviceKey[DEVICE_KEY_SIZE];
\r
625 MatrixOlmAccountGetDeviceKey(&client->olmAccount, thisDeviceKey, DEVICE_KEY_SIZE);
\r
626 char thisSigningKey[DEVICE_KEY_SIZE];
\r
627 MatrixOlmAccountGetSigningKey(&client->olmAccount, thisSigningKey, DEVICE_KEY_SIZE);
\r
630 fread(thisDeviceKey, 1, DEVICE_KEY_SIZE, f);
\r
631 fread(thisSigningKey, 1, DEVICE_KEY_SIZE, f);
\r
632 fread(client->userId, 1, USER_ID_SIZE, f);
\r
633 fread(client->accessToken, 1, ACCESS_TOKEN_SIZE, f);
\r
634 fread(client->deviceId, 1, DEVICE_ID_SIZE, f);
\r
635 fread(client->expireMs, 1, EXPIRE_MS_SIZE, f);
\r
636 fread(client->refreshToken, 1, REFRESH_TOKEN_SIZE, f);
\r
638 fread(&client->numDevices, sizeof(int), 1, f);
\r
639 for (int i = 0; i < client->numDevices; i++) {
\r
640 fread(client->devices[i].deviceId, 1, DEVICE_ID_SIZE, f);
\r
641 fread(client->devices[i].deviceKey, 1, DEVICE_KEY_SIZE, f);
\r
649 MatrixClientSetAccessToken(
\r
650 MatrixClient * client,
\r
651 const char * accessToken)
\r
653 for (int i = 0; i < ACCESS_TOKEN_SIZE-1; i++)
\r
654 client->accessToken[i] = accessToken[i];
\r
655 client->accessToken[ACCESS_TOKEN_SIZE-1] = '\0';
\r
661 MatrixClientSetDeviceId(
\r
662 MatrixClient * client,
\r
663 const char * deviceId)
\r
665 for (int i = 0; i < DEVICE_ID_SIZE-1; i++)
\r
666 client->deviceId[i] = deviceId[i];
\r
667 client->deviceId[DEVICE_ID_SIZE-1] = '\0';
\r
673 MatrixClientSetUserId(
\r
674 MatrixClient * client,
\r
675 const char * userId)
\r
677 for (int i = 0; i < USER_ID_SIZE-1; i++)
\r
678 client->userId[i] = userId[i];
\r
679 client->userId[USER_ID_SIZE-1] = '\0';
\r
685 MatrixClientGenerateOnetimeKeys(
\r
686 MatrixClient * client,
\r
689 STATIC uint8_t random[OLM_ONETIME_KEYS_RANDOM_SIZE];
\r
690 Randomize(random, OLM_ONETIME_KEYS_RANDOM_SIZE);
\r
693 olm_account_generate_one_time_keys(client->olmAccount.account,
\r
694 numberOfKeys, random, OLM_ONETIME_KEYS_RANDOM_SIZE);
\r
696 return res != olm_error();
\r
699 // https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv3keysupload
\r
701 MatrixClientUploadOnetimeKeys(
\r
702 MatrixClient * client)
\r
704 mjson_snprintf(g_KeysUploadRequestBuffer, KEYS_UPLOAD_REQUEST_SIZE,
\r
707 STATIC char onetimeKeysBuffer[1024];
\r
708 olm_account_one_time_keys(client->olmAccount.account,
\r
709 onetimeKeysBuffer, 1024);
\r
713 mjson_find(onetimeKeysBuffer, strlen(onetimeKeysBuffer), "$.curve25519", &keys, &keysLen);
\r
715 int koff, klen, voff, vlen, vtype, off = 0;
\r
716 while ((off = mjson_next(keys, keysLen, off, &koff, &klen, &voff, &vlen, &vtype)) != 0) {
\r
717 STATIC char keyJson[JSON_ONETIME_KEY_SIZE];
\r
720 snprintf(keyJson, JSON_ONETIME_KEY_SIZE,
\r
721 "{\"key\":\"%.*s\"}",
\r
722 vlen-2, keys + voff+1);
\r
724 STATIC char keyJsonSigned[JSON_ONETIME_KEY_SIGNED_SIZE];
\r
727 keyJson, keyJsonLen,
\r
728 keyJsonSigned, JSON_ONETIME_KEY_SIGNED_SIZE);
\r
730 mjson_snprintf(g_KeysUploadRequestBuffer+strlen(g_KeysUploadRequestBuffer), KEYS_UPLOAD_REQUEST_SIZE-strlen(g_KeysUploadRequestBuffer),
\r
731 "\"signed_curve25519:%.*s\":%s,",
\r
732 klen-2, keys + koff+1,
\r
736 if (g_KeysUploadRequestBuffer[strlen(g_KeysUploadRequestBuffer)-1] == ',')
\r
737 g_KeysUploadRequestBuffer[strlen(g_KeysUploadRequestBuffer)-1] = '\0';
\r
739 mjson_snprintf(g_KeysUploadRequestBuffer+strlen(g_KeysUploadRequestBuffer), KEYS_UPLOAD_REQUEST_SIZE-strlen(g_KeysUploadRequestBuffer),
\r
742 // STATIC char onetimeKeysSignedBuffer[KEYS_UPLOAD_REQUEST_SIGNED_SIZE];
\r
743 // JsonSign(client,
\r
744 // g_KeysUploadRequestBuffer, strlen(g_KeysUploadRequestBuffer),
\r
745 // onetimeKeysSignedBuffer, KEYS_UPLOAD_REQUEST_SIZE);
\r
747 // STATIC char finalEvent[KEYS_UPLOAD_REQUEST_SIGNED_SIZE];
\r
748 // snprintf(finalEvent, KEYS_UPLOAD_REQUEST_SIGNED_SIZE,
\r
749 // "{\"one_time_keys\":%s}", onetimeKeysSignedBuffer);
\r
750 snprintf(g_KeysUploadRequestSignedBuffer, KEYS_UPLOAD_REQUEST_SIGNED_SIZE,
\r
751 "{\"one_time_keys\":%s}", g_KeysUploadRequestBuffer);
\r
753 STATIC char responseBuffer[KEYS_UPLOAD_RESPONSE_SIZE];
\r
754 MatrixHttpPost(client->hc,
\r
756 g_KeysUploadRequestSignedBuffer,
\r
757 responseBuffer, KEYS_UPLOAD_RESPONSE_SIZE,
\r
763 // https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv3keysupload
\r
765 MatrixClientUploadDeviceKey(
\r
766 MatrixClient * client)
\r
768 char thisDeviceKey[DEVICE_KEY_SIZE];
\r
769 MatrixOlmAccountGetDeviceKey(&client->olmAccount, thisDeviceKey, DEVICE_KEY_SIZE);
\r
770 char thisSigningKey[DEVICE_KEY_SIZE];
\r
771 MatrixOlmAccountGetSigningKey(&client->olmAccount, thisSigningKey, DEVICE_KEY_SIZE);
\r
773 int deviceKeysBufferLen =
\r
774 mjson_snprintf(g_KeysUploadRequestBuffer, KEYS_UPLOAD_REQUEST_SIZE,
\r
776 "\"algorithms\":[\"m.olm.v1.curve25519-aes-sha2\",\"m.megolm.v1.aes-sha2\"],"
\r
777 "\"device_id\":\"%s\","
\r
779 "\"curve25519:%s\":\"%s\","
\r
780 "\"ed25519:%s\":\"%s\""
\r
782 "\"user_id\":\"%s\""
\r
785 client->deviceId, thisDeviceKey,
\r
786 client->deviceId, thisSigningKey,
\r
790 g_KeysUploadRequestBuffer, deviceKeysBufferLen,
\r
791 g_KeysUploadRequestSignedBuffer, KEYS_UPLOAD_REQUEST_SIZE);
\r
793 STATIC char finalEvent[KEYS_UPLOAD_REQUEST_SIGNED_SIZE+30];
\r
794 snprintf(finalEvent, KEYS_UPLOAD_REQUEST_SIGNED_SIZE+30,
\r
795 "{\"device_keys\":%s}", g_KeysUploadRequestSignedBuffer);
\r
797 STATIC char responseBuffer[KEYS_UPLOAD_RESPONSE_SIZE];
\r
798 MatrixHttpPost(client->hc,
\r
801 responseBuffer, KEYS_UPLOAD_RESPONSE_SIZE,
\r
807 // https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv3keysclaim
\r
809 MatrixClientClaimOnetimeKey(
\r
810 MatrixClient * client,
\r
811 const char * userId,
\r
812 const char * deviceId,
\r
813 char * outOnetimeKey, int outOnetimeKeyCap)
\r
815 STATIC char requestBuffer[KEYS_CLAIM_REQUEST_SIZE];
\r
816 mjson_snprintf(requestBuffer, KEYS_CLAIM_REQUEST_SIZE,
\r
818 "\"one_time_keys\":{"
\r
820 "\"%s\":\"signed_curve25519\""
\r
823 "\"timeout\":10000"
\r
828 STATIC char responseBuffer[KEYS_CLAIM_RESPONSE_SIZE];
\r
829 MatrixHttpPost(client->hc,
\r
832 responseBuffer, KEYS_CLAIM_RESPONSE_SIZE,
\r
835 STATIC char userIdEscaped[USER_ID_SIZE];
\r
836 JsonEscape(userId, strlen(userId),
\r
837 userIdEscaped, USER_ID_SIZE);
\r
839 STATIC char query[JSON_QUERY_SIZE];
\r
840 snprintf(query, JSON_QUERY_SIZE,
\r
841 "$.one_time_keys.%s.%s",
\r
845 const char * keyObject;
\r
847 mjson_find(responseBuffer, strlen(responseBuffer),
\r
849 &keyObject, &keyObjectSize);
\r
851 int koff, klen, voff, vlen, vtype;
\r
852 mjson_next(keyObject, keyObjectSize, 0,
\r
853 &koff, &klen, &voff, &vlen, &vtype);
\r
855 mjson_get_string(keyObject + voff, vlen,
\r
856 "$.key", outOnetimeKey, outOnetimeKeyCap);
\r
858 // TODO:verify signature
\r
863 // https://spec.matrix.org/v1.6/client-server-api/#post_matrixclientv3login
\r
865 MatrixClientLoginPassword(
\r
866 MatrixClient * client,
\r
867 const char * username,
\r
868 const char * password,
\r
869 const char * displayName)
\r
871 STATIC char requestBuffer[LOGIN_REQUEST_SIZE];
\r
873 mjson_snprintf(requestBuffer, LOGIN_REQUEST_SIZE,
\r
875 "\"type\":\"m.login.password\","
\r
877 "\"type\":\"m.id.user\","
\r
880 "\"password\":\"%s\","
\r
881 "\"initial_device_display_name\":\"%s\""
\r
887 STATIC char responseBuffer[LOGIN_RESPONSE_SIZE];
\r
889 MatrixHttpPost(client->hc,
\r
892 responseBuffer, LOGIN_RESPONSE_SIZE,
\r
898 int responseLen = strlen(responseBuffer);
\r
900 mjson_get_string(responseBuffer, responseLen,
\r
902 client->accessToken, ACCESS_TOKEN_SIZE);
\r
903 mjson_get_string(responseBuffer, responseLen,
\r
905 client->deviceId, DEVICE_ID_SIZE);
\r
906 mjson_get_string(responseBuffer, responseLen,
\r
908 client->expireMs, EXPIRE_MS_SIZE);
\r
909 mjson_get_string(responseBuffer, responseLen,
\r
911 client->refreshToken, REFRESH_TOKEN_SIZE);
\r
913 MatrixHttpSetAccessToken(client->hc, client->accessToken);
\r
918 // https://spec.matrix.org/v1.6/client-server-api/#put_matrixclientv3roomsroomidsendeventtypetxnid
\r
920 MatrixClientSendEvent(
\r
921 MatrixClient * client,
\r
922 const char * roomId,
\r
923 const char * msgType,
\r
924 const char * msgBody)
\r
926 STATIC char requestUrl[MAX_URL_LEN];
\r
927 sprintf(requestUrl,
\r
928 ROOM_SEND_URL, roomId, msgType, (int)time(NULL));
\r
930 STATIC char responseBuffer[ROOM_SEND_RESPONSE_SIZE];
\r
932 MatrixHttpPut(client->hc,
\r
935 responseBuffer, ROOM_SEND_RESPONSE_SIZE,
\r
941 // https://spec.matrix.org/v1.6/client-server-api/#mroomencrypted
\r
942 // https://matrix.org/docs/guides/end-to-end-encryption-implementation-guide#sending-an-encrypted-message-event
\r
944 MatrixClientSendEventEncrypted(
\r
945 MatrixClient * client,
\r
946 const char * roomId,
\r
947 const char * msgType,
\r
948 const char * msgBody)
\r
951 STATIC char requestBuffer[ROOM_SEND_REQUEST_SIZE];
\r
952 sprintf(requestBuffer,
\r
956 "\"room_id\":\"%s\""
\r
962 // get megolm session
\r
963 MatrixMegolmOutSession * outSession;
\r
964 if (! MatrixClientGetMegolmOutSession(client, roomId, &outSession))
\r
965 MatrixClientNewMegolmOutSession(client, roomId, &outSession);
\r
968 MatrixMegolmOutSessionEncrypt(outSession,
\r
970 g_EncryptedRequestBuffer, ENCRYPTED_REQUEST_SIZE);
\r
972 char thisDeviceKey[DEVICE_KEY_SIZE];
\r
973 MatrixOlmAccountGetDeviceKey(&client->olmAccount, thisDeviceKey, DEVICE_KEY_SIZE);
\r
976 // encrypted event json
\r
977 const char * senderKey = thisDeviceKey;
\r
978 const char * sessionId = outSession->id;
\r
979 const char * deviceId = client->deviceId;
\r
981 snprintf(g_EncryptedEventBuffer, ENCRYPTED_EVENT_SIZE,
\r
983 "\"algorithm\":\"m.megolm.v1.aes-sha2\","
\r
984 "\"ciphertext\":\"%s\","
\r
985 "\"device_id\":\"%s\","
\r
986 "\"sender_key\":\"%s\","
\r
987 "\"session_id\":\"%s\""
\r
989 g_EncryptedRequestBuffer,
\r
995 return MatrixClientSendEvent(client,
\r
997 "m.room.encrypted",
\r
998 g_EncryptedEventBuffer);
\r
1001 // https://spec.matrix.org/v1.6/client-server-api/#get_matrixclientv3sync
\r
1004 MatrixClient * client,
\r
1005 char * outSyncBuffer, int outSyncCap,
\r
1006 const char * nextBatch)
\r
1008 // filter={\"event_fields\":[\"to_device\"]}
\r
1009 STATIC char url[MAX_URL_LEN];
\r
1010 snprintf(url, MAX_URL_LEN,
\r
1011 "/_matrix/client/v3/sync?timeout=%d" "%s" "%s",
\r
1014 // "&filter={\"event_fields\":[\"to_device\"]}",
\r
1015 strlen(nextBatch) > 0 ? "&since=" : "");
\r
1017 int index = strlen(url);
\r
1019 for (size_t i = 0; i < strlen(nextBatch); i++) {
\r
1020 char c = nextBatch[i];
\r
1023 url[index++] = '%';
\r
1024 url[index++] = '7';
\r
1025 url[index++] = 'E';
\r
1031 url[index] = '\0';
\r
1034 MatrixHttpGet(client->hc,
\r
1036 outSyncBuffer, outSyncCap,
\r
1040 // https://spec.matrix.org/v1.7/client-server-api/#get_matrixclientv3roomsroomideventeventid
\r
1042 MatrixClientGetRoomEvent(
\r
1043 MatrixClient * client,
\r
1044 const char * roomId,
\r
1045 const char * eventId,
\r
1046 char * outEvent, int outEventCap)
\r
1048 STATIC char url[MAX_URL_LEN];
\r
1049 snprintf(url, MAX_URL_LEN,
\r
1050 "/_matrix/client/v3/rooms/%s/event/%s",
\r
1055 MatrixHttpGet(client->hc,
\r
1057 outEvent, outEventCap,
\r
1062 MatrixClientShareMegolmOutSession(
\r
1063 MatrixClient * client,
\r
1064 const char * userId,
\r
1065 const char * deviceId,
\r
1066 MatrixMegolmOutSession * session)
\r
1068 // generate room key event
\r
1069 STATIC char eventBuffer[KEY_SHARE_EVENT_LEN];
\r
1070 sprintf(eventBuffer,
\r
1072 "\"algorithm\":\"m.megolm.v1.aes-sha2\","
\r
1073 "\"room_id\":\"%s\","
\r
1074 "\"session_id\":\"%s\","
\r
1075 "\"session_key\":\"%s\""
\r
1083 MatrixClientSendToDeviceEncrypted(client,
\r
1093 MatrixClientShareMegolmOutSessionTest(
\r
1094 MatrixClient * client,
\r
1095 const char * userId,
\r
1096 const char * deviceId,
\r
1097 MatrixMegolmOutSession * session)
\r
1099 // generate room key event
\r
1100 char eventBuffer[KEY_SHARE_EVENT_LEN];
\r
1101 sprintf(eventBuffer,
\r
1103 "\"algorithm\":\"m.megolm.v1.aes-sha2\","
\r
1104 "\"room_id\":\"%s\","
\r
1105 "\"session_id\":\"%s\","
\r
1106 "\"session_key\":\"%s\""
\r
1114 MatrixClientSendToDevice(client,
\r
1124 MatrixClientGetMegolmOutSession(
\r
1125 MatrixClient * client,
\r
1126 const char * roomId,
\r
1127 MatrixMegolmOutSession ** outSession)
\r
1129 for (int i = 0; i < client->numMegolmOutSessions; i++)
\r
1131 if (strcmp(client->megolmOutSessions[i].roomId, roomId) == 0)
\r
1133 *outSession = &client->megolmOutSessions[i];
\r
1142 MatrixClientNewMegolmOutSession(
\r
1143 MatrixClient * client,
\r
1144 const char * roomId,
\r
1145 MatrixMegolmOutSession ** outSession)
\r
1147 if (client->numMegolmOutSessions < NUM_MEGOLM_SESSIONS)
\r
1149 MatrixMegolmOutSession * result =
\r
1150 &client->megolmOutSessions[client->numMegolmOutSessions];
\r
1152 MatrixMegolmOutSessionInit(result,
\r
1155 *outSession = result;
\r
1157 client->numMegolmOutSessions++;
\r
1166 MatrixClientGetMegolmInSession(
\r
1167 MatrixClient * client,
\r
1168 const char * roomId, int roomIdLen,
\r
1169 const char * sessionId, int sessionIdLen,
\r
1170 MatrixMegolmInSession ** outSession)
\r
1172 for (int i = 0; i < client->numMegolmInSessions; i++)
\r
1174 if (strncmp(client->megolmInSessions[i].roomId, roomId, roomIdLen) == 0 &&
\r
1175 strncmp(client->megolmInSessions[i].id, sessionId, sessionIdLen) == 0)
\r
1177 *outSession = &client->megolmInSessions[i];
\r
1186 MatrixClientNewMegolmInSession(
\r
1187 MatrixClient * client,
\r
1188 const char * roomId,
\r
1189 const char * sessionId,
\r
1190 const char * sessionKey,
\r
1191 MatrixMegolmInSession ** outSession)
\r
1193 if (client->numMegolmInSessions < NUM_MEGOLM_SESSIONS)
\r
1195 MatrixMegolmInSession * result =
\r
1196 &client->megolmInSessions[client->numMegolmInSessions];
\r
1198 MatrixMegolmInSessionInit(result,
\r
1201 sessionKey, strlen(sessionKey));
\r
1203 *outSession = result;
\r
1205 client->numMegolmInSessions++;
\r
1214 MatrixClientRequestMegolmInSession(
\r
1215 MatrixClient * client,
\r
1216 const char * roomId,
\r
1217 const char * sessionId,
\r
1218 const char * senderKey,
\r
1219 const char * userId,
\r
1220 const char * deviceId)
\r
1222 // TODO: cancel requests
\r
1223 MatrixClientSendDummy(client, userId, deviceId);
\r
1225 STATIC char event[ROOMKEY_REQUEST_SIZE];
\r
1226 snprintf(event, ROOMKEY_REQUEST_SIZE,
\r
1228 "\"action\":\"request\","
\r
1230 "\"algorithm\":\"m.megolm.v1.aes-sha2\","
\r
1231 "\"room_id\":\"%s\","
\r
1232 "\"sender_key\":\"%s\","
\r
1233 "\"session_id\":\"%s\""
\r
1235 "\"request_id\":\"%lld\","
\r
1236 "\"requesting_device_id\":\"%s\""
\r
1242 client->deviceId);
\r
1245 MatrixClientSendToDevice(client,
\r
1249 "m.room_key_request");
\r
1255 MatrixClientGetOlmSession(
\r
1256 MatrixClient * client,
\r
1257 const char * userId,
\r
1258 const char * deviceId,
\r
1259 MatrixOlmSession ** outSession)
\r
1261 for (int i = 0; i < client->numOlmSessions; i++)
\r
1263 if (strcmp(client->olmSessions[i].deviceId, deviceId) == 0)
\r
1265 *outSession = &client->olmSessions[i];
\r
1274 MatrixClientNewOlmSessionIn(
\r
1275 MatrixClient * client,
\r
1276 const char * userId,
\r
1277 const char * deviceId,
\r
1278 const char * encrypted,
\r
1279 MatrixOlmSession ** outSession)
\r
1281 if (client->numOlmSessions < NUM_OLM_SESSIONS)
\r
1283 STATIC char deviceKey[DEVICE_KEY_SIZE];
\r
1284 MatrixClientRequestDeviceKey(client,
\r
1286 deviceKey, DEVICE_KEY_SIZE);
\r
1288 MatrixOlmSessionFrom(
\r
1289 &client->olmSessions[client->numOlmSessions],
\r
1290 client->olmAccount.account,
\r
1295 *outSession = &client->olmSessions[client->numOlmSessions];
\r
1297 client->numOlmSessions++;
\r
1306 MatrixClientNewOlmSessionOut(
\r
1307 MatrixClient * client,
\r
1308 const char * userId,
\r
1309 const char * deviceId,
\r
1310 MatrixOlmSession ** outSession)
\r
1312 if (client->numOlmSessions < NUM_OLM_SESSIONS)
\r
1314 STATIC char deviceKey[DEVICE_KEY_SIZE];
\r
1315 MatrixClientRequestDeviceKey(client,
\r
1317 deviceKey, DEVICE_KEY_SIZE);
\r
1319 char onetimeKey[ONETIME_KEY_SIZE];
\r
1320 MatrixClientClaimOnetimeKey(client,
\r
1323 onetimeKey, ONETIME_KEY_SIZE);
\r
1325 MatrixOlmSessionTo(
\r
1326 &client->olmSessions[client->numOlmSessions],
\r
1327 client->olmAccount.account,
\r
1332 *outSession = &client->olmSessions[client->numOlmSessions];
\r
1334 client->numOlmSessions++;
\r
1342 // https://spec.matrix.org/v1.6/client-server-api/#put_matrixclientv3sendtodeviceeventtypetxnid
\r
1344 MatrixClientSendToDevice(
\r
1345 MatrixClient * client,
\r
1346 const char * userId,
\r
1347 const char * deviceId,
\r
1348 const char * message,
\r
1349 const char * msgType)
\r
1351 STATIC char requestUrl[MAX_URL_LEN];
\r
1352 sprintf(requestUrl,
\r
1353 TODEVICE_URL, msgType, (int)time(NULL));
\r
1355 snprintf(g_TodeviceEventBuffer, TODEVICE_EVENT_SIZE,
\r
1367 STATIC char responseBuffer[ROOM_SEND_RESPONSE_SIZE];
\r
1369 MatrixHttpPut(client->hc,
\r
1371 g_TodeviceEventBuffer,
\r
1372 responseBuffer, ROOM_SEND_RESPONSE_SIZE,
\r
1375 printf("%s\n", responseBuffer);
\r
1381 MatrixClientSendToDeviceEncrypted(
\r
1382 MatrixClient * client,
\r
1383 const char * userId,
\r
1384 const char * deviceId,
\r
1385 const char * message,
\r
1386 const char * msgType)
\r
1388 // get olm session
\r
1389 MatrixOlmSession * olmSession;
\r
1390 if (! MatrixClientGetOlmSession(client, userId, deviceId, &olmSession))
\r
1391 MatrixClientNewOlmSessionOut(client, userId, deviceId, &olmSession);
\r
1393 // create event json
\r
1394 char targetDeviceKey[DEVICE_KEY_SIZE];
\r
1395 MatrixClientRequestDeviceKey(client, deviceId, targetDeviceKey, DEVICE_KEY_SIZE);
\r
1396 char targetSigningKey[SIGNING_KEY_SIZE];
\r
1397 MatrixClientRequestSigningKey(client, deviceId, targetSigningKey, SIGNING_KEY_SIZE);
\r
1399 char thisSigningKey[DEVICE_KEY_SIZE];
\r
1400 MatrixOlmAccountGetSigningKey(&client->olmAccount, thisSigningKey, DEVICE_KEY_SIZE);
\r
1402 snprintf(g_TodeviceEventBuffer, TODEVICE_EVENT_SIZE,
\r
1404 "\"type\":\"%s\","
\r
1406 "\"sender\":\"%s\","
\r
1407 "\"recipient\":\"%s\","
\r
1408 "\"recipient_keys\":{"
\r
1409 "\"ed25519\":\"%s\""
\r
1412 "\"ed25519\":\"%s\""
\r
1418 userId, // recipient user id
\r
1419 targetSigningKey, // recipient device key
\r
1423 MatrixOlmSessionEncrypt(olmSession,
\r
1424 g_TodeviceEventBuffer,
\r
1425 g_EncryptedRequestBuffer, ENCRYPTED_REQUEST_SIZE);
\r
1427 char thisDeviceKey[DEVICE_KEY_SIZE];
\r
1428 MatrixOlmAccountGetDeviceKey(&client->olmAccount, thisDeviceKey, DEVICE_KEY_SIZE);
\r
1430 snprintf(g_EncryptedEventBuffer, ENCRYPTED_EVENT_SIZE,
\r
1432 "\"algorithm\":\"m.olm.v1.curve25519-aes-sha2\","
\r
1433 "\"ciphertext\":{"
\r
1435 "\"body\":\"%s\","
\r
1439 "\"device_id\":\"%s\","
\r
1440 "\"sender_key\":\"%s\""
\r
1443 g_EncryptedRequestBuffer,
\r
1444 olm_session_has_received_message(olmSession->session),
\r
1449 return MatrixClientSendToDevice(
\r
1453 g_EncryptedEventBuffer,
\r
1454 "m.room.encrypted");
\r
1458 MatrixClientSendDummy(
\r
1459 MatrixClient * client,
\r
1460 const char * userId,
\r
1461 const char * deviceId)
\r
1463 return MatrixClientSendToDeviceEncrypted(
\r
1472 MatrixClientFindDevice(
\r
1473 MatrixClient * client,
\r
1474 const char * deviceId,
\r
1475 MatrixDevice ** outDevice)
\r
1477 MatrixClientRequestDeviceKeys(client);
\r
1479 for (int i = 0; i < client->numDevices; i++)
\r
1481 if (strcmp(client->devices[i].deviceId, deviceId) == 0)
\r
1483 *outDevice = &client->devices[i];
\r
1488 *outDevice = NULL;
\r
1493 MatrixClientRequestDeviceKey(
\r
1494 MatrixClient * client,
\r
1495 const char * deviceId,
\r
1496 char * outDeviceKey, int outDeviceKeyCap)
\r
1498 MatrixDevice * device;
\r
1500 if (MatrixClientFindDevice(client, deviceId, &device))
\r
1502 strncpy(outDeviceKey, device->deviceKey, outDeviceKeyCap);
\r
1506 MatrixClientRequestDeviceKeys(client);
\r
1508 if (MatrixClientFindDevice(client, deviceId, &device))
\r
1510 strncpy(outDeviceKey, device->deviceKey, outDeviceKeyCap);
\r
1518 MatrixClientRequestSigningKey(
\r
1519 MatrixClient * client,
\r
1520 const char * deviceId,
\r
1521 char * outSigningKey, int outSigningKeyCap)
\r
1523 MatrixDevice * device;
\r
1525 if (MatrixClientFindDevice(client, deviceId, &device))
\r
1527 strncpy(outSigningKey, device->signingKey, outSigningKeyCap);
\r
1531 MatrixClientRequestDeviceKeys(client);
\r
1533 if (MatrixClientFindDevice(client, deviceId, &device))
\r
1535 strncpy(outSigningKey, device->signingKey, outSigningKeyCap);
\r
1542 // https://spec.matrix.org/v1.6/client-server-api/#post_matrixclientv3keysquery
\r
1544 MatrixClientRequestDeviceKeys(
\r
1545 MatrixClient * client)
\r
1547 if (client->numDevices >= NUM_DEVICES) {
\r
1548 printf("Maximum number of devices reached\n");
\r
1552 STATIC char userIdEscaped[USER_ID_SIZE];
\r
1553 JsonEscape(client->userId, strlen(client->userId),
\r
1554 userIdEscaped, USER_ID_SIZE);
\r
1556 STATIC char request[KEYS_QUERY_REQUEST_SIZE];
\r
1557 snprintf(request, KEYS_QUERY_REQUEST_SIZE,
\r
1558 "{\"device_keys\":{\"%s\":[]}}", client->userId);
\r
1560 STATIC char responseBuffer[KEYS_QUERY_RESPONSE_SIZE];
\r
1561 bool requestResult = MatrixHttpPost(client->hc,
\r
1564 responseBuffer, KEYS_QUERY_RESPONSE_SIZE,
\r
1567 if (! requestResult)
\r
1570 // query for retrieving device keys for user id
\r
1571 STATIC char query[JSON_QUERY_SIZE];
\r
1572 snprintf(query, JSON_QUERY_SIZE,
\r
1573 "$.device_keys.%s", userIdEscaped);
\r
1577 mjson_find(responseBuffer, strlen(responseBuffer),
\r
1578 query, &s, &slen);
\r
1582 int koff, klen, voff, vlen, vtype, off = 0;
\r
1583 for (off = 0; (off = mjson_next(s, slen, off, &koff, &klen,
\r
1584 &voff, &vlen, &vtype)) != 0; ) {
\r
1585 const char * key = s + koff;
\r
1586 const char * val = s + voff;
\r
1588 // set device id, "key" is the JSON key
\r
1590 snprintf(d.deviceId, DEVICE_ID_SIZE,
\r
1591 "%.*s", klen-2, key+1);
\r
1593 // look for device key in value
\r
1594 STATIC char deviceKeyQuery[JSON_QUERY_SIZE];
\r
1595 snprintf(deviceKeyQuery, JSON_QUERY_SIZE,
\r
1596 "$.keys.curve25519:%s", d.deviceId);
\r
1597 mjson_get_string(val, vlen,
\r
1598 deviceKeyQuery, d.deviceKey, DEVICE_KEY_SIZE);
\r
1600 // look for signing key in value
\r
1601 STATIC char signingKeyQuery[JSON_QUERY_SIZE];
\r
1602 snprintf(signingKeyQuery, JSON_QUERY_SIZE,
\r
1603 "$.keys.ed25519:%s", d.deviceId);
\r
1604 mjson_get_string(val, vlen,
\r
1605 signingKeyQuery, d.signingKey, SIGNING_KEY_SIZE);
\r
1608 if (client->numDevices < NUM_DEVICES)
\r
1610 bool foundDevice = false;
\r
1611 for (int i = 0; i < client->numDevices; i++)
\r
1612 if (strcmp(client->devices[i].deviceId, d.deviceId) == 0)
\r
1613 foundDevice = true;
\r
1615 if (! foundDevice) {
\r
1616 printf("new device: %s %s %s\n", d.deviceId, d.deviceKey, d.signingKey);
\r
1617 client->devices[client->numDevices] = d;
\r
1618 client->numDevices++;
\r
1631 MatrixClientDeleteDevice(
\r
1632 MatrixClient * client)
\r
1634 STATIC char deleteRequest[1024];
\r
1635 snprintf(deleteRequest, 1024,
\r
1636 "{\"devices\":[\"%s\"]}",
\r
1637 client->deviceId);
\r
1638 STATIC char deleteResponse[1024];
\r
1639 bool res = MatrixHttpPost(client->hc, "/_matrix/client/v3/delete_devices",
\r
1640 deleteRequest, deleteResponse, 1024, true);
\r