+JsonCanonicalize(\r
+ const char * sIn, int sInLen,\r
+ char * sOut, int sOutCap)\r
+{\r
+ snprintf(sOut, sOutCap, "{}");\r
+\r
+ int koff, klen, voff, vlen, vtype, off;\r
+\r
+ struct Key {\r
+ const char * ptr;\r
+ int len;\r
+ };\r
+\r
+ struct Key keys[JSON_MAX_INDICES];\r
+ int numKeys = 0;\r
+\r
+ for (off = 0; (off = mjson_next(sIn, sInLen, off, &koff, &klen, &voff, &vlen, &vtype)) != 0; ) {\r
+ keys[numKeys].ptr = sIn + koff;\r
+ keys[numKeys].len = klen;\r
+ numKeys++;\r
+ }\r
+\r
+ for (int i = 0; i < numKeys; i++) {\r
+ for (int j = i; j < numKeys; j++) {\r
+ if (\r
+ strncmp(\r
+ keys[i].ptr,\r
+ keys[j].ptr,\r
+ MIN(keys[i].len, keys[j].len)\r
+ ) > 0\r
+ ) {\r
+ struct Key k = keys[i];\r
+ keys[i] = keys[j];\r
+ keys[j] = k;\r
+ }\r
+ }\r
+ }\r
+\r
+ for (int i = 0; i < numKeys; i++) {\r
+ char jp[JSON_QUERY_SIZE];\r
+ snprintf(jp, JSON_QUERY_SIZE, "$.%.*s", keys[i].len-2, keys[i].ptr+1);\r
+\r
+ const char * valPtr;\r
+ int valLen;\r
+ mjson_find(sIn, sInLen, jp, &valPtr, &valLen);\r
+ \r
+ STATIC char newEntry[JSON_MAX_ENTRY_SIZE];\r
+ snprintf(newEntry, JSON_MAX_ENTRY_SIZE, "{%.*s:%.*s}", keys[i].len, keys[i].ptr, valLen, valPtr);\r
+\r
+ char * buffer = strdup(sOut);\r
+\r
+ struct mjson_fixedbuf fb = { sOut, sOutCap, 0 };\r
+ mjson_merge(buffer, strlen(buffer), newEntry, strlen(newEntry), mjson_print_fixed_buf, &fb);\r
+\r
+ free(buffer);\r
+ }\r
+\r
+ // TODO: recursively sort entries\r
+\r
+ return true;\r
+}\r
+\r
+bool JsonSign(\r
+ MatrixClient * client,\r
+ const char * sIn, int sInLen,\r
+ char * sOut, int sOutCap)\r
+{\r
+ STATIC char signature[OLM_SIGNATURE_SIZE];\r
+ size_t res =\r
+ olm_account_sign(client->olmAccount.account,\r
+ sIn, sInLen,\r
+ signature, OLM_SIGNATURE_SIZE);\r
+ \r
+ int signatureLen = res;\r
+ \r
+ STATIC char thisSigningKey[SIGNING_KEY_SIZE];\r
+ MatrixOlmAccountGetSigningKey(&client->olmAccount, thisSigningKey, SIGNING_KEY_SIZE);\r
+\r
+ STATIC char signatureJson[JSON_SIGNATURE_SIZE];\r
+ int signatureJsonLen =\r
+ mjson_snprintf(signatureJson, JSON_SIGNATURE_SIZE,\r
+ "{"\r
+ "\"signatures\":{"\r
+ "\"%s\":{"\r
+ "\"ed25519:%s\":\"%.*s\""\r
+ "}"\r
+ "}"\r
+ "}",\r
+ client->userId,\r
+ //"1",\r
+ client->deviceId,\r
+ signatureLen, signature);\r
+\r
+ struct mjson_fixedbuf result = { sOut, sOutCap, 0 };\r
+ mjson_merge(\r
+ sIn, sInLen,\r
+ signatureJson, signatureJsonLen,\r
+ mjson_print_fixed_buf,\r
+ &result);\r
+\r
+ return true;\r
+}\r
+\r
+\r
+bool\r
+MatrixOlmAccountInit(\r
+ MatrixOlmAccount * account)\r
+{\r
+ account->account = olm_account(account->memory);\r
+\r
+ STATIC uint8_t random[OLM_ACCOUNT_RANDOM_SIZE];\r
+ Randomize(random, OLM_ACCOUNT_RANDOM_SIZE);\r
+\r
+ size_t res = olm_create_account(\r
+ account->account,\r
+ random,\r
+ OLM_ACCOUNT_RANDOM_SIZE);\r
+\r
+ return res != olm_error();\r
+}\r
+\r
+bool\r
+MatrixOlmAccountUnpickle(\r
+ MatrixOlmAccount * account,\r
+ void * pickled, int pickledLen,\r
+ const void * key, int keyLen)\r
+{\r
+ size_t res;\r
+ res = olm_unpickle_account(account->account,\r
+ key, keyLen,\r
+ pickled, pickledLen);\r
+ if (res == olm_error()) {\r
+ printf("error unpickling olm account:%s\n",\r
+ olm_account_last_error(account->account));\r
+ }\r
+ return res != olm_error();\r
+}\r
+\r
+bool\r
+MatrixOlmAccountGetDeviceKey(\r
+ MatrixOlmAccount * account,\r
+ char * key, int keyCap)\r
+{\r
+ STATIC char deviceKeysJson[OLM_IDENTITY_KEYS_JSON_SIZE];\r
+ size_t res =\r
+ olm_account_identity_keys(account->account,\r
+ deviceKeysJson, OLM_IDENTITY_KEYS_JSON_SIZE);\r
+ mjson_get_string(deviceKeysJson, res,\r
+ "$.curve25519",\r
+ key, keyCap);\r
+ return true;\r
+}\r
+\r
+bool\r
+MatrixOlmAccountGetSigningKey(\r
+ MatrixOlmAccount * account,\r
+ char * key, int keyCap)\r
+{\r
+ STATIC char deviceKeysJson[OLM_IDENTITY_KEYS_JSON_SIZE];\r
+ size_t res =\r
+ olm_account_identity_keys(account->account,\r
+ deviceKeysJson, OLM_IDENTITY_KEYS_JSON_SIZE);\r
+ mjson_get_string(deviceKeysJson, res,\r
+ "$.ed25519",\r
+ key, keyCap);\r
+ return true;\r
+}\r
+\r
+bool\r
+MatrixOlmSessionFrom(\r