8 #define LOGIN_REQUEST_SIZE 1024
\r
9 #define LOGIN_RESPONSE_SIZE 1024
\r
10 #define LOGIN_URL "/_matrix/client/v3/login"
\r
12 #define ENCRYPTED_REQUEST_SIZE 512
\r
13 #define ENCRYPTED_EVENT_SIZE 1024
\r
14 #define ROOMEVENT_REQUEST_SIZE 256
\r
15 #define ROOMEVENT_RESPONSE_SIZE 1024
\r
16 #define ROOMEVENT_URL "/_matrix/client/v3/rooms/%s/send/%s/%d"
\r
18 #define TODEVICE_EVENT_SIZE 512
\r
19 #define TODEVICE_URL "/_matrix/client/v3/sendToDevice/%s/%d"
\r
21 #define KEYS_QUERY_URL "/_matrix/client/v3/keys/query"
\r
22 #define KEYS_QUERY_REQUEST_SIZE 256
\r
23 #define KEYS_QUERY_RESPONSE_SIZE 1024
\r
25 #define KEYS_UPLOAD_URL "/_matrix/client/v3/keys/upload"
\r
26 #define KEYS_UPLOAD_REQUEST_SIZE 1024
\r
27 #define KEYS_UPLOAD_REQUEST_SIGNED_SIZE 2048
\r
28 #define KEYS_UPLOAD_RESPONSE_SIZE 2048
\r
30 #define JSON_QUERY_SIZE 128
\r
39 static bool first = false;
\r
40 if (first) { srand(time(0)); first = false; }
\r
42 for (int i = 0; i < randomLen; i++)
\r
44 random[i] = rand() % 256;
\r
50 char * sIn, int sInLen,
\r
51 char * sOut, int sOutCap)
\r
55 for (int i = 0; i < sInLen; i++)
\r
60 if (sIn[i] == '.' ||
\r
64 sOut[sOutIndex++] = '\\';
\r
66 sOut[sOutIndex++] = sIn[i];
\r
69 if (sOutIndex < sOutCap)
\r
70 sOut[sOutIndex] = '\0';
\r
76 MatrixClient * client,
\r
77 char * sIn, int sInLen,
\r
78 char * sOut, int sOutCap)
\r
80 static char signature[OLM_SIGNATURE_SIZE];
\r
82 olm_account_sign(client->olmAccount.account,
\r
84 signature, OLM_SIGNATURE_SIZE);
\r
86 int signatureLen = res;
\r
88 static char signatureJson[JSON_SIGNATURE_SIZE];
\r
89 int signatureJsonLen =
\r
90 mjson_snprintf(signatureJson, JSON_SIGNATURE_SIZE,
\r
94 "\"ed25519:%s\":\"%.*s\""
\r
100 signatureLen, signature);
\r
102 struct mjson_fixedbuf result = { sOut, sOutCap, 0 };
\r
105 signatureJson, signatureJsonLen,
\r
106 mjson_print_fixed_buf,
\r
114 MatrixOlmAccountInit(
\r
115 MatrixOlmAccount * account)
\r
117 account->account = olm_account(account->memory);
\r
119 static uint8_t random[OLM_ACCOUNT_RANDOM_SIZE];
\r
120 Randomize(random, OLM_ACCOUNT_RANDOM_SIZE);
\r
122 size_t res = olm_create_account(
\r
125 OLM_ACCOUNT_RANDOM_SIZE);
\r
127 return res != olm_error();
\r
130 // TODO: in/outbound sessions
\r
132 MatrixOlmSessionInit(
\r
133 MatrixOlmSession * session,
\r
134 const char * deviceId)
\r
136 memset(session, 0, sizeof(MatrixOlmSession));
\r
138 static uint8_t random[MEGOLM_INIT_RANDOM_SIZE];
\r
139 Randomize(random, MEGOLM_INIT_RANDOM_SIZE);
\r
141 session->deviceId = deviceId;
\r
144 olm_session(session->memory);
\r
146 return session->session != NULL;
\r
150 MatrixOlmSessionEncrypt(
\r
151 MatrixOlmSession * session,
\r
152 const char * plaintext,
\r
153 char * outBuffer, int outBufferCap)
\r
155 static uint8_t random[OLM_ENCRYPT_RANDOM_SIZE];
\r
156 Randomize(random, OLM_ENCRYPT_RANDOM_SIZE);
\r
158 size_t res = olm_encrypt(session->session,
\r
159 plaintext, strlen(plaintext),
\r
160 random, OLM_ENCRYPT_RANDOM_SIZE,
\r
161 outBuffer, outBufferCap);
\r
163 return res != olm_error();
\r
166 // https://matrix.org/docs/guides/end-to-end-encryption-implementation-guide#starting-a-megolm-session
\r
168 MatrixMegolmOutSessionInit(
\r
169 MatrixMegolmOutSession * session,
\r
170 const char * roomId)
\r
172 memset(session, 0, sizeof(MatrixMegolmOutSession));
\r
174 static uint8_t random[MEGOLM_INIT_RANDOM_SIZE];
\r
175 Randomize(random, MEGOLM_INIT_RANDOM_SIZE);
\r
177 session->roomId = roomId;
\r
180 olm_outbound_group_session(session->memory);
\r
182 olm_init_outbound_group_session(
\r
185 MEGOLM_INIT_RANDOM_SIZE);
\r
187 olm_outbound_group_session_id(session->session,
\r
188 (uint8_t *)session->id,
\r
189 MEGOLM_SESSION_ID_SIZE);
\r
191 olm_outbound_group_session_key(session->session,
\r
192 (uint8_t *)session->key,
\r
193 MEGOLM_SESSION_KEY_SIZE);
\r
199 MatrixMegolmOutSessionEncrypt(
\r
200 MatrixMegolmOutSession * session,
\r
201 const char * plaintext,
\r
202 char * outBuffer, int outBufferCap)
\r
204 size_t res = olm_group_encrypt(session->session,
\r
205 (uint8_t *)plaintext, strlen(plaintext),
\r
206 (uint8_t *)outBuffer, outBufferCap);
\r
208 return res != olm_error();
\r
215 MatrixClient * client,
\r
216 const char * server)
\r
218 memset(client, 0, sizeof(MatrixClient));
\r
220 strcpy(client->server, server);
\r
222 // init olm account
\r
223 MatrixOlmAccountInit(&client->olmAccount);
\r
226 static char deviceKeysJson[OLM_IDENTITY_KEYS_JSON_SIZE];
\r
228 olm_account_identity_keys(
\r
229 client->olmAccount.account,
\r
231 OLM_IDENTITY_KEYS_JSON_SIZE);
\r
233 mjson_get_string(deviceKeysJson, res,
\r
235 client->deviceKey, DEVICE_KEY_SIZE);
\r
236 mjson_get_string(deviceKeysJson, res,
\r
238 client->signingKey, SIGNING_KEY_SIZE);
\r
244 MatrixClientSetAccessToken(
\r
245 MatrixClient * client,
\r
246 const char * accessToken)
\r
248 int accessTokenLen = strlen(accessToken);
\r
250 if (accessTokenLen > ACCESS_TOKEN_SIZE - 1)
\r
253 for (int i = 0; i < accessTokenLen; i++)
\r
254 client->accessToken[i] = accessToken[i];
\r
260 MatrixClientSetDeviceId(
\r
261 MatrixClient * client,
\r
262 const char * deviceId)
\r
264 int deviceIdLen = strlen(deviceId);
\r
266 if (deviceIdLen > DEVICE_ID_SIZE - 1)
\r
269 for (int i = 0; i < deviceIdLen; i++)
\r
270 client->deviceId[i] = deviceId[i];
\r
276 MatrixClientSetUserId(
\r
277 MatrixClient * client,
\r
278 const char * userId)
\r
280 int userIdLen = strlen(userId);
\r
282 if (userIdLen > USER_ID_SIZE - 1)
\r
285 for (int i = 0; i < userIdLen; i++)
\r
286 client->userId[i] = userId[i];
\r
292 MatrixClientGenerateOnetimeKeys(
\r
293 MatrixClient * client,
\r
296 static uint8_t random[OLM_ONETIME_KEYS_RANDOM_SIZE];
\r
297 Randomize(random, OLM_ONETIME_KEYS_RANDOM_SIZE);
\r
300 olm_account_generate_one_time_keys(client->olmAccount.account,
\r
301 numberOfKeys, random, OLM_ONETIME_KEYS_RANDOM_SIZE);
\r
303 return res != olm_error();
\r
306 // https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv3keysupload
\r
308 MatrixClientUploadOnetimeKeys(
\r
309 MatrixClient * client)
\r
311 static char requestBuffer[KEYS_UPLOAD_REQUEST_SIZE];
\r
313 mjson_snprintf(requestBuffer, KEYS_UPLOAD_REQUEST_SIZE,
\r
314 "{\"one_time_keys\":{");
\r
316 static char onetimeKeysBuffer[1024];
\r
317 olm_account_one_time_keys(client->olmAccount.account,
\r
318 onetimeKeysBuffer, 1024);
\r
322 mjson_find(onetimeKeysBuffer, strlen(onetimeKeysBuffer), "$.curve25519", &keys, &keysLen);
\r
324 int koff, klen, voff, vlen, vtype, off = 0;
\r
325 while ((off = mjson_next(keys, keysLen, off, &koff, &klen, &voff, &vlen, &vtype)) != 0) {
\r
326 static char keyJson[JSON_ONETIME_KEY_SIZE];
\r
328 snprintf(keyJson, JSON_ONETIME_KEY_SIZE,
\r
329 "{\"key\":\"%.*s\"}",
\r
330 vlen-2, keys + voff+1);
\r
332 static char keyJsonSigned[JSON_ONETIME_KEY_SIGNED_SIZE];
\r
335 keyJson, JSON_ONETIME_KEY_SIZE,
\r
336 keyJsonSigned, JSON_ONETIME_KEY_SIGNED_SIZE);
\r
338 mjson_snprintf(requestBuffer+strlen(requestBuffer), KEYS_UPLOAD_REQUEST_SIZE-strlen(requestBuffer),
\r
339 "\"signed_curve25519:%.*s\":%s,",
\r
340 klen-2, keys + koff+1,
\r
344 mjson_snprintf(requestBuffer+strlen(requestBuffer)-1, KEYS_UPLOAD_REQUEST_SIZE-strlen(requestBuffer),
\r
347 static char responseBuffer[KEYS_UPLOAD_RESPONSE_SIZE];
\r
348 MatrixHttpPost(client,
\r
351 responseBuffer, KEYS_UPLOAD_RESPONSE_SIZE,
\r
357 // https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv3keysupload
\r
359 MatrixClientUploadDeviceKeys(
\r
360 MatrixClient * client)
\r
362 static char deviceKeysBuffer[KEYS_UPLOAD_REQUEST_SIZE];
\r
364 mjson_snprintf(deviceKeysBuffer, KEYS_UPLOAD_REQUEST_SIZE,
\r
365 "{\"device_keys\":{"
\r
366 "\"algorithms\":[\"m.olm.v1.curve25519-aes-sha2\",\"m.megolm.v1.aes-sha2\"],"
\r
367 "\"device_id\":\"%s\","
\r
369 "\"curve25519:%s\":\"%s\","
\r
370 "\"ed25519:%s\":\"%s\""
\r
372 "\"user_id\":\"%s\""
\r
375 client->deviceId, client->deviceKey,
\r
376 client->deviceId, client->signingKey,
\r
379 static char deviceKeysSignedBuffer[KEYS_UPLOAD_REQUEST_SIGNED_SIZE];
\r
381 deviceKeysBuffer, KEYS_UPLOAD_REQUEST_SIZE,
\r
382 deviceKeysSignedBuffer, KEYS_UPLOAD_REQUEST_SIZE);
\r
385 static char responseBuffer[KEYS_UPLOAD_RESPONSE_SIZE];
\r
386 MatrixHttpPost(client,
\r
388 deviceKeysSignedBuffer,
\r
389 responseBuffer, KEYS_UPLOAD_RESPONSE_SIZE,
\r
395 // https://spec.matrix.org/v1.6/client-server-api/#post_matrixclientv3login
\r
397 MatrixClientLoginPassword(
\r
398 MatrixClient * client,
\r
399 const char * username,
\r
400 const char * password,
\r
401 const char * displayName)
\r
403 static char requestBuffer[LOGIN_REQUEST_SIZE];
\r
405 mjson_snprintf(requestBuffer, LOGIN_REQUEST_SIZE,
\r
407 "\"type\": \"m.login.password\","
\r
408 "\"identifier\": {"
\r
409 "\"type\": \"m.id.user\","
\r
412 "\"password\": \"%s\","
\r
413 "\"initial_device_display_name\": \"%s\""
\r
419 static char responseBuffer[LOGIN_RESPONSE_SIZE];
\r
421 MatrixHttpPost(client,
\r
424 responseBuffer, LOGIN_RESPONSE_SIZE,
\r
427 int responseLen = strlen(responseBuffer);
\r
432 mjson_get_string(responseBuffer, responseLen,
\r
434 client->accessToken, ACCESS_TOKEN_SIZE);
\r
435 mjson_get_string(responseBuffer, responseLen,
\r
437 client->deviceId, DEVICE_ID_SIZE);
\r
438 mjson_get_string(responseBuffer, responseLen,
\r
440 client->expireMs, EXPIRE_MS_SIZE);
\r
441 mjson_get_string(responseBuffer, responseLen,
\r
443 client->refreshToken, REFRESH_TOKEN_SIZE);
\r
448 // https://spec.matrix.org/v1.6/client-server-api/#put_matrixclientv3roomsroomidsendeventtypetxnid
\r
450 MatrixClientSendEvent(
\r
451 MatrixClient * client,
\r
452 const char * roomId,
\r
453 const char * msgType,
\r
454 const char * msgBody)
\r
456 static char requestUrl[MAX_URL_LEN];
\r
457 sprintf(requestUrl,
\r
458 ROOMEVENT_URL, roomId, msgType, (int)time(NULL));
\r
460 static char responseBuffer[ROOMEVENT_RESPONSE_SIZE];
\r
462 MatrixHttpPut(client,
\r
465 responseBuffer, ROOMEVENT_RESPONSE_SIZE,
\r
471 // https://spec.matrix.org/v1.6/client-server-api/#mroomencrypted
\r
472 // https://matrix.org/docs/guides/end-to-end-encryption-implementation-guide#sending-an-encrypted-message-event
\r
474 MatrixClientSendEventEncrypted(
\r
475 MatrixClient * client,
\r
476 const char * roomId,
\r
477 const char * msgType,
\r
478 const char * msgBody)
\r
481 static char requestBuffer[ROOMEVENT_REQUEST_SIZE];
\r
482 sprintf(requestBuffer,
\r
486 "\"room_id\":\"%s\""
\r
492 // get megolm session
\r
493 MatrixMegolmOutSession * outSession;
\r
494 MatrixClientGetMegolmOutSession(client, roomId, &outSession);
\r
497 static char encryptedBuffer[ENCRYPTED_REQUEST_SIZE];
\r
498 MatrixMegolmOutSessionEncrypt(outSession,
\r
500 encryptedBuffer, ENCRYPTED_REQUEST_SIZE);
\r
502 // encrypted event json
\r
503 const char * senderKey = client->deviceKey;
\r
504 const char * sessionId = outSession->id;
\r
505 const char * deviceId = client->deviceId;
\r
507 static char encryptedEventBuffer[ENCRYPTED_EVENT_SIZE];
\r
508 sprintf(encryptedEventBuffer,
\r
510 "\"algorithm\":\"m.megolm.v1.aes-sha2\","
\r
511 "\"sender_key\":\"%s\","
\r
512 "\"ciphertext\":\"%s\","
\r
513 "\"session_id\":\"%s\","
\r
514 "\"device_id\":\"%s\""
\r
522 return MatrixClientSendEvent(client,
\r
524 "m.room.encrypted",
\r
525 encryptedEventBuffer);
\r
528 // https://spec.matrix.org/v1.6/client-server-api/#get_matrixclientv3sync
\r
531 MatrixClient * client,
\r
532 char * outSyncBuffer, int outSyncCap)
\r
535 MatrixHttpGet(client,
\r
536 "/_matrix/client/v3/sync",
\r
537 outSyncBuffer, outSyncCap,
\r
542 MatrixClientShareMegolmOutSession(
\r
543 MatrixClient * client,
\r
544 const char * deviceId,
\r
545 MatrixMegolmOutSession * session)
\r
547 // generate room key event
\r
548 char eventBuffer[KEY_SHARE_EVENT_LEN];
\r
549 sprintf(eventBuffer,
\r
551 "\"algorithm\":\"m.megolm.v1.aes-sha2\","
\r
552 "\"room_id\":\"%s\","
\r
553 "\"session_id\":\"%s\","
\r
554 "\"session_key\":\"%s\""
\r
562 MatrixOlmSession * olmSession;
\r
563 MatrixClientGetOlmSession(client, deviceId, &olmSession);
\r
566 char encryptedBuffer[KEY_SHARE_EVENT_LEN];
\r
567 MatrixOlmSessionEncrypt(olmSession,
\r
569 encryptedBuffer, KEY_SHARE_EVENT_LEN);
\r
572 MatrixClientSendToDeviceEncrypted(client,
\r
582 MatrixClientShareMegolmOutSessionTest(
\r
583 MatrixClient * client,
\r
584 const char * deviceId,
\r
585 MatrixMegolmOutSession * session)
\r
587 // generate room key event
\r
588 char eventBuffer[KEY_SHARE_EVENT_LEN];
\r
589 sprintf(eventBuffer,
\r
591 "\"algorithm\":\"m.megolm.v1.aes-sha2\","
\r
592 "\"room_id\":\"%s\","
\r
593 "\"session_id\":\"%s\","
\r
594 "\"session_key\":\"%s\""
\r
602 MatrixClientSendToDevice(client,
\r
612 // MatrixClientSetMegolmOutSession(
\r
613 // MatrixClient * client,
\r
614 // const char * roomId,
\r
615 // MatrixMegolmOutSession session)
\r
617 // if (client->numMegolmOutSessions < 10)
\r
619 // session.roomId = roomId;
\r
620 // client->megolmOutSessions[client->numMegolmOutSessions] = session;
\r
621 // client->numMegolmOutSessions++;
\r
629 MatrixClientGetMegolmOutSession(
\r
630 MatrixClient * client,
\r
631 const char * roomId,
\r
632 MatrixMegolmOutSession ** outSession)
\r
634 for (int i = 0; i < client->numMegolmOutSessions; i++)
\r
636 if (strcmp(client->megolmOutSessions[i].roomId, roomId) == 0)
\r
638 *outSession = &client->megolmOutSessions[i];
\r
643 if (client->numMegolmOutSessions < NUM_MEGOLM_SESSIONS)
\r
645 MatrixMegolmOutSessionInit(
\r
646 &client->megolmOutSessions[client->numMegolmOutSessions],
\r
649 *outSession = &client->megolmOutSessions[client->numMegolmOutSessions];
\r
651 client->numMegolmOutSessions++;
\r
660 MatrixClientGetOlmSession(
\r
661 MatrixClient * client,
\r
662 const char * deviceId,
\r
663 MatrixOlmSession ** outSession)
\r
665 for (int i = 0; i < client->numOlmSessions; i++)
\r
667 if (strcmp(client->olmSessions[i].deviceId, deviceId) == 0)
\r
669 *outSession = &client->olmSessions[i];
\r
674 if (client->numOlmSessions < NUM_OLM_SESSIONS)
\r
676 MatrixOlmSessionInit(
\r
677 &client->olmSessions[client->numOlmSessions],
\r
680 *outSession = &client->olmSessions[client->numOlmSessions];
\r
682 client->numOlmSessions++;
\r
690 // https://spec.matrix.org/v1.6/client-server-api/#put_matrixclientv3sendtodeviceeventtypetxnid
\r
692 MatrixClientSendToDevice(
\r
693 MatrixClient * client,
\r
694 const char * userId,
\r
695 const char * deviceId,
\r
696 const char * message,
\r
697 const char * msgType)
\r
699 static char requestUrl[MAX_URL_LEN];
\r
700 sprintf(requestUrl,
\r
701 TODEVICE_URL, msgType, (int)time(NULL));
\r
703 static char eventBuffer[TODEVICE_EVENT_SIZE];
\r
704 snprintf(eventBuffer, TODEVICE_EVENT_SIZE,
\r
716 static char responseBuffer[ROOMEVENT_RESPONSE_SIZE];
\r
718 MatrixHttpPut(client,
\r
721 responseBuffer, ROOMEVENT_RESPONSE_SIZE,
\r
728 MatrixClientSendToDeviceEncrypted(
\r
729 MatrixClient * client,
\r
730 const char * userId,
\r
731 const char * deviceId,
\r
732 const char * message,
\r
733 const char * msgType)
\r
736 MatrixOlmSession * olmSession;
\r
737 MatrixClientGetOlmSession(client, deviceId, &olmSession);
\r
739 // create event json
\r
740 char deviceKey[DEVICE_KEY_SIZE];
\r
741 MatrixClientGetDeviceKey(client, deviceId, deviceKey, DEVICE_KEY_SIZE);
\r
742 const char * senderKey = client->deviceKey;
\r
744 static char eventBuffer[TODEVICE_EVENT_SIZE];
\r
745 sprintf(eventBuffer,
\r
747 "\"type\": \"%s\","
\r
748 "\"content\": \"%s\","
\r
749 "\"sender\": \"%s\","
\r
750 "\"recipient\": \"%s\","
\r
751 "\"recipient_keys\": {"
\r
752 "\"ed25519\": \"%s\""
\r
755 "\"ed25519\": \"%s\""
\r
761 userId, // recipient user id
\r
762 deviceKey, // recipient device key
\r
763 client->deviceKey);
\r
766 static char encryptedBuffer[ENCRYPTED_REQUEST_SIZE];
\r
767 MatrixOlmSessionEncrypt(olmSession,
\r
769 encryptedBuffer, ENCRYPTED_REQUEST_SIZE);
\r
771 static char encryptedEventBuffer[ENCRYPTED_EVENT_SIZE];
\r
772 sprintf(encryptedEventBuffer,
\r
774 "\"algorithm\":\"m.megolm.v1.aes-sha2\","
\r
775 "\"sender_key\":\"%s\","
\r
789 return MatrixClientSendToDevice(
\r
793 encryptedEventBuffer,
\r
794 "m.room.encrypted");
\r
798 MatrixClientFindDevice(
\r
799 MatrixClient * client,
\r
800 const char * deviceId,
\r
801 MatrixDevice ** outDevice)
\r
803 MatrixClientRequestDeviceKeys(client);
\r
805 for (int i = 0; i < client->numDevices; i++)
\r
807 if (strcmp(client->devices[i].deviceId, deviceId) == 0)
\r
809 *outDevice = &client->devices[i];
\r
819 MatrixClientGetDeviceKey(
\r
820 MatrixClient * client,
\r
821 const char * deviceId,
\r
822 char * outDeviceKey, int outDeviceKeyCap)
\r
824 MatrixClientRequestDeviceKeys(client);
\r
826 MatrixDevice * device;
\r
827 if (MatrixClientFindDevice(client, deviceId, &device))
\r
829 strncpy(outDeviceKey, device->deviceKey, outDeviceKeyCap);
\r
836 // https://spec.matrix.org/v1.6/client-server-api/#post_matrixclientv3keysquery
\r
838 MatrixClientRequestDeviceKeys(
\r
839 MatrixClient * client)
\r
841 char userIdEscaped[USER_ID_SIZE];
\r
842 JsonEscape(client->userId, strlen(client->userId),
\r
843 userIdEscaped, USER_ID_SIZE);
\r
845 char request[KEYS_QUERY_REQUEST_SIZE];
\r
846 snprintf(request, KEYS_QUERY_REQUEST_SIZE,
\r
847 "{\"device_keys\":{\"%s\":[]}}", userIdEscaped);
\r
849 char responseBuffer[KEYS_QUERY_RESPONSE_SIZE];
\r
850 bool requestResult = MatrixHttpPost(client,
\r
853 responseBuffer, KEYS_QUERY_RESPONSE_SIZE,
\r
858 // query for retrieving device keys for user id
\r
859 char query[JSON_QUERY_SIZE];
\r
860 snprintf(query, JSON_QUERY_SIZE,
\r
861 "$.device_keys.%s", userIdEscaped);
\r
865 mjson_find(responseBuffer, strlen(responseBuffer),
\r
870 int koff, klen, voff, vlen, vtype, off;
\r
871 for (off = 0; (off = mjson_next(s, slen, off, &koff, &klen,
\r
872 &voff, &vlen, &vtype)) != 0; ) {
\r
873 const char * key = s + koff;
\r
874 const char * val = s + voff;
\r
876 // set device id, "key" is the JSON key
\r
878 strncpy(d.deviceId, key, klen);
\r
880 // look for device key in value
\r
881 char deviceKeyQuery[JSON_QUERY_SIZE];
\r
882 snprintf(deviceKeyQuery, JSON_QUERY_SIZE,
\r
883 "$.keys.curve25519:%.*s", klen, key);
\r
884 mjson_get_string(val, vlen,
\r
885 deviceKeyQuery, d.deviceKey, DEVICE_KEY_SIZE);
\r
888 if (client->numDevices < NUM_DEVICES)
\r
890 client->devices[client->numDevices] = d;
\r
891 client->numDevices++;
\r