8 #include <esp_random.h>
\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 #define ENCRYPTED_EVENT_SIZE (1024*10)
\r
19 #define ROOM_SEND_REQUEST_SIZE 256
\r
20 #define ROOM_SEND_RESPONSE_SIZE 1024
\r
21 #define ROOM_SEND_URL "/_matrix/client/v3/rooms/%s/send/%s/%d"
\r
23 #define ROOMKEY_REQUEST_SIZE (1024*4)
\r
25 #define TODEVICE_EVENT_SIZE (1024*5)
\r
26 #define TODEVICE_URL "/_matrix/client/v3/sendToDevice/%s/%d"
\r
28 #define KEYS_QUERY_URL "/_matrix/client/v3/keys/query"
\r
29 #define KEYS_QUERY_REQUEST_SIZE 256
\r
30 #define KEYS_QUERY_RESPONSE_SIZE (1024*10)
\r
32 #define KEYS_UPLOAD_URL "/_matrix/client/v3/keys/upload"
\r
33 #define KEYS_UPLOAD_REQUEST_SIZE 1024*4
\r
34 #define KEYS_UPLOAD_REQUEST_SIGNED_SIZE 2048*4
\r
35 #define KEYS_UPLOAD_RESPONSE_SIZE 2048
\r
37 #define KEYS_CLAIM_URL "/_matrix/client/v3/keys/claim"
\r
38 #define KEYS_CLAIM_REQUEST_SIZE 1024
\r
39 #define KEYS_CLAIM_RESPONSE_SIZE 1024
\r
41 #define SYNC_TIMEOUT 5000
\r
43 #define JSON_QUERY_SIZE 128
\r
44 #define JSON_MAX_INDICES 100
\r
45 #define JSON_MAX_ENTRY_SIZE 1024
\r
47 #define MAX(a,b) ((a) > (b) ? (a) : (b))
\r
48 #define MIN(a,b) ((a) < (b) ? (a) : (b))
\r
57 for (int i = 0; i < randomLen; i++)
\r
59 random[i] = esp_random() % 256;
\r
64 STATIC bool first = true;
\r
65 if (first) { srand(time(0)); first = false; }
\r
67 for (int i = 0; i < randomLen; i++)
\r
69 random[i] = rand() % 256;
\r
77 const char * sIn, int sInLen,
\r
78 char * sOut, int sOutCap)
\r
82 for (int i = 0; i < sInLen; i++)
\r
87 if (sIn[i] == '.' ||
\r
91 sOut[sOutIndex++] = '\\';
\r
93 sOut[sOutIndex++] = sIn[i];
\r
96 if (sOutIndex < sOutCap)
\r
97 sOut[sOutIndex] = '\0';
\r
104 const char * sIn, int sInLen,
\r
105 char * sOut, int sOutCap)
\r
107 snprintf(sOut, sOutCap, "{}");
\r
109 int koff, klen, voff, vlen, vtype, off;
\r
116 struct Key keys[JSON_MAX_INDICES];
\r
119 for (off = 0; (off = mjson_next(sIn, sInLen, off, &koff, &klen, &voff, &vlen, &vtype)) != 0; ) {
\r
120 keys[numKeys].ptr = sIn + koff;
\r
121 keys[numKeys].len = klen;
\r
125 for (int i = 0; i < numKeys; i++) {
\r
126 for (int j = i; j < numKeys; j++) {
\r
131 MIN(keys[i].len, keys[j].len)
\r
134 struct Key k = keys[i];
\r
141 for (int i = 0; i < numKeys; i++) {
\r
142 char jp[JSON_QUERY_SIZE];
\r
143 snprintf(jp, JSON_QUERY_SIZE, "$.%.*s", keys[i].len-2, keys[i].ptr+1);
\r
145 const char * valPtr;
\r
147 mjson_find(sIn, sInLen, jp, &valPtr, &valLen);
\r
149 STATIC char newEntry[JSON_MAX_ENTRY_SIZE];
\r
150 snprintf(newEntry, JSON_MAX_ENTRY_SIZE, "{%.*s:%.*s}", keys[i].len, keys[i].ptr, valLen, valPtr);
\r
152 char * buffer = strdup(sOut);
\r
154 struct mjson_fixedbuf fb = { sOut, sOutCap, 0 };
\r
155 mjson_merge(buffer, strlen(buffer), newEntry, strlen(newEntry), mjson_print_fixed_buf, &fb);
\r
160 // TODO: recursively sort entries
\r
166 MatrixClient * client,
\r
167 const char * sIn, int sInLen,
\r
168 char * sOut, int sOutCap)
\r
170 STATIC char signature[OLM_SIGNATURE_SIZE];
\r
172 olm_account_sign(client->olmAccount.account,
\r
174 signature, OLM_SIGNATURE_SIZE);
\r
176 int signatureLen = res;
\r
178 STATIC char thisSigningKey[SIGNING_KEY_SIZE];
\r
179 MatrixOlmAccountGetSigningKey(&client->olmAccount, thisSigningKey, SIGNING_KEY_SIZE);
\r
181 STATIC char signatureJson[JSON_SIGNATURE_SIZE];
\r
182 int signatureJsonLen =
\r
183 mjson_snprintf(signatureJson, JSON_SIGNATURE_SIZE,
\r
187 "\"ed25519:%s\":\"%.*s\""
\r
194 signatureLen, signature);
\r
196 struct mjson_fixedbuf result = { sOut, sOutCap, 0 };
\r
199 signatureJson, signatureJsonLen,
\r
200 mjson_print_fixed_buf,
\r
208 MatrixOlmAccountInit(
\r
209 MatrixOlmAccount * account)
\r
211 account->account = olm_account(account->memory);
\r
213 STATIC uint8_t random[OLM_ACCOUNT_RANDOM_SIZE];
\r
214 Randomize(random, OLM_ACCOUNT_RANDOM_SIZE);
\r
216 size_t res = olm_create_account(
\r
219 OLM_ACCOUNT_RANDOM_SIZE);
\r
221 return res != olm_error();
\r
225 MatrixOlmAccountUnpickle(
\r
226 MatrixOlmAccount * account,
\r
227 void * pickled, int pickledLen,
\r
228 const void * key, int keyLen)
\r
231 res = olm_unpickle_account(account->account,
\r
233 pickled, pickledLen);
\r
234 if (res == olm_error()) {
\r
235 printf("error unpickling olm account:%s\n",
\r
236 olm_account_last_error(account->account));
\r
238 return res != olm_error();
\r
242 MatrixOlmAccountGetDeviceKey(
\r
243 MatrixOlmAccount * account,
\r
244 char * key, int keyCap)
\r
246 STATIC char deviceKeysJson[OLM_IDENTITY_KEYS_JSON_SIZE];
\r
248 olm_account_identity_keys(account->account,
\r
249 deviceKeysJson, OLM_IDENTITY_KEYS_JSON_SIZE);
\r
250 mjson_get_string(deviceKeysJson, res,
\r
257 MatrixOlmAccountGetSigningKey(
\r
258 MatrixOlmAccount * account,
\r
259 char * key, int keyCap)
\r
261 STATIC char deviceKeysJson[OLM_IDENTITY_KEYS_JSON_SIZE];
\r
263 olm_account_identity_keys(account->account,
\r
264 deviceKeysJson, OLM_IDENTITY_KEYS_JSON_SIZE);
\r
265 mjson_get_string(deviceKeysJson, res,
\r
272 MatrixOlmSessionFrom(
\r
273 MatrixOlmSession * session,
\r
274 OlmAccount * olmAccount,
\r
275 const char * deviceId,
\r
276 const char * deviceKey,
\r
277 const char * encrypted)
\r
279 memset(session, 0, sizeof(MatrixOlmSession));
\r
281 session->deviceId = deviceId;
\r
284 olm_session(session->memory);
\r
286 char * encryptedCopy = strdup(encrypted);
\r
289 olm_create_inbound_session_from(session->session, olmAccount,
\r
290 deviceKey, strlen(deviceKey),
\r
291 encryptedCopy, strlen(encryptedCopy));
\r
293 if (res == olm_error()) {
\r
294 printf("error olm:%s\n", olm_session_last_error(session->session));
\r
297 return res != olm_error();
\r
301 MatrixOlmSessionTo(
\r
302 MatrixOlmSession * session,
\r
303 OlmAccount * olmAccount,
\r
304 const char * deviceId,
\r
305 const char * deviceKey,
\r
306 const char * deviceOnetimeKey)
\r
308 memset(session, 0, sizeof(MatrixOlmSession));
\r
310 session->deviceId = deviceId;
\r
313 olm_session(session->memory);
\r
315 STATIC uint8_t random[OLM_OUTBOUND_SESSION_RANDOM_SIZE];
\r
316 Randomize(random, OLM_OUTBOUND_SESSION_RANDOM_SIZE);
\r
319 olm_create_outbound_session(session->session,
\r
321 deviceKey, strlen(deviceKey),
\r
322 deviceOnetimeKey, strlen(deviceOnetimeKey),
\r
323 random, OLM_OUTBOUND_SESSION_RANDOM_SIZE);
\r
325 if (res == olm_error()) {
\r
326 printf("error olm:%s\n", olm_session_last_error(session->session));
\r
329 return res != olm_error();
\r
333 MatrixOlmSessionUnpickle(
\r
334 MatrixOlmSession * session,
\r
335 const char * deviceId,
\r
336 void * pickled, int pickledLen,
\r
337 const void * key, int keyLen)
\r
339 memset(session, 0, sizeof(MatrixOlmSession));
\r
341 session->deviceId = deviceId;
\r
344 olm_session(session->memory);
\r
347 res = olm_unpickle_session(session->session,
\r
349 pickled, pickledLen);
\r
351 if (res == olm_error()) {
\r
352 printf("error unpickling olm session:%s\n", olm_session_last_error(session->session));
\r
355 return res != olm_error();
\r
359 MatrixOlmSessionEncrypt(
\r
360 MatrixOlmSession * session,
\r
361 const char * plaintext,
\r
362 char * outBuffer, int outBufferCap)
\r
364 STATIC uint8_t random[OLM_ENCRYPT_RANDOM_SIZE];
\r
365 Randomize(random, OLM_ENCRYPT_RANDOM_SIZE);
\r
367 size_t res = olm_encrypt(session->session,
\r
368 plaintext, strlen(plaintext),
\r
369 random, OLM_ENCRYPT_RANDOM_SIZE,
\r
370 outBuffer, outBufferCap);
\r
372 return res != olm_error();
\r
376 MatrixOlmSessionDecrypt(
\r
377 MatrixOlmSession * session,
\r
378 size_t messageType,
\r
380 char * outBuffer, int outBufferCap)
\r
382 STATIC uint8_t random[OLM_ENCRYPT_RANDOM_SIZE];
\r
383 Randomize(random, OLM_ENCRYPT_RANDOM_SIZE);
\r
386 olm_decrypt(session->session,
\r
388 encrypted, strlen(encrypted),
\r
389 outBuffer, outBufferCap);
\r
391 if (res != olm_error() && res < outBufferCap)
\r
392 outBuffer[res] = '\0';
\r
394 return res != olm_error();
\r
398 MatrixMegolmInSessionInit(
\r
399 MatrixMegolmInSession * session,
\r
400 const char * roomId,
\r
401 const char * sessionId,
\r
402 const char * sessionKey, int sessionKeyLen)
\r
404 memset(session, 0, sizeof(MatrixMegolmInSession));
\r
406 strncpy(session->roomId, roomId, sizeof(session->roomId));
\r
407 strncpy(session->id, sessionId, sizeof(session->id));
\r
408 strncpy(session->key, sessionKey, sizeof(session->key));
\r
411 olm_inbound_group_session(session->memory);
\r
414 olm_init_inbound_group_session(
\r
415 // olm_import_inbound_group_session(
\r
417 (const uint8_t *)sessionKey, sessionKeyLen);
\r
418 if (res == olm_error()) {
\r
419 printf("Error initializing Megolm session: %s\n", olm_inbound_group_session_last_error(session->session));
\r
422 return res != olm_error();
\r
426 MatrixMegolmInSessionDecrypt(
\r
427 MatrixMegolmInSession * session,
\r
428 const char * encrypted, int encryptedLen,
\r
429 char * outDecrypted, int outDecryptedCap)
\r
431 // uint8_t buffer[1024];
\r
432 // memcpy(buffer, encrypted, encryptedLen);
\r
434 uint32_t megolmInMessageIndex;
\r
437 olm_group_decrypt(session->session,
\r
438 (uint8_t *)encrypted, encryptedLen,
\r
439 (uint8_t *)outDecrypted, outDecryptedCap,
\r
440 &megolmInMessageIndex);
\r
442 printf("message index: %d\n", (int)megolmInMessageIndex);
\r
444 if (res == olm_error()) {
\r
445 printf("error decrypting megolm message: %s\n", olm_inbound_group_session_last_error(session->session));
\r
448 printf("decrypted len: %d\n", res);
\r
454 // https://matrix.org/docs/guides/end-to-end-encryption-implementation-guide#starting-a-megolm-session
\r
456 MatrixMegolmOutSessionInit(
\r
457 MatrixMegolmOutSession * session,
\r
458 const char * roomId)
\r
460 memset(session, 0, sizeof(MatrixMegolmOutSession));
\r
462 STATIC uint8_t random[MEGOLM_INIT_RANDOM_SIZE];
\r
463 Randomize(random, MEGOLM_INIT_RANDOM_SIZE);
\r
465 strncpy(session->roomId, roomId, ROOM_ID_SIZE);
\r
468 olm_outbound_group_session(session->memory);
\r
470 olm_init_outbound_group_session(
\r
473 MEGOLM_INIT_RANDOM_SIZE);
\r
475 olm_outbound_group_session_id(session->session,
\r
476 (uint8_t *)session->id,
\r
477 MEGOLM_SESSION_ID_SIZE);
\r
479 olm_outbound_group_session_key(session->session,
\r
480 (uint8_t *)session->key,
\r
481 MEGOLM_SESSION_KEY_SIZE);
\r
487 MatrixMegolmOutSessionEncrypt(
\r
488 MatrixMegolmOutSession * session,
\r
489 const char * plaintext,
\r
490 char * outBuffer, int outBufferCap)
\r
492 size_t res = olm_group_encrypt(session->session,
\r
493 (uint8_t *)plaintext, strlen(plaintext),
\r
494 (uint8_t *)outBuffer, outBufferCap);
\r
496 return res != olm_error();
\r
500 MatrixMegolmOutSessionSave(
\r
501 MatrixMegolmOutSession * session,
\r
502 const char * filename,
\r
505 FILE * f = fopen(filename, "w");
\r
507 size_t roomIdLen = strlen(session->roomId);
\r
508 fwrite(&roomIdLen, sizeof(size_t), 1, f);
\r
509 fwrite(session->roomId, 1, roomIdLen, f);
\r
511 size_t pickleBufferLen =
\r
512 olm_pickle_outbound_group_session_length(
\r
514 void * pickleBuffer = malloc(pickleBufferLen);
\r
516 olm_pickle_outbound_group_session(
\r
519 pickleBuffer, pickleBufferLen);
\r
521 fwrite(&pickleBufferLen, sizeof(size_t), 1, f);
\r
522 fwrite(pickleBuffer, 1, pickleBufferLen, f);
\r
523 free(pickleBuffer);
\r
531 MatrixMegolmOutSessionLoad(
\r
532 MatrixMegolmOutSession * session,
\r
533 const char * filename,
\r
536 FILE * f = fopen(filename, "r");
\r
539 fread(&roomIdLen, sizeof(size_t), 1, f);
\r
540 fread(session->roomId, 1, roomIdLen, f);
\r
541 for (int i = roomIdLen; i < ROOM_ID_SIZE; i++)
\r
542 session->roomId[i] = '\0';
\r
544 size_t pickleBufferLen;
\r
545 fread(&pickleBufferLen, sizeof(size_t), 1, f);
\r
547 void * pickleBuffer = malloc(pickleBufferLen);
\r
548 fread(pickleBuffer, 1, pickleBufferLen, f);
\r
550 olm_unpickle_outbound_group_session(
\r
553 pickleBuffer, pickleBufferLen);
\r
555 free(pickleBuffer);
\r
557 olm_outbound_group_session_id(session->session, (uint8_t *)session->id, MEGOLM_SESSION_ID_SIZE);
\r
558 olm_outbound_group_session_key(session->session, (uint8_t *)session->key, MEGOLM_SESSION_KEY_SIZE);
\r
569 MatrixClient * client)
\r
571 memset(client, 0, sizeof(MatrixClient));
\r
573 // init olm account
\r
574 MatrixOlmAccountInit(&client->olmAccount);
\r
581 MatrixClient * client,
\r
582 const char * filename)
\r
584 FILE * f = fopen(filename, "w");
\r
587 char thisDeviceKey[DEVICE_KEY_SIZE];
\r
588 MatrixOlmAccountGetDeviceKey(&client->olmAccount, thisDeviceKey, DEVICE_KEY_SIZE);
\r
589 char thisSigningKey[DEVICE_KEY_SIZE];
\r
590 MatrixOlmAccountGetSigningKey(&client->olmAccount, thisSigningKey, DEVICE_KEY_SIZE);
\r
593 fwrite(thisDeviceKey, 1, DEVICE_KEY_SIZE, f);
\r
594 fwrite(thisSigningKey, 1, DEVICE_KEY_SIZE, f);
\r
595 fwrite(client->userId, 1, USER_ID_SIZE, f);
\r
596 fwrite(client->accessToken, 1, ACCESS_TOKEN_SIZE, f);
\r
597 fwrite(client->deviceId, 1, DEVICE_ID_SIZE, f);
\r
598 fwrite(client->expireMs, 1, EXPIRE_MS_SIZE, f);
\r
599 fwrite(client->refreshToken, 1, REFRESH_TOKEN_SIZE, f);
\r
601 fwrite(&client->numDevices, sizeof(int), 1, f);
\r
602 for (int i = 0; i < client->numDevices; i++) {
\r
603 fwrite(client->devices[i].deviceId, 1, DEVICE_ID_SIZE, f);
\r
604 fwrite(client->devices[i].deviceKey, 1, DEVICE_KEY_SIZE, f);
\r
613 MatrixClient * client,
\r
614 const char * filename)
\r
616 FILE * f = fopen(filename, "r");
\r
619 char thisDeviceKey[DEVICE_KEY_SIZE];
\r
620 MatrixOlmAccountGetDeviceKey(&client->olmAccount, thisDeviceKey, DEVICE_KEY_SIZE);
\r
621 char thisSigningKey[DEVICE_KEY_SIZE];
\r
622 MatrixOlmAccountGetSigningKey(&client->olmAccount, thisSigningKey, DEVICE_KEY_SIZE);
\r
625 fread(thisDeviceKey, 1, DEVICE_KEY_SIZE, f);
\r
626 fread(thisSigningKey, 1, DEVICE_KEY_SIZE, f);
\r
627 fread(client->userId, 1, USER_ID_SIZE, f);
\r
628 fread(client->accessToken, 1, ACCESS_TOKEN_SIZE, f);
\r
629 fread(client->deviceId, 1, DEVICE_ID_SIZE, f);
\r
630 fread(client->expireMs, 1, EXPIRE_MS_SIZE, f);
\r
631 fread(client->refreshToken, 1, REFRESH_TOKEN_SIZE, f);
\r
633 fread(&client->numDevices, sizeof(int), 1, f);
\r
634 for (int i = 0; i < client->numDevices; i++) {
\r
635 fread(client->devices[i].deviceId, 1, DEVICE_ID_SIZE, f);
\r
636 fread(client->devices[i].deviceKey, 1, DEVICE_KEY_SIZE, f);
\r
644 MatrixClientSetAccessToken(
\r
645 MatrixClient * client,
\r
646 const char * accessToken)
\r
648 for (int i = 0; i < ACCESS_TOKEN_SIZE-1; i++)
\r
649 client->accessToken[i] = accessToken[i];
\r
650 client->accessToken[ACCESS_TOKEN_SIZE-1] = '\0';
\r
656 MatrixClientSetDeviceId(
\r
657 MatrixClient * client,
\r
658 const char * deviceId)
\r
660 for (int i = 0; i < DEVICE_ID_SIZE-1; i++)
\r
661 client->deviceId[i] = deviceId[i];
\r
662 client->deviceId[DEVICE_ID_SIZE-1] = '\0';
\r
668 MatrixClientSetUserId(
\r
669 MatrixClient * client,
\r
670 const char * userId)
\r
672 for (int i = 0; i < USER_ID_SIZE-1; i++)
\r
673 client->userId[i] = userId[i];
\r
674 client->userId[USER_ID_SIZE-1] = '\0';
\r
680 MatrixClientGenerateOnetimeKeys(
\r
681 MatrixClient * client,
\r
684 STATIC uint8_t random[OLM_ONETIME_KEYS_RANDOM_SIZE];
\r
685 Randomize(random, OLM_ONETIME_KEYS_RANDOM_SIZE);
\r
688 olm_account_generate_one_time_keys(client->olmAccount.account,
\r
689 numberOfKeys, random, OLM_ONETIME_KEYS_RANDOM_SIZE);
\r
691 return res != olm_error();
\r
694 // https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv3keysupload
\r
696 MatrixClientUploadOnetimeKeys(
\r
697 MatrixClient * client)
\r
699 STATIC char requestBuffer[KEYS_UPLOAD_REQUEST_SIZE];
\r
701 mjson_snprintf(requestBuffer, KEYS_UPLOAD_REQUEST_SIZE,
\r
704 STATIC char onetimeKeysBuffer[1024];
\r
705 olm_account_one_time_keys(client->olmAccount.account,
\r
706 onetimeKeysBuffer, 1024);
\r
710 mjson_find(onetimeKeysBuffer, strlen(onetimeKeysBuffer), "$.curve25519", &keys, &keysLen);
\r
712 int koff, klen, voff, vlen, vtype, off = 0;
\r
713 while ((off = mjson_next(keys, keysLen, off, &koff, &klen, &voff, &vlen, &vtype)) != 0) {
\r
714 STATIC char keyJson[JSON_ONETIME_KEY_SIZE];
\r
717 snprintf(keyJson, JSON_ONETIME_KEY_SIZE,
\r
718 "{\"key\":\"%.*s\"}",
\r
719 vlen-2, keys + voff+1);
\r
721 STATIC char keyJsonSigned[JSON_ONETIME_KEY_SIGNED_SIZE];
\r
724 keyJson, keyJsonLen,
\r
725 keyJsonSigned, JSON_ONETIME_KEY_SIGNED_SIZE);
\r
727 mjson_snprintf(requestBuffer+strlen(requestBuffer), KEYS_UPLOAD_REQUEST_SIZE-strlen(requestBuffer),
\r
728 "\"signed_curve25519:%.*s\":%s,",
\r
729 klen-2, keys + koff+1,
\r
733 if (requestBuffer[strlen(requestBuffer)-1] == ',')
\r
734 requestBuffer[strlen(requestBuffer)-1] = '\0';
\r
736 mjson_snprintf(requestBuffer+strlen(requestBuffer), KEYS_UPLOAD_REQUEST_SIZE-strlen(requestBuffer),
\r
739 // STATIC char onetimeKeysSignedBuffer[KEYS_UPLOAD_REQUEST_SIGNED_SIZE];
\r
740 // JsonSign(client,
\r
741 // requestBuffer, strlen(requestBuffer),
\r
742 // onetimeKeysSignedBuffer, KEYS_UPLOAD_REQUEST_SIZE);
\r
744 // STATIC char finalEvent[KEYS_UPLOAD_REQUEST_SIGNED_SIZE];
\r
745 // snprintf(finalEvent, KEYS_UPLOAD_REQUEST_SIGNED_SIZE,
\r
746 // "{\"one_time_keys\":%s}", onetimeKeysSignedBuffer);
\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}", requestBuffer);
\r
751 STATIC char responseBuffer[KEYS_UPLOAD_RESPONSE_SIZE];
\r
752 MatrixHttpPost(client->hc,
\r
755 responseBuffer, KEYS_UPLOAD_RESPONSE_SIZE,
\r
761 // https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv3keysupload
\r
763 MatrixClientUploadDeviceKey(
\r
764 MatrixClient * client)
\r
766 char thisDeviceKey[DEVICE_KEY_SIZE];
\r
767 MatrixOlmAccountGetDeviceKey(&client->olmAccount, thisDeviceKey, DEVICE_KEY_SIZE);
\r
768 char thisSigningKey[DEVICE_KEY_SIZE];
\r
769 MatrixOlmAccountGetSigningKey(&client->olmAccount, thisSigningKey, DEVICE_KEY_SIZE);
\r
771 STATIC char deviceKeysBuffer[KEYS_UPLOAD_REQUEST_SIZE];
\r
773 int deviceKeysBufferLen =
\r
774 mjson_snprintf(deviceKeysBuffer, 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
789 STATIC char deviceKeysSignedBuffer[KEYS_UPLOAD_REQUEST_SIGNED_SIZE];
\r
791 deviceKeysBuffer, deviceKeysBufferLen,
\r
792 deviceKeysSignedBuffer, KEYS_UPLOAD_REQUEST_SIZE);
\r
794 STATIC char finalEvent[KEYS_UPLOAD_REQUEST_SIGNED_SIZE+30];
\r
795 snprintf(finalEvent, KEYS_UPLOAD_REQUEST_SIGNED_SIZE+30,
\r
796 "{\"device_keys\":%s}", deviceKeysSignedBuffer);
\r
798 STATIC char responseBuffer[KEYS_UPLOAD_RESPONSE_SIZE];
\r
799 MatrixHttpPost(client->hc,
\r
802 responseBuffer, KEYS_UPLOAD_RESPONSE_SIZE,
\r
808 // https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv3keysclaim
\r
810 MatrixClientClaimOnetimeKey(
\r
811 MatrixClient * client,
\r
812 const char * userId,
\r
813 const char * deviceId,
\r
814 char * outOnetimeKey, int outOnetimeKeyCap)
\r
816 STATIC char requestBuffer[KEYS_CLAIM_REQUEST_SIZE];
\r
817 mjson_snprintf(requestBuffer, KEYS_CLAIM_REQUEST_SIZE,
\r
819 "\"one_time_keys\":{"
\r
821 "\"%s\":\"signed_curve25519\""
\r
824 "\"timeout\":10000"
\r
829 STATIC char responseBuffer[KEYS_CLAIM_RESPONSE_SIZE];
\r
830 MatrixHttpPost(client->hc,
\r
833 responseBuffer, KEYS_CLAIM_RESPONSE_SIZE,
\r
836 STATIC char userIdEscaped[USER_ID_SIZE];
\r
837 JsonEscape(userId, strlen(userId),
\r
838 userIdEscaped, USER_ID_SIZE);
\r
840 STATIC char query[JSON_QUERY_SIZE];
\r
841 snprintf(query, JSON_QUERY_SIZE,
\r
842 "$.one_time_keys.%s.%s",
\r
846 const char * keyObject;
\r
848 mjson_find(responseBuffer, strlen(responseBuffer),
\r
850 &keyObject, &keyObjectSize);
\r
852 int koff, klen, voff, vlen, vtype;
\r
853 mjson_next(keyObject, keyObjectSize, 0,
\r
854 &koff, &klen, &voff, &vlen, &vtype);
\r
856 mjson_get_string(keyObject + voff, vlen,
\r
857 "$.key", outOnetimeKey, outOnetimeKeyCap);
\r
859 // TODO:verify signature
\r
864 // https://spec.matrix.org/v1.6/client-server-api/#post_matrixclientv3login
\r
866 MatrixClientLoginPassword(
\r
867 MatrixClient * client,
\r
868 const char * username,
\r
869 const char * password,
\r
870 const char * displayName)
\r
872 STATIC char requestBuffer[LOGIN_REQUEST_SIZE];
\r
874 mjson_snprintf(requestBuffer, LOGIN_REQUEST_SIZE,
\r
876 "\"type\":\"m.login.password\","
\r
878 "\"type\":\"m.id.user\","
\r
881 "\"password\":\"%s\","
\r
882 "\"initial_device_display_name\":\"%s\""
\r
888 STATIC char responseBuffer[LOGIN_RESPONSE_SIZE];
\r
890 MatrixHttpPost(client->hc,
\r
893 responseBuffer, LOGIN_RESPONSE_SIZE,
\r
899 int responseLen = strlen(responseBuffer);
\r
901 mjson_get_string(responseBuffer, responseLen,
\r
903 client->accessToken, ACCESS_TOKEN_SIZE);
\r
904 mjson_get_string(responseBuffer, responseLen,
\r
906 client->deviceId, DEVICE_ID_SIZE);
\r
907 mjson_get_string(responseBuffer, responseLen,
\r
909 client->expireMs, EXPIRE_MS_SIZE);
\r
910 mjson_get_string(responseBuffer, responseLen,
\r
912 client->refreshToken, REFRESH_TOKEN_SIZE);
\r
914 MatrixHttpSetAccessToken(client->hc, client->accessToken);
\r
919 // https://spec.matrix.org/v1.6/client-server-api/#put_matrixclientv3roomsroomidsendeventtypetxnid
\r
921 MatrixClientSendEvent(
\r
922 MatrixClient * client,
\r
923 const char * roomId,
\r
924 const char * msgType,
\r
925 const char * msgBody)
\r
927 STATIC char requestUrl[MAX_URL_LEN];
\r
928 sprintf(requestUrl,
\r
929 ROOM_SEND_URL, roomId, msgType, (int)time(NULL));
\r
931 STATIC char responseBuffer[ROOM_SEND_RESPONSE_SIZE];
\r
933 MatrixHttpPut(client->hc,
\r
936 responseBuffer, ROOM_SEND_RESPONSE_SIZE,
\r
942 // https://spec.matrix.org/v1.6/client-server-api/#mroomencrypted
\r
943 // https://matrix.org/docs/guides/end-to-end-encryption-implementation-guide#sending-an-encrypted-message-event
\r
945 MatrixClientSendEventEncrypted(
\r
946 MatrixClient * client,
\r
947 const char * roomId,
\r
948 const char * msgType,
\r
949 const char * msgBody)
\r
952 STATIC char requestBuffer[ROOM_SEND_REQUEST_SIZE];
\r
953 sprintf(requestBuffer,
\r
957 "\"room_id\":\"%s\""
\r
963 // get megolm session
\r
964 MatrixMegolmOutSession * outSession;
\r
965 if (! MatrixClientGetMegolmOutSession(client, roomId, &outSession))
\r
966 MatrixClientNewMegolmOutSession(client, roomId, &outSession);
\r
969 STATIC char encryptedBuffer[ENCRYPTED_REQUEST_SIZE/10];
\r
970 MatrixMegolmOutSessionEncrypt(outSession,
\r
972 encryptedBuffer, ENCRYPTED_REQUEST_SIZE);
\r
974 char thisDeviceKey[DEVICE_KEY_SIZE];
\r
975 MatrixOlmAccountGetDeviceKey(&client->olmAccount, thisDeviceKey, DEVICE_KEY_SIZE);
\r
978 // encrypted event json
\r
979 const char * senderKey = thisDeviceKey;
\r
980 const char * sessionId = outSession->id;
\r
981 const char * deviceId = client->deviceId;
\r
983 STATIC char encryptedEventBuffer[ENCRYPTED_EVENT_SIZE/10];
\r
984 sprintf(encryptedEventBuffer,
\r
986 "\"algorithm\":\"m.megolm.v1.aes-sha2\","
\r
987 "\"ciphertext\":\"%s\","
\r
988 "\"device_id\":\"%s\","
\r
989 "\"sender_key\":\"%s\","
\r
990 "\"session_id\":\"%s\""
\r
998 return MatrixClientSendEvent(client,
\r
1000 "m.room.encrypted",
\r
1001 encryptedEventBuffer);
\r
1004 // https://spec.matrix.org/v1.6/client-server-api/#get_matrixclientv3sync
\r
1007 MatrixClient * client,
\r
1008 char * outSyncBuffer, int outSyncCap,
\r
1009 const char * nextBatch)
\r
1011 // filter={\"event_fields\":[\"to_device\"]}
\r
1012 STATIC char url[MAX_URL_LEN];
\r
1013 snprintf(url, MAX_URL_LEN,
\r
1014 "/_matrix/client/v3/sync?timeout=%d%s",
\r
1016 strlen(nextBatch) > 0 ? "&since=" : "");
\r
1018 int index = strlen(url);
\r
1020 for (size_t i = 0; i < strlen(nextBatch); i++) {
\r
1021 char c = nextBatch[i];
\r
1024 url[index++] = '%';
\r
1025 url[index++] = '7';
\r
1026 url[index++] = 'E';
\r
1032 url[index] = '\0';
\r
1035 MatrixHttpGet(client->hc,
\r
1037 outSyncBuffer, outSyncCap,
\r
1041 // https://spec.matrix.org/v1.7/client-server-api/#get_matrixclientv3roomsroomideventeventid
\r
1043 MatrixClientGetRoomEvent(
\r
1044 MatrixClient * client,
\r
1045 const char * roomId,
\r
1046 const char * eventId,
\r
1047 char * outEvent, int outEventCap)
\r
1049 STATIC char url[MAX_URL_LEN];
\r
1050 snprintf(url, MAX_URL_LEN,
\r
1051 "/_matrix/client/v3/rooms/%s/event/%s",
\r
1056 MatrixHttpGet(client->hc,
\r
1058 outEvent, outEventCap,
\r
1063 MatrixClientShareMegolmOutSession(
\r
1064 MatrixClient * client,
\r
1065 const char * userId,
\r
1066 const char * deviceId,
\r
1067 MatrixMegolmOutSession * session)
\r
1069 // generate room key event
\r
1070 STATIC char eventBuffer[KEY_SHARE_EVENT_LEN];
\r
1071 sprintf(eventBuffer,
\r
1073 "\"algorithm\":\"m.megolm.v1.aes-sha2\","
\r
1074 "\"room_id\":\"%s\","
\r
1075 "\"session_id\":\"%s\","
\r
1076 "\"session_key\":\"%s\""
\r
1084 MatrixClientSendToDeviceEncrypted(client,
\r
1094 MatrixClientShareMegolmOutSessionTest(
\r
1095 MatrixClient * client,
\r
1096 const char * userId,
\r
1097 const char * deviceId,
\r
1098 MatrixMegolmOutSession * session)
\r
1100 // generate room key event
\r
1101 char eventBuffer[KEY_SHARE_EVENT_LEN];
\r
1102 sprintf(eventBuffer,
\r
1104 "\"algorithm\":\"m.megolm.v1.aes-sha2\","
\r
1105 "\"room_id\":\"%s\","
\r
1106 "\"session_id\":\"%s\","
\r
1107 "\"session_key\":\"%s\""
\r
1115 MatrixClientSendToDevice(client,
\r
1125 MatrixClientGetMegolmOutSession(
\r
1126 MatrixClient * client,
\r
1127 const char * roomId,
\r
1128 MatrixMegolmOutSession ** outSession)
\r
1130 for (int i = 0; i < client->numMegolmOutSessions; i++)
\r
1132 if (strcmp(client->megolmOutSessions[i].roomId, roomId) == 0)
\r
1134 *outSession = &client->megolmOutSessions[i];
\r
1143 MatrixClientNewMegolmOutSession(
\r
1144 MatrixClient * client,
\r
1145 const char * roomId,
\r
1146 MatrixMegolmOutSession ** outSession)
\r
1148 if (client->numMegolmOutSessions < NUM_MEGOLM_SESSIONS)
\r
1150 MatrixMegolmOutSession * result =
\r
1151 &client->megolmOutSessions[client->numMegolmOutSessions];
\r
1153 MatrixMegolmOutSessionInit(result,
\r
1156 *outSession = result;
\r
1158 client->numMegolmOutSessions++;
\r
1167 MatrixClientGetMegolmInSession(
\r
1168 MatrixClient * client,
\r
1169 const char * roomId, int roomIdLen,
\r
1170 const char * sessionId, int sessionIdLen,
\r
1171 MatrixMegolmInSession ** outSession)
\r
1173 for (int i = 0; i < client->numMegolmInSessions; i++)
\r
1175 if (strncmp(client->megolmInSessions[i].roomId, roomId, roomIdLen) == 0 &&
\r
1176 strncmp(client->megolmInSessions[i].id, sessionId, sessionIdLen) == 0)
\r
1178 *outSession = &client->megolmInSessions[i];
\r
1187 MatrixClientNewMegolmInSession(
\r
1188 MatrixClient * client,
\r
1189 const char * roomId,
\r
1190 const char * sessionId,
\r
1191 const char * sessionKey,
\r
1192 MatrixMegolmInSession ** outSession)
\r
1194 if (client->numMegolmInSessions < NUM_MEGOLM_SESSIONS)
\r
1196 MatrixMegolmInSession * result =
\r
1197 &client->megolmInSessions[client->numMegolmInSessions];
\r
1199 MatrixMegolmInSessionInit(result,
\r
1202 sessionKey, strlen(sessionKey));
\r
1204 *outSession = result;
\r
1206 client->numMegolmInSessions++;
\r
1215 MatrixClientRequestMegolmInSession(
\r
1216 MatrixClient * client,
\r
1217 const char * roomId,
\r
1218 const char * sessionId,
\r
1219 const char * senderKey,
\r
1220 const char * userId,
\r
1221 const char * deviceId)
\r
1223 // TODO: cancel requests
\r
1224 MatrixClientSendDummy(client, userId, deviceId);
\r
1226 STATIC char event[ROOMKEY_REQUEST_SIZE];
\r
1227 snprintf(event, ROOMKEY_REQUEST_SIZE,
\r
1229 "\"action\":\"request\","
\r
1231 "\"algorithm\":\"m.megolm.v1.aes-sha2\","
\r
1232 "\"room_id\":\"%s\","
\r
1233 "\"sender_key\":\"%s\","
\r
1234 "\"session_id\":\"%s\""
\r
1236 "\"request_id\":\"%lld\","
\r
1237 "\"requesting_device_id\":\"%s\""
\r
1243 client->deviceId);
\r
1246 MatrixClientSendToDevice(client,
\r
1250 "m.room_key_request");
\r
1256 MatrixClientGetOlmSessionIn(
\r
1257 MatrixClient * client,
\r
1258 const char * userId,
\r
1259 const char * deviceId,
\r
1260 MatrixOlmSession ** outSession)
\r
1262 for (int i = 0; i < client->numOlmSessions; i++)
\r
1264 if (strcmp(client->olmSessions[i].deviceId, deviceId) == 0)
\r
1266 *outSession = &client->olmSessions[i];
\r
1275 MatrixClientNewOlmSessionIn(
\r
1276 MatrixClient * client,
\r
1277 const char * userId,
\r
1278 const char * deviceId,
\r
1279 const char * encrypted,
\r
1280 MatrixOlmSession ** outSession)
\r
1282 if (client->numOlmSessions < NUM_OLM_SESSIONS)
\r
1284 STATIC char deviceKey[DEVICE_KEY_SIZE];
\r
1285 MatrixClientRequestDeviceKey(client,
\r
1287 deviceKey, DEVICE_KEY_SIZE);
\r
1289 MatrixOlmSessionFrom(
\r
1290 &client->olmSessions[client->numOlmSessions],
\r
1291 client->olmAccount.account,
\r
1296 *outSession = &client->olmSessions[client->numOlmSessions];
\r
1298 client->numOlmSessions++;
\r
1307 MatrixClientGetOlmSessionOut(
\r
1308 MatrixClient * client,
\r
1309 const char * userId,
\r
1310 const char * deviceId,
\r
1311 MatrixOlmSession ** outSession)
\r
1313 for (int i = 0; i < client->numOlmSessions; i++)
\r
1315 if (strcmp(client->olmSessions[i].deviceId, deviceId) == 0)
\r
1317 *outSession = &client->olmSessions[i];
\r
1326 MatrixClientNewOlmSessionOut(
\r
1327 MatrixClient * client,
\r
1328 const char * userId,
\r
1329 const char * deviceId,
\r
1330 MatrixOlmSession ** outSession)
\r
1332 if (client->numOlmSessions < NUM_OLM_SESSIONS)
\r
1334 STATIC char deviceKey[DEVICE_KEY_SIZE];
\r
1335 MatrixClientRequestDeviceKey(client,
\r
1337 deviceKey, DEVICE_KEY_SIZE);
\r
1339 char onetimeKey[ONETIME_KEY_SIZE];
\r
1340 MatrixClientClaimOnetimeKey(client,
\r
1343 onetimeKey, ONETIME_KEY_SIZE);
\r
1345 MatrixOlmSessionTo(
\r
1346 &client->olmSessions[client->numOlmSessions],
\r
1347 client->olmAccount.account,
\r
1352 *outSession = &client->olmSessions[client->numOlmSessions];
\r
1354 client->numOlmSessions++;
\r
1362 // https://spec.matrix.org/v1.6/client-server-api/#put_matrixclientv3sendtodeviceeventtypetxnid
\r
1364 MatrixClientSendToDevice(
\r
1365 MatrixClient * client,
\r
1366 const char * userId,
\r
1367 const char * deviceId,
\r
1368 const char * message,
\r
1369 const char * msgType)
\r
1371 STATIC char requestUrl[MAX_URL_LEN];
\r
1372 sprintf(requestUrl,
\r
1373 TODEVICE_URL, msgType, (int)time(NULL));
\r
1375 STATIC char eventBuffer[TODEVICE_EVENT_SIZE];
\r
1376 snprintf(eventBuffer, TODEVICE_EVENT_SIZE,
\r
1388 STATIC char responseBuffer[ROOM_SEND_RESPONSE_SIZE];
\r
1390 MatrixHttpPut(client->hc,
\r
1393 responseBuffer, ROOM_SEND_RESPONSE_SIZE,
\r
1396 printf("%s\n", responseBuffer);
\r
1402 MatrixClientSendToDeviceEncrypted(
\r
1403 MatrixClient * client,
\r
1404 const char * userId,
\r
1405 const char * deviceId,
\r
1406 const char * message,
\r
1407 const char * msgType)
\r
1409 // get olm session
\r
1410 MatrixOlmSession * olmSession;
\r
1411 if (! MatrixClientGetOlmSessionOut(client, userId, deviceId, &olmSession))
\r
1412 MatrixClientNewOlmSessionOut(client, userId, deviceId, &olmSession);
\r
1414 // create event json
\r
1415 char targetDeviceKey[DEVICE_KEY_SIZE];
\r
1416 MatrixClientRequestDeviceKey(client, deviceId, targetDeviceKey, DEVICE_KEY_SIZE);
\r
1417 char targetSigningKey[SIGNING_KEY_SIZE];
\r
1418 MatrixClientRequestSigningKey(client, deviceId, targetSigningKey, SIGNING_KEY_SIZE);
\r
1420 char thisSigningKey[DEVICE_KEY_SIZE];
\r
1421 MatrixOlmAccountGetSigningKey(&client->olmAccount, thisSigningKey, DEVICE_KEY_SIZE);
\r
1423 STATIC char eventBuffer[TODEVICE_EVENT_SIZE];
\r
1424 sprintf(eventBuffer,
\r
1426 "\"type\":\"%s\","
\r
1428 "\"sender\":\"%s\","
\r
1429 "\"recipient\":\"%s\","
\r
1430 "\"recipient_keys\":{"
\r
1431 "\"ed25519\":\"%s\""
\r
1434 "\"ed25519\":\"%s\""
\r
1440 userId, // recipient user id
\r
1441 targetSigningKey, // recipient device key
\r
1445 STATIC char encryptedBuffer[ENCRYPTED_REQUEST_SIZE];
\r
1446 MatrixOlmSessionEncrypt(olmSession,
\r
1448 encryptedBuffer, ENCRYPTED_REQUEST_SIZE);
\r
1450 char thisDeviceKey[DEVICE_KEY_SIZE];
\r
1451 MatrixOlmAccountGetDeviceKey(&client->olmAccount, thisDeviceKey, DEVICE_KEY_SIZE);
\r
1454 STATIC char encryptedEventBuffer[ENCRYPTED_EVENT_SIZE];
\r
1455 sprintf(encryptedEventBuffer,
\r
1457 "\"algorithm\":\"m.olm.v1.curve25519-aes-sha2\","
\r
1458 "\"ciphertext\":{"
\r
1460 "\"body\":\"%s\","
\r
1464 "\"device_id\":\"%s\","
\r
1465 "\"sender_key\":\"%s\""
\r
1469 olm_session_has_received_message(olmSession->session),
\r
1474 return MatrixClientSendToDevice(
\r
1478 encryptedEventBuffer,
\r
1479 "m.room.encrypted");
\r
1483 MatrixClientSendDummy(
\r
1484 MatrixClient * client,
\r
1485 const char * userId,
\r
1486 const char * deviceId)
\r
1488 return MatrixClientSendToDeviceEncrypted(
\r
1497 MatrixClientFindDevice(
\r
1498 MatrixClient * client,
\r
1499 const char * deviceId,
\r
1500 MatrixDevice ** outDevice)
\r
1502 MatrixClientRequestDeviceKeys(client);
\r
1504 for (int i = 0; i < client->numDevices; i++)
\r
1506 if (strcmp(client->devices[i].deviceId, deviceId) == 0)
\r
1508 *outDevice = &client->devices[i];
\r
1513 *outDevice = NULL;
\r
1518 MatrixClientRequestDeviceKey(
\r
1519 MatrixClient * client,
\r
1520 const char * deviceId,
\r
1521 char * outDeviceKey, int outDeviceKeyCap)
\r
1523 MatrixDevice * device;
\r
1525 if (MatrixClientFindDevice(client, deviceId, &device))
\r
1527 strncpy(outDeviceKey, device->deviceKey, outDeviceKeyCap);
\r
1531 MatrixClientRequestDeviceKeys(client);
\r
1533 if (MatrixClientFindDevice(client, deviceId, &device))
\r
1535 strncpy(outDeviceKey, device->deviceKey, outDeviceKeyCap);
\r
1543 MatrixClientRequestSigningKey(
\r
1544 MatrixClient * client,
\r
1545 const char * deviceId,
\r
1546 char * outSigningKey, int outSigningKeyCap)
\r
1548 MatrixDevice * device;
\r
1550 if (MatrixClientFindDevice(client, deviceId, &device))
\r
1552 strncpy(outSigningKey, device->signingKey, outSigningKeyCap);
\r
1556 MatrixClientRequestDeviceKeys(client);
\r
1558 if (MatrixClientFindDevice(client, deviceId, &device))
\r
1560 strncpy(outSigningKey, device->signingKey, outSigningKeyCap);
\r
1567 // https://spec.matrix.org/v1.6/client-server-api/#post_matrixclientv3keysquery
\r
1569 MatrixClientRequestDeviceKeys(
\r
1570 MatrixClient * client)
\r
1572 if (client->numDevices >= NUM_DEVICES) {
\r
1573 printf("Maximum number of devices reached\n");
\r
1577 STATIC char userIdEscaped[USER_ID_SIZE];
\r
1578 JsonEscape(client->userId, strlen(client->userId),
\r
1579 userIdEscaped, USER_ID_SIZE);
\r
1581 STATIC char request[KEYS_QUERY_REQUEST_SIZE];
\r
1582 snprintf(request, KEYS_QUERY_REQUEST_SIZE,
\r
1583 "{\"device_keys\":{\"%s\":[]}}", client->userId);
\r
1585 STATIC char responseBuffer[KEYS_QUERY_RESPONSE_SIZE];
\r
1586 bool requestResult = MatrixHttpPost(client->hc,
\r
1589 responseBuffer, KEYS_QUERY_RESPONSE_SIZE,
\r
1592 if (! requestResult)
\r
1595 // query for retrieving device keys for user id
\r
1596 STATIC char query[JSON_QUERY_SIZE];
\r
1597 snprintf(query, JSON_QUERY_SIZE,
\r
1598 "$.device_keys.%s", userIdEscaped);
\r
1602 mjson_find(responseBuffer, strlen(responseBuffer),
\r
1603 query, &s, &slen);
\r
1607 int koff, klen, voff, vlen, vtype, off = 0;
\r
1608 for (off = 0; (off = mjson_next(s, slen, off, &koff, &klen,
\r
1609 &voff, &vlen, &vtype)) != 0; ) {
\r
1610 const char * key = s + koff;
\r
1611 const char * val = s + voff;
\r
1613 // set device id, "key" is the JSON key
\r
1615 snprintf(d.deviceId, DEVICE_ID_SIZE,
\r
1616 "%.*s", klen-2, key+1);
\r
1618 // look for device key in value
\r
1619 STATIC char deviceKeyQuery[JSON_QUERY_SIZE];
\r
1620 snprintf(deviceKeyQuery, JSON_QUERY_SIZE,
\r
1621 "$.keys.curve25519:%s", d.deviceId);
\r
1622 mjson_get_string(val, vlen,
\r
1623 deviceKeyQuery, d.deviceKey, DEVICE_KEY_SIZE);
\r
1625 // look for signing key in value
\r
1626 STATIC char signingKeyQuery[JSON_QUERY_SIZE];
\r
1627 snprintf(signingKeyQuery, JSON_QUERY_SIZE,
\r
1628 "$.keys.ed25519:%s", d.deviceId);
\r
1629 mjson_get_string(val, vlen,
\r
1630 signingKeyQuery, d.signingKey, SIGNING_KEY_SIZE);
\r
1633 if (client->numDevices < NUM_DEVICES)
\r
1635 bool foundDevice = false;
\r
1636 for (int i = 0; i < client->numDevices; i++)
\r
1637 if (strcmp(client->devices[i].deviceId, d.deviceId) == 0)
\r
1638 foundDevice = true;
\r
1640 if (! foundDevice) {
\r
1641 printf("new device: %s %s %s\n", d.deviceId, d.deviceKey, d.signingKey);
\r
1642 client->devices[client->numDevices] = d;
\r
1643 client->numDevices++;
\r
1656 MatrixClientDeleteDevice(
\r
1657 MatrixClient * client)
\r
1659 STATIC char deleteRequest[1024];
\r
1660 snprintf(deleteRequest, 1024,
\r
1661 "{\"devices\":[\"%s\"]}",
\r
1662 client->deviceId);
\r
1663 STATIC char deleteResponse[1024];
\r
1664 bool res = MatrixHttpPost(client->hc, "/_matrix/client/v3/delete_devices",
\r
1665 deleteRequest, deleteResponse, 1024, true);
\r