forked from Telodendria/Telodendria
[ADD/WIP] Dumb key management
This is just enough to fool FluffyChat and nheko, and still not enough to actually do proper E2EE. Also, don't use Cinny with it, it seems to repeteadly upload keys. Terrible.
This commit is contained in:
parent
8612aae24c
commit
4b427a4c82
15 changed files with 405 additions and 28 deletions
62
Schema/KeyUpload.json
Normal file
62
Schema/KeyUpload.json
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"guard": "TELODENDRIA_KEY_UPLOAD_H",
|
||||||
|
"header": "Schema/KeyUpload.h",
|
||||||
|
"types": {
|
||||||
|
"DeviceKeys": {
|
||||||
|
"type": "struct",
|
||||||
|
"fields": {
|
||||||
|
"device_id": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"algorithms": {
|
||||||
|
"type": "[string]",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"keys": {
|
||||||
|
"type": "{string}",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"signatures": {
|
||||||
|
"//": "TODO: More complex j2s types.",
|
||||||
|
"//": "This is meant to be a map from user ID to ",
|
||||||
|
"//": "algo+device ID to a signature(string).",
|
||||||
|
"type": "object",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"KeyResponse": {
|
||||||
|
"type": "struct",
|
||||||
|
"fields": {
|
||||||
|
"one_time_key_counts": {
|
||||||
|
"type": "{integer}",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"KeyUploadRequest": {
|
||||||
|
"type": "struct",
|
||||||
|
"fields": {
|
||||||
|
"device_keys": {
|
||||||
|
"type": "DeviceKeys",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"fallback_keys": {
|
||||||
|
"//": "This is a one-time key.",
|
||||||
|
"type": "object",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"one_time_keys": {
|
||||||
|
"//": "This is a one-time key.",
|
||||||
|
"type": "object",
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,6 +38,10 @@
|
||||||
"redacted_because": {
|
"redacted_because": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": false
|
"required": false
|
||||||
|
},
|
||||||
|
"transaction_id": {
|
||||||
|
"type": "string",
|
||||||
|
"required": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
"sender": { "type": "string", "required": true },
|
"sender": { "type": "string", "required": true },
|
||||||
"state_key": { "type": "string" },
|
"state_key": { "type": "string" },
|
||||||
"redacts": { "type": "string" },
|
"redacts": { "type": "string" },
|
||||||
|
"_unsigned": { "type": "object" },
|
||||||
"type": { "type": "string", "required": true }
|
"type": { "type": "string", "required": true }
|
||||||
},
|
},
|
||||||
"type": "struct"
|
"type": "struct"
|
||||||
|
@ -105,6 +106,9 @@
|
||||||
},
|
},
|
||||||
"rooms": {
|
"rooms": {
|
||||||
"type": "Rooms"
|
"type": "Rooms"
|
||||||
|
},
|
||||||
|
"device_one_time_keys_count": {
|
||||||
|
"type": "{integer}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "struct"
|
"type": "struct"
|
||||||
|
|
16
src/Room.c
16
src/Room.c
|
@ -348,6 +348,11 @@ RoomEventFetch(Room *room, char *id, bool prev)
|
||||||
"pdu_status",
|
"pdu_status",
|
||||||
JsonValueDuplicate(HashMapGet(DbJson(event_ref), "status"))
|
JsonValueDuplicate(HashMapGet(DbJson(event_ref), "status"))
|
||||||
));
|
));
|
||||||
|
JsonValueFree(HashMapSet(
|
||||||
|
unsign,
|
||||||
|
"transaction_id",
|
||||||
|
JsonValueDuplicate(HashMapGet(DbJson(event_ref), "transaction"))
|
||||||
|
));
|
||||||
ts = JsonValueAsInteger(HashMapGet(ret, "origin_server_ts"));
|
ts = JsonValueAsInteger(HashMapGet(ret, "origin_server_ts"));
|
||||||
JsonValueFree(HashMapSet(
|
JsonValueFree(HashMapSet(
|
||||||
unsign,
|
unsign,
|
||||||
|
@ -391,7 +396,7 @@ finish:
|
||||||
}
|
}
|
||||||
|
|
||||||
HashMap *
|
HashMap *
|
||||||
RoomEventCreate(char *sender, char *type, char *key, HashMap *c)
|
RoomEventCreate(char *sender, char *type, char *key, HashMap *c, char *txn)
|
||||||
{
|
{
|
||||||
HashMap *event;
|
HashMap *event;
|
||||||
if (!sender || !type || !c)
|
if (!sender || !type || !c)
|
||||||
|
@ -403,6 +408,7 @@ RoomEventCreate(char *sender, char *type, char *key, HashMap *c)
|
||||||
JsonSet(event, JsonValueObject(c), 1, "content");
|
JsonSet(event, JsonValueObject(c), 1, "content");
|
||||||
JsonSet(event, JsonValueString(sender), 1, "sender");
|
JsonSet(event, JsonValueString(sender), 1, "sender");
|
||||||
JsonSet(event, JsonValueString(type), 1, "type");
|
JsonSet(event, JsonValueString(type), 1, "type");
|
||||||
|
JsonSet(event, JsonValueString(txn), 1, "transaction");
|
||||||
if (key)
|
if (key)
|
||||||
{
|
{
|
||||||
JsonSet(event, JsonValueString(key), 1, "state_key");
|
JsonSet(event, JsonValueString(key), 1, "state_key");
|
||||||
|
@ -557,7 +563,7 @@ RoomSendInvite(User *sender, bool direct, char *user, Room *room)
|
||||||
content = HashMapCreate();
|
content = HashMapCreate();
|
||||||
JsonSet(content, JsonValueBoolean(direct), 1, "is_direct");
|
JsonSet(content, JsonValueBoolean(direct), 1, "is_direct");
|
||||||
JsonSet(content, JsonValueString("invite"), 1, "membership");
|
JsonSet(content, JsonValueString("invite"), 1, "membership");
|
||||||
event = RoomEventCreate(senderStr, "m.room.member", user, content);
|
event = RoomEventCreate(senderStr, "m.room.member", user, content, NULL);
|
||||||
JsonFree(RoomEventSend(room, event, NULL));
|
JsonFree(RoomEventSend(room, event, NULL));
|
||||||
JsonFree(event);
|
JsonFree(event);
|
||||||
|
|
||||||
|
@ -692,7 +698,7 @@ RoomLeave(Room *room, User *user, char **errp)
|
||||||
|
|
||||||
content = HashMapCreate();
|
content = HashMapCreate();
|
||||||
JsonSet(content, JsonValueString("leave"), 1, "membership");
|
JsonSet(content, JsonValueString("leave"), 1, "membership");
|
||||||
event = RoomEventCreate(userString, "m.room.member", userString, content);
|
event = RoomEventCreate(userString, "m.room.member", userString, content, NULL);
|
||||||
pdu = RoomEventSend(room, event, errp);
|
pdu = RoomEventSend(room, event, errp);
|
||||||
|
|
||||||
/* TODO: One ought to be extremely careful with managing users in those
|
/* TODO: One ought to be extremely careful with managing users in those
|
||||||
|
@ -756,7 +762,7 @@ RoomRedact(Room *room, User *user, char *eventID, char *reason, char **errp)
|
||||||
HashMapSet(content, "reason", JsonValueString(reason));
|
HashMapSet(content, "reason", JsonValueString(reason));
|
||||||
event = RoomEventCreate(userString,
|
event = RoomEventCreate(userString,
|
||||||
"m.room.redaction", NULL,
|
"m.room.redaction", NULL,
|
||||||
content
|
content, NULL
|
||||||
);
|
);
|
||||||
HashMapSet(event, "redacts", JsonValueString(eventID));
|
HashMapSet(event, "redacts", JsonValueString(eventID));
|
||||||
pdu = RoomEventSend(room, event, errp);
|
pdu = RoomEventSend(room, event, errp);
|
||||||
|
@ -811,7 +817,7 @@ RoomJoin(Room *room, User *user, char **errp)
|
||||||
|
|
||||||
content = HashMapCreate();
|
content = HashMapCreate();
|
||||||
JsonSet(content, JsonValueString("join"), 1, "membership");
|
JsonSet(content, JsonValueString("join"), 1, "membership");
|
||||||
event = RoomEventCreate(userString, "m.room.member", userString, content);
|
event = RoomEventCreate(userString, "m.room.member", userString, content, NULL);
|
||||||
pdu = RoomEventSend(room, event, errp);
|
pdu = RoomEventSend(room, event, errp);
|
||||||
|
|
||||||
/* TODO: One ought to be extremely careful with managing users in those
|
/* TODO: One ought to be extremely careful with managing users in those
|
||||||
|
|
|
@ -97,7 +97,7 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
|
||||||
}
|
}
|
||||||
JsonValueFree(HashMapSet(content, key, JsonValueDuplicate(val)));
|
JsonValueFree(HashMapSet(content, key, JsonValueDuplicate(val)));
|
||||||
}
|
}
|
||||||
event = RoomEventCreate(sender_str, "m.room.create", "", content);
|
event = RoomEventCreate(sender_str, "m.room.create", "", content, NULL);
|
||||||
JsonFree(RoomEventSend(room, event, NULL));
|
JsonFree(RoomEventSend(room, event, NULL));
|
||||||
JsonFree(event);
|
JsonFree(event);
|
||||||
UserAddJoin(user, room->id);
|
UserAddJoin(user, room->id);
|
||||||
|
@ -105,7 +105,7 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
|
||||||
/* m.room.member */
|
/* m.room.member */
|
||||||
content = HashMapCreate();
|
content = HashMapCreate();
|
||||||
JsonSet(content, JsonValueString("join"), 1, "membership");
|
JsonSet(content, JsonValueString("join"), 1, "membership");
|
||||||
event = RoomEventCreate(sender_str, "m.room.member", sender_str, content);
|
event = RoomEventCreate(sender_str, "m.room.member", sender_str, content, NULL);
|
||||||
JsonFree(RoomEventSend(room, event, NULL));
|
JsonFree(RoomEventSend(room, event, NULL));
|
||||||
JsonFree(event);
|
JsonFree(event);
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
|
||||||
}
|
}
|
||||||
HashMapSet(content, key, JsonValueDuplicate(val));
|
HashMapSet(content, key, JsonValueDuplicate(val));
|
||||||
}
|
}
|
||||||
event = RoomEventCreate(sender_str, "m.room.power_levels", "", content);
|
event = RoomEventCreate(sender_str, "m.room.power_levels", "", content, NULL);
|
||||||
JsonFree(RoomEventSend(room, event, NULL));
|
JsonFree(RoomEventSend(room, event, NULL));
|
||||||
JsonFree(event);
|
JsonFree(event);
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
|
||||||
, 1, a); \
|
, 1, a); \
|
||||||
event = RoomEventCreate( \
|
event = RoomEventCreate( \
|
||||||
sender_str, \
|
sender_str, \
|
||||||
"m.room." #p, "", content); \
|
"m.room." #p, "", content, NULL); \
|
||||||
JsonFree(RoomEventSend(room, event, NULL)); \
|
JsonFree(RoomEventSend(room, event, NULL)); \
|
||||||
JsonFree(event); \
|
JsonFree(event); \
|
||||||
} \
|
} \
|
||||||
|
@ -208,7 +208,7 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
|
||||||
{
|
{
|
||||||
content = HashMapCreate();
|
content = HashMapCreate();
|
||||||
JsonSet(content, JsonValueString(req->name), 1, "name");
|
JsonSet(content, JsonValueString(req->name), 1, "name");
|
||||||
event = RoomEventCreate(sender_str, "m.room.name", "", content);
|
event = RoomEventCreate(sender_str, "m.room.name", "", content, NULL);
|
||||||
JsonFree(RoomEventSend(room, event, NULL));
|
JsonFree(RoomEventSend(room, event, NULL));
|
||||||
JsonFree(event);
|
JsonFree(event);
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
|
||||||
{
|
{
|
||||||
content = HashMapCreate();
|
content = HashMapCreate();
|
||||||
JsonSet(content, JsonValueString(req->topic), 1, "topic");
|
JsonSet(content, JsonValueString(req->topic), 1, "topic");
|
||||||
event = RoomEventCreate(sender_str, "m.room.topic", "", content);
|
event = RoomEventCreate(sender_str, "m.room.topic", "", content, NULL);
|
||||||
JsonFree(RoomEventSend(room, event, NULL));
|
JsonFree(RoomEventSend(room, event, NULL));
|
||||||
JsonFree(event);
|
JsonFree(event);
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
|
||||||
JsonSet(content, JsonValueString(fullStr), 1, "alias");
|
JsonSet(content, JsonValueString(fullStr), 1, "alias");
|
||||||
event = RoomEventCreate(
|
event = RoomEventCreate(
|
||||||
sender_str,
|
sender_str,
|
||||||
"m.room.canonical_alias", "", content);
|
"m.room.canonical_alias", "", content, NULL);
|
||||||
JsonFree(RoomEventSend(room, event, NULL));
|
JsonFree(RoomEventSend(room, event, NULL));
|
||||||
JsonFree(event);
|
JsonFree(event);
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event = RoomEventCreate(sender_str, "m.room.power_levels", "", pl_content);
|
event = RoomEventCreate(sender_str, "m.room.power_levels", "", pl_content, NULL);
|
||||||
JsonFree(RoomEventSend(room, event, NULL));
|
JsonFree(RoomEventSend(room, event, NULL));
|
||||||
JsonFree(event);
|
JsonFree(event);
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@ PopulateEventV1(Room * room, HashMap * event, PduV1 * pdu, ServerPart serv)
|
||||||
StrDuplicate(JsonValueAsString(JsonGet(event, 1, "type")));
|
StrDuplicate(JsonValueAsString(JsonGet(event, 1, "type")));
|
||||||
pdu->redacts =
|
pdu->redacts =
|
||||||
StrDuplicate(JsonValueAsString(JsonGet(event, 1, "redacts")));
|
StrDuplicate(JsonValueAsString(JsonGet(event, 1, "redacts")));
|
||||||
|
pdu->_unsigned.transaction_id =
|
||||||
|
StrDuplicate(JsonValueAsString(JsonGet(event, 1, "transaction")));
|
||||||
if (JsonGet(event, 1, "state_key"))
|
if (JsonGet(event, 1, "state_key"))
|
||||||
{
|
{
|
||||||
pdu->state_key =
|
pdu->state_key =
|
||||||
|
|
|
@ -242,6 +242,11 @@ RoomAddEventV1(Room *room, PduV1 pdu, PduV1Status status)
|
||||||
JsonValueArray(ArrayCreate()),
|
JsonValueArray(ArrayCreate()),
|
||||||
1, "next_events"
|
1, "next_events"
|
||||||
);
|
);
|
||||||
|
JsonSet(
|
||||||
|
DbJson(event_ref),
|
||||||
|
JsonValueString(pdu._unsigned.transaction_id),
|
||||||
|
1, "transaction"
|
||||||
|
);
|
||||||
|
|
||||||
DbUnlock(room->db, event_ref);
|
DbUnlock(room->db, event_ref);
|
||||||
Free(safe_id);
|
Free(safe_id);
|
||||||
|
|
|
@ -298,7 +298,7 @@ ROUTE_IMPL(RouteKickRoom, path, argp)
|
||||||
membership = RoomEventCreate(
|
membership = RoomEventCreate(
|
||||||
sender,
|
sender,
|
||||||
"m.room.member", kicked,
|
"m.room.member", kicked,
|
||||||
content
|
content, NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
HashMapSet(content, "membership", JsonValueString(membershipState));
|
HashMapSet(content, "membership", JsonValueString(membershipState));
|
||||||
|
|
|
@ -34,8 +34,105 @@
|
||||||
#include <Room.h>
|
#include <Room.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <Schema/Filter.h>
|
#include <Schema/KeyUpload.h>
|
||||||
|
|
||||||
|
HashMap *
|
||||||
|
UploadKey(RouteArgs *args, User *user, KeyUploadRequest *req, char *sender)
|
||||||
|
{
|
||||||
|
char *deviceId = UserGetDeviceId(user);
|
||||||
|
KeyResponse response = { 0 };
|
||||||
|
HashMap *json;
|
||||||
|
char *fbKey;
|
||||||
|
JsonValue *fbValue;
|
||||||
|
size_t i;
|
||||||
|
if (!user || !req || !sender)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Log(LOG_ERR, "did=%s", deviceId);
|
||||||
|
if (req->device_keys.user_id)
|
||||||
|
{
|
||||||
|
HashMap *publicKeys;
|
||||||
|
char *pkTag, *pk;
|
||||||
|
/* We have device key information */
|
||||||
|
if (!StrEquals(req->device_keys.user_id, sender))
|
||||||
|
{
|
||||||
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
|
return MatrixErrorCreate(
|
||||||
|
M_UNAUTHORIZED, "Device key update has an invalid user ID"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!StrEquals(req->device_keys.device_id, deviceId))
|
||||||
|
{
|
||||||
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
|
return MatrixErrorCreate(
|
||||||
|
M_UNAUTHORIZED, "Device key update has an invalid device ID"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the public key list */
|
||||||
|
publicKeys = req->device_keys.keys;
|
||||||
|
i = 0;
|
||||||
|
while (HashMapIterateReentrant(publicKeys, &pkTag, (void **) &pk, &i))
|
||||||
|
{
|
||||||
|
char *pktDID = strchr(pkTag, ':');
|
||||||
|
|
||||||
|
/* Maybe C does need NULL saturation */
|
||||||
|
pktDID = pktDID ? pktDID + 1 : NULL;
|
||||||
|
if (!StrEquals(pktDID, deviceId))
|
||||||
|
{
|
||||||
|
/* As far as I know, we're not meant to handle other devices'
|
||||||
|
* public keys */
|
||||||
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
|
Log(LOG_ERR, "%s!=%s 1", pktDID, deviceId);
|
||||||
|
return MatrixErrorCreate(
|
||||||
|
M_UNAUTHORIZED, "Device key update has an invalid device ID"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UserSetDeviceKeys(user, &req->device_keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserClearFallbackKeys(user);
|
||||||
|
i = 0;
|
||||||
|
while (HashMapIterateReentrant(req->fallback_keys, &fbKey, (void **) &fbValue, &i))
|
||||||
|
{
|
||||||
|
char *fbKID = strchr(fbKey, ':');
|
||||||
|
size_t len = fbKID ? fbKID - fbKey : 0;
|
||||||
|
char algo[len + 1];
|
||||||
|
|
||||||
|
memcpy(algo, fbKey, len);
|
||||||
|
algo[len] = '\0';
|
||||||
|
|
||||||
|
/* Maybe C does need NULL saturation */
|
||||||
|
fbKID = fbKID ? fbKID + 1 : NULL;
|
||||||
|
|
||||||
|
UserAddKey(user, fbKey, fbValue, true);
|
||||||
|
(void) fbKID;
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
while (HashMapIterateReentrant(req->one_time_keys, &fbKey, (void **) &fbValue, &i))
|
||||||
|
{
|
||||||
|
char *fbKID = strchr(fbKey, ':');
|
||||||
|
size_t len = fbKID ? fbKID - fbKey : 0;
|
||||||
|
char algo[len + 1];
|
||||||
|
|
||||||
|
memcpy(algo, fbKey, len);
|
||||||
|
algo[len] = '\0';
|
||||||
|
|
||||||
|
/* Maybe C does need NULL saturation */
|
||||||
|
fbKID = fbKID ? fbKID + 1 : NULL;
|
||||||
|
|
||||||
|
UserAddKey(user, fbKey, fbValue, false);
|
||||||
|
(void) fbKID;
|
||||||
|
}
|
||||||
|
response.one_time_key_counts = UserGetOnetimeCounts(user);
|
||||||
|
UserNotifyUser(UserGetName(user));
|
||||||
|
json = KeyResponseToJson(&response);
|
||||||
|
KeyResponseFree(&response);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
ROUTE_IMPL(RouteKeyQuery, path, argp)
|
ROUTE_IMPL(RouteKeyQuery, path, argp)
|
||||||
{
|
{
|
||||||
|
@ -45,9 +142,14 @@ ROUTE_IMPL(RouteKeyQuery, path, argp)
|
||||||
HashMap *request = NULL;
|
HashMap *request = NULL;
|
||||||
HashMap *response = NULL;
|
HashMap *response = NULL;
|
||||||
|
|
||||||
User *user = NULL;
|
CommonID *id = NULL;
|
||||||
char *token = NULL;
|
char *token = NULL;
|
||||||
|
User *user = NULL;
|
||||||
|
|
||||||
|
char *serverName = NULL;
|
||||||
|
char *sender = NULL;
|
||||||
|
|
||||||
|
char *method = ArrayGet(path, 0);
|
||||||
char *err;
|
char *err;
|
||||||
|
|
||||||
if (HttpRequestMethodGet(args->context) != HTTP_POST)
|
if (HttpRequestMethodGet(args->context) != HTTP_POST)
|
||||||
|
@ -71,6 +173,11 @@ ROUTE_IMPL(RouteKeyQuery, path, argp)
|
||||||
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
|
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
serverName = ConfigGetServerName(db);
|
||||||
|
id = UserIdParse(UserGetName(user), serverName);
|
||||||
|
id->sigil = '@';
|
||||||
|
sender = ParserRecomposeCommonID(*id);
|
||||||
|
|
||||||
request = JsonDecode(HttpServerStream(args->context));
|
request = JsonDecode(HttpServerStream(args->context));
|
||||||
if (!request)
|
if (!request)
|
||||||
{
|
{
|
||||||
|
@ -79,10 +186,37 @@ ROUTE_IMPL(RouteKeyQuery, path, argp)
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (StrEquals(method, "upload"))
|
||||||
|
{
|
||||||
|
KeyUploadRequest upload = { 0 };
|
||||||
|
|
||||||
|
if (!KeyUploadRequestFromJson(request, &upload, &err))
|
||||||
|
{
|
||||||
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
|
response = MatrixErrorCreate(M_BAD_JSON, err);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((response = UploadKey(args, user, &upload, sender)))
|
||||||
|
{
|
||||||
|
KeyUploadRequestFree(&upload);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
KeyUploadRequestFree(&upload);
|
||||||
|
}
|
||||||
|
else if (StrEquals(method, "query"))
|
||||||
|
{
|
||||||
|
/* TODO: Fetch a user's key information */
|
||||||
|
}
|
||||||
|
|
||||||
response = HashMapCreate();
|
response = HashMapCreate();
|
||||||
(void) path;
|
(void) path;
|
||||||
finish:
|
finish:
|
||||||
JsonFree(request);
|
JsonFree(request);
|
||||||
UserUnlock(user);
|
UserUnlock(user);
|
||||||
|
|
||||||
|
Free(serverName);
|
||||||
|
UserIdFree(id);
|
||||||
|
Free(sender);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,7 +122,7 @@ ROUTE_IMPL(RouteSendEvent, path, argp)
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
event = RoomEventCreate(sender, eventType, NULL, JsonDuplicate(request));
|
event = RoomEventCreate(sender, eventType, NULL, JsonDuplicate(request), transId);
|
||||||
filled = RoomEventSend(room, event, &err);
|
filled = RoomEventSend(room, event, &err);
|
||||||
JsonFree(event);
|
JsonFree(event);
|
||||||
|
|
||||||
|
@ -266,7 +266,7 @@ ROUTE_IMPL(RouteSendState, path, argp)
|
||||||
event = RoomEventCreate(
|
event = RoomEventCreate(
|
||||||
sender,
|
sender,
|
||||||
eventType, stateKey ? stateKey : "",
|
eventType, stateKey ? stateKey : "",
|
||||||
JsonDuplicate(request)
|
JsonDuplicate(request), NULL
|
||||||
);
|
);
|
||||||
filled = RoomEventSend(room, event, &err);
|
filled = RoomEventSend(room, event, &err);
|
||||||
JsonFree(event);
|
JsonFree(event);
|
||||||
|
|
|
@ -139,12 +139,17 @@ ROUTE_IMPL(RouteSync, path, argp)
|
||||||
|
|
||||||
/* TODO: I only am manually parsing this because j2s does not support
|
/* TODO: I only am manually parsing this because j2s does not support
|
||||||
* a hashmap of unknown keys pointing to a known type. */
|
* a hashmap of unknown keys pointing to a known type. */
|
||||||
sync.rooms.invite = HashMapCreate();
|
sync.rooms.invite = NULL;
|
||||||
sync.rooms.join = HashMapCreate();
|
sync.rooms.join = NULL;
|
||||||
sync.account_data.events = ArrayCreate();
|
sync.account_data.events = NULL;
|
||||||
|
sync.device_one_time_keys_count = UserGetOnetimeCounts(user);
|
||||||
|
|
||||||
/* account data */
|
/* account data */
|
||||||
accountData = UserGetAccountDataSync(user, currBatch);
|
accountData = UserGetAccountDataSync(user, currBatch);
|
||||||
|
if (ArraySize(accountData) > 0)
|
||||||
|
{
|
||||||
|
sync.account_data.events = ArrayCreate();
|
||||||
|
}
|
||||||
for (i = 0; i < ArraySize(accountData); i++)
|
for (i = 0; i < ArraySize(accountData); i++)
|
||||||
{
|
{
|
||||||
char *key = ArrayGet(accountData, i);
|
char *key = ArrayGet(accountData, i);
|
||||||
|
@ -158,6 +163,10 @@ ROUTE_IMPL(RouteSync, path, argp)
|
||||||
|
|
||||||
/* invites */
|
/* invites */
|
||||||
invites = UserGetInvites(user, currBatch);
|
invites = UserGetInvites(user, currBatch);
|
||||||
|
if (ArraySize(invites) > 0)
|
||||||
|
{
|
||||||
|
sync.rooms.invite = HashMapCreate();
|
||||||
|
}
|
||||||
for (i = 0; i < ArraySize(invites); i++)
|
for (i = 0; i < ArraySize(invites); i++)
|
||||||
{
|
{
|
||||||
char *roomId = ArrayGet(invites, i);
|
char *roomId = ArrayGet(invites, i);
|
||||||
|
@ -171,7 +180,7 @@ ROUTE_IMPL(RouteSync, path, argp)
|
||||||
invited = Malloc(sizeof(*invited));
|
invited = Malloc(sizeof(*invited));
|
||||||
memset(invited, 0, sizeof(*invited));
|
memset(invited, 0, sizeof(*invited));
|
||||||
|
|
||||||
/* TODO: Populate the invitestate */
|
// TODO: Populate the invitestate
|
||||||
invited->invite_state.events = ArrayCreate();
|
invited->invite_state.events = ArrayCreate();
|
||||||
HashMapSet(sync.rooms.invite, roomId, invited);
|
HashMapSet(sync.rooms.invite, roomId, invited);
|
||||||
}
|
}
|
||||||
|
@ -179,9 +188,12 @@ ROUTE_IMPL(RouteSync, path, argp)
|
||||||
|
|
||||||
/* Joins */
|
/* Joins */
|
||||||
joins = UserGetJoins(user, currBatch);
|
joins = UserGetJoins(user, currBatch);
|
||||||
|
if (ArraySize(joins) > 0)
|
||||||
|
{
|
||||||
|
sync.rooms.join = HashMapCreate();
|
||||||
|
}
|
||||||
for (i = 0; i < ArraySize(joins); i++)
|
for (i = 0; i < ArraySize(joins); i++)
|
||||||
{
|
{
|
||||||
/* TODO: Rename these variables */
|
|
||||||
char *roomId = ArrayGet(joins, i);
|
char *roomId = ArrayGet(joins, i);
|
||||||
JoinedRooms *joined;
|
JoinedRooms *joined;
|
||||||
char *firstEvent = NULL;
|
char *firstEvent = NULL;
|
||||||
|
@ -230,8 +242,8 @@ ROUTE_IMPL(RouteSync, path, argp)
|
||||||
joined->timeline.prev_batch = UserNewMessageToken(
|
joined->timeline.prev_batch = UserNewMessageToken(
|
||||||
user, roomId, firstEvent
|
user, roomId, firstEvent
|
||||||
);
|
);
|
||||||
/* TODO: Don't shove the entire state.
|
// TODO: Don't shove the entire state.
|
||||||
* That's a recipe for disaster, especially on large rooms. */
|
// That's a recipe for disaster, especially on large rooms.
|
||||||
joined->state.events = ArrayCreate();
|
joined->state.events = ArrayCreate();
|
||||||
while (StateIterate(state, &type, &key, (void **) &id))
|
while (StateIterate(state, &type, &key, (void **) &id))
|
||||||
{
|
{
|
||||||
|
@ -253,12 +265,13 @@ ROUTE_IMPL(RouteSync, path, argp)
|
||||||
if (prevBatch)
|
if (prevBatch)
|
||||||
{
|
{
|
||||||
/* TODO: Should we be dropping syncs? */
|
/* TODO: Should we be dropping syncs? */
|
||||||
UserDropSync(user, prevBatch);
|
//UserDropSync(user, prevBatch);
|
||||||
nextBatch = UserInitSyncDiff(user);
|
nextBatch = UserInitSyncDiff(user);
|
||||||
}
|
}
|
||||||
sync.next_batch = nextBatch;
|
sync.next_batch = nextBatch;
|
||||||
response = SyncResponseToJson(&sync);
|
response = SyncResponseToJson(&sync);
|
||||||
SyncResponseFree(&sync);
|
SyncResponseFree(&sync);
|
||||||
|
(void) i;
|
||||||
finish:
|
finish:
|
||||||
FilterDestroy(filterData);
|
FilterDestroy(filterData);
|
||||||
UserUnlock(user);
|
UserUnlock(user);
|
||||||
|
|
|
@ -56,7 +56,7 @@ SendMembership(Db *db, User *user)
|
||||||
HashMap *content = HashMapCreate();
|
HashMap *content = HashMapCreate();
|
||||||
HashMap *membership = RoomEventCreate(
|
HashMap *membership = RoomEventCreate(
|
||||||
sender, "m.room.member", sender,
|
sender, "m.room.member", sender,
|
||||||
content
|
content, NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
HashMapSet(content, "membership", JsonValueString("join"));
|
HashMapSet(content, "membership", JsonValueString("join"));
|
||||||
|
|
123
src/User.c
123
src/User.c
|
@ -1533,6 +1533,7 @@ UserGetAccountDataSync(User *user, char *batch)
|
||||||
syncRef = DbLock(db, 4, "users", user->name, "sync", batch);
|
syncRef = DbLock(db, 4, "users", user->name, "sync", batch);
|
||||||
if (!syncRef)
|
if (!syncRef)
|
||||||
{
|
{
|
||||||
|
Log(LOG_ERR, "Tried to get batch=%s (user=%s), but it's gone?", batch, user->deviceId);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2153,3 +2154,125 @@ UserSetAccountData(User *user, char *key, HashMap *obj)
|
||||||
|
|
||||||
UserPushAccountData(user, key);
|
UserPushAccountData(user, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserSetDeviceKeys(User *user, DeviceKeys *keys)
|
||||||
|
{
|
||||||
|
char *device;
|
||||||
|
HashMap *deviceObj;
|
||||||
|
if (!user || !keys)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
device = UserGetDeviceId(user);
|
||||||
|
deviceObj = JsonValueAsObject(HashMapGet(
|
||||||
|
UserGetDevices(user), device
|
||||||
|
));
|
||||||
|
if (!deviceObj)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonValueFree(HashMapSet(deviceObj, "deviceKeys", JsonValueObject(DeviceKeysToJson(keys))));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
UserClearFallbackKeys(User *user)
|
||||||
|
{
|
||||||
|
char *device;
|
||||||
|
HashMap *deviceObj;
|
||||||
|
if (!user)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
device = UserGetDeviceId(user);
|
||||||
|
deviceObj = JsonValueAsObject(HashMapGet(
|
||||||
|
UserGetDevices(user), device
|
||||||
|
));
|
||||||
|
if (!deviceObj)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HashMapGet(deviceObj, "oneTimeKeys"))
|
||||||
|
{
|
||||||
|
JsonValueFree(HashMapSet(deviceObj,
|
||||||
|
"oneTimeKeys", JsonValueObject(HashMapCreate())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
JsonValueFree(HashMapSet(deviceObj,
|
||||||
|
"fallbackKeys", JsonValueObject(HashMapCreate())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
void
|
||||||
|
UserAddKey(User *user, char *algo, JsonValue *key, bool fb)
|
||||||
|
{
|
||||||
|
char *device;
|
||||||
|
HashMap *deviceObj, *method;
|
||||||
|
if (!user || !algo || !key)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
device = UserGetDeviceId(user);
|
||||||
|
deviceObj = JsonValueAsObject(HashMapGet(
|
||||||
|
UserGetDevices(user), device
|
||||||
|
));
|
||||||
|
if (!deviceObj)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
method = JsonValueAsObject(HashMapGet(
|
||||||
|
deviceObj, fb ? "fallbackKeys" : "oneTimeKeys"
|
||||||
|
));
|
||||||
|
JsonValueFree(HashMapSet(method, algo, JsonValueDuplicate(key)));
|
||||||
|
}
|
||||||
|
HashMap *
|
||||||
|
UserGetOnetimeCounts(User *user)
|
||||||
|
{
|
||||||
|
char *device, *algoKey;
|
||||||
|
HashMap *deviceObj, *otk, *ret;
|
||||||
|
void *ignore;
|
||||||
|
if (!user)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
device = UserGetDeviceId(user);
|
||||||
|
deviceObj = JsonValueAsObject(HashMapGet(
|
||||||
|
UserGetDevices(user), device
|
||||||
|
));
|
||||||
|
if (!deviceObj)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
otk = JsonValueAsObject(HashMapGet(
|
||||||
|
deviceObj, "oneTimeKeys"
|
||||||
|
));
|
||||||
|
ret = HashMapCreate();
|
||||||
|
while (HashMapIterate(otk, &algoKey, &ignore))
|
||||||
|
{
|
||||||
|
char *algo = StrDuplicate(algoKey);
|
||||||
|
char *end = strchr(algo, ':');
|
||||||
|
int64_t *ptr;
|
||||||
|
if (end)
|
||||||
|
{
|
||||||
|
*end = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ptr = HashMapGet(ret, algo)))
|
||||||
|
{
|
||||||
|
ptr = Malloc(sizeof(*ptr));
|
||||||
|
*ptr = 0;
|
||||||
|
HashMapSet(ret, algo, ptr);
|
||||||
|
}
|
||||||
|
(*ptr)++;
|
||||||
|
Free(algo);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -195,7 +195,7 @@ extern bool RoomAddEventV1(Room *, PduV1, PduV1Status);
|
||||||
* Creates a barebones JSON object to be sent to
|
* Creates a barebones JSON object to be sent to
|
||||||
* .Fn RoomEventFetch .
|
* .Fn RoomEventFetch .
|
||||||
*/
|
*/
|
||||||
extern HashMap * RoomEventCreate(char *, char *, char *, HashMap *);
|
extern HashMap * RoomEventCreate(char *, char *, char *, HashMap *, char *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes an approximation of the PDU depth by looking at
|
* Computes an approximation of the PDU depth by looking at
|
||||||
|
|
|
@ -44,6 +44,8 @@
|
||||||
|
|
||||||
#include <Parser.h>
|
#include <Parser.h>
|
||||||
|
|
||||||
|
#include <Schema/KeyUpload.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -522,4 +524,26 @@ extern HashMap * UserGetAccountData(User *, char *);
|
||||||
* Replaces an account data entry.
|
* Replaces an account data entry.
|
||||||
*/
|
*/
|
||||||
extern void UserSetAccountData(User *, char *, HashMap *);
|
extern void UserSetAccountData(User *, char *, HashMap *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the device key list.
|
||||||
|
*/
|
||||||
|
extern void UserSetDeviceKeys(User *, DeviceKeys *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the fallback/one-time key list.
|
||||||
|
*/
|
||||||
|
extern void UserClearFallbackKeys(User *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a one-time/fallback key.
|
||||||
|
*/
|
||||||
|
extern void UserAddKey(User *, char *, JsonValue *, bool);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a hashmap from algorithm to one-time key count as
|
||||||
|
* a pointer to the uint64_t.
|
||||||
|
* This is intended for /keys/upload. Please do not use this
|
||||||
|
* elsewhere */
|
||||||
|
extern HashMap * UserGetOnetimeCounts(User *);
|
||||||
#endif /* TELODENDRIA_USER_H */
|
#endif /* TELODENDRIA_USER_H */
|
||||||
|
|
Loading…
Reference in a new issue