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": {
|
||||
"type": "object",
|
||||
"required": false
|
||||
},
|
||||
"transaction_id": {
|
||||
"type": "string",
|
||||
"required": false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
"sender": { "type": "string", "required": true },
|
||||
"state_key": { "type": "string" },
|
||||
"redacts": { "type": "string" },
|
||||
"_unsigned": { "type": "object" },
|
||||
"type": { "type": "string", "required": true }
|
||||
},
|
||||
"type": "struct"
|
||||
|
@ -105,6 +106,9 @@
|
|||
},
|
||||
"rooms": {
|
||||
"type": "Rooms"
|
||||
},
|
||||
"device_one_time_keys_count": {
|
||||
"type": "{integer}"
|
||||
}
|
||||
},
|
||||
"type": "struct"
|
||||
|
|
16
src/Room.c
16
src/Room.c
|
@ -348,6 +348,11 @@ RoomEventFetch(Room *room, char *id, bool prev)
|
|||
"pdu_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"));
|
||||
JsonValueFree(HashMapSet(
|
||||
unsign,
|
||||
|
@ -391,7 +396,7 @@ finish:
|
|||
}
|
||||
|
||||
HashMap *
|
||||
RoomEventCreate(char *sender, char *type, char *key, HashMap *c)
|
||||
RoomEventCreate(char *sender, char *type, char *key, HashMap *c, char *txn)
|
||||
{
|
||||
HashMap *event;
|
||||
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, JsonValueString(sender), 1, "sender");
|
||||
JsonSet(event, JsonValueString(type), 1, "type");
|
||||
JsonSet(event, JsonValueString(txn), 1, "transaction");
|
||||
if (key)
|
||||
{
|
||||
JsonSet(event, JsonValueString(key), 1, "state_key");
|
||||
|
@ -557,7 +563,7 @@ RoomSendInvite(User *sender, bool direct, char *user, Room *room)
|
|||
content = HashMapCreate();
|
||||
JsonSet(content, JsonValueBoolean(direct), 1, "is_direct");
|
||||
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(event);
|
||||
|
||||
|
@ -692,7 +698,7 @@ RoomLeave(Room *room, User *user, char **errp)
|
|||
|
||||
content = HashMapCreate();
|
||||
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);
|
||||
|
||||
/* 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));
|
||||
event = RoomEventCreate(userString,
|
||||
"m.room.redaction", NULL,
|
||||
content
|
||||
content, NULL
|
||||
);
|
||||
HashMapSet(event, "redacts", JsonValueString(eventID));
|
||||
pdu = RoomEventSend(room, event, errp);
|
||||
|
@ -811,7 +817,7 @@ RoomJoin(Room *room, User *user, char **errp)
|
|||
|
||||
content = HashMapCreate();
|
||||
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);
|
||||
|
||||
/* 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)));
|
||||
}
|
||||
event = RoomEventCreate(sender_str, "m.room.create", "", content);
|
||||
event = RoomEventCreate(sender_str, "m.room.create", "", content, NULL);
|
||||
JsonFree(RoomEventSend(room, event, NULL));
|
||||
JsonFree(event);
|
||||
UserAddJoin(user, room->id);
|
||||
|
@ -105,7 +105,7 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
|
|||
/* m.room.member */
|
||||
content = HashMapCreate();
|
||||
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(event);
|
||||
|
||||
|
@ -126,7 +126,7 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
|
|||
}
|
||||
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(event);
|
||||
|
||||
|
@ -174,7 +174,7 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
|
|||
, 1, a); \
|
||||
event = RoomEventCreate( \
|
||||
sender_str, \
|
||||
"m.room." #p, "", content); \
|
||||
"m.room." #p, "", content, NULL); \
|
||||
JsonFree(RoomEventSend(room, event, NULL)); \
|
||||
JsonFree(event); \
|
||||
} \
|
||||
|
@ -208,7 +208,7 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
|
|||
{
|
||||
content = HashMapCreate();
|
||||
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(event);
|
||||
}
|
||||
|
@ -216,7 +216,7 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
|
|||
{
|
||||
content = HashMapCreate();
|
||||
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(event);
|
||||
}
|
||||
|
@ -240,7 +240,7 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
|
|||
JsonSet(content, JsonValueString(fullStr), 1, "alias");
|
||||
event = RoomEventCreate(
|
||||
sender_str,
|
||||
"m.room.canonical_alias", "", content);
|
||||
"m.room.canonical_alias", "", content, NULL);
|
||||
JsonFree(RoomEventSend(room, event, NULL));
|
||||
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(event);
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ PopulateEventV1(Room * room, HashMap * event, PduV1 * pdu, ServerPart serv)
|
|||
StrDuplicate(JsonValueAsString(JsonGet(event, 1, "type")));
|
||||
pdu->redacts =
|
||||
StrDuplicate(JsonValueAsString(JsonGet(event, 1, "redacts")));
|
||||
pdu->_unsigned.transaction_id =
|
||||
StrDuplicate(JsonValueAsString(JsonGet(event, 1, "transaction")));
|
||||
if (JsonGet(event, 1, "state_key"))
|
||||
{
|
||||
pdu->state_key =
|
||||
|
|
|
@ -242,6 +242,11 @@ RoomAddEventV1(Room *room, PduV1 pdu, PduV1Status status)
|
|||
JsonValueArray(ArrayCreate()),
|
||||
1, "next_events"
|
||||
);
|
||||
JsonSet(
|
||||
DbJson(event_ref),
|
||||
JsonValueString(pdu._unsigned.transaction_id),
|
||||
1, "transaction"
|
||||
);
|
||||
|
||||
DbUnlock(room->db, event_ref);
|
||||
Free(safe_id);
|
||||
|
|
|
@ -298,7 +298,7 @@ ROUTE_IMPL(RouteKickRoom, path, argp)
|
|||
membership = RoomEventCreate(
|
||||
sender,
|
||||
"m.room.member", kicked,
|
||||
content
|
||||
content, NULL
|
||||
);
|
||||
|
||||
HashMapSet(content, "membership", JsonValueString(membershipState));
|
||||
|
|
|
@ -34,8 +34,105 @@
|
|||
#include <Room.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)
|
||||
{
|
||||
|
@ -45,9 +142,14 @@ ROUTE_IMPL(RouteKeyQuery, path, argp)
|
|||
HashMap *request = NULL;
|
||||
HashMap *response = NULL;
|
||||
|
||||
User *user = NULL;
|
||||
CommonID *id = NULL;
|
||||
char *token = NULL;
|
||||
User *user = NULL;
|
||||
|
||||
char *serverName = NULL;
|
||||
char *sender = NULL;
|
||||
|
||||
char *method = ArrayGet(path, 0);
|
||||
char *err;
|
||||
|
||||
if (HttpRequestMethodGet(args->context) != HTTP_POST)
|
||||
|
@ -71,6 +173,11 @@ ROUTE_IMPL(RouteKeyQuery, path, argp)
|
|||
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
|
||||
goto finish;
|
||||
}
|
||||
serverName = ConfigGetServerName(db);
|
||||
id = UserIdParse(UserGetName(user), serverName);
|
||||
id->sigil = '@';
|
||||
sender = ParserRecomposeCommonID(*id);
|
||||
|
||||
request = JsonDecode(HttpServerStream(args->context));
|
||||
if (!request)
|
||||
{
|
||||
|
@ -79,10 +186,37 @@ ROUTE_IMPL(RouteKeyQuery, path, argp)
|
|||
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();
|
||||
(void) path;
|
||||
finish:
|
||||
JsonFree(request);
|
||||
UserUnlock(user);
|
||||
|
||||
Free(serverName);
|
||||
UserIdFree(id);
|
||||
Free(sender);
|
||||
return response;
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ ROUTE_IMPL(RouteSendEvent, path, argp)
|
|||
goto finish;
|
||||
}
|
||||
|
||||
event = RoomEventCreate(sender, eventType, NULL, JsonDuplicate(request));
|
||||
event = RoomEventCreate(sender, eventType, NULL, JsonDuplicate(request), transId);
|
||||
filled = RoomEventSend(room, event, &err);
|
||||
JsonFree(event);
|
||||
|
||||
|
@ -266,7 +266,7 @@ ROUTE_IMPL(RouteSendState, path, argp)
|
|||
event = RoomEventCreate(
|
||||
sender,
|
||||
eventType, stateKey ? stateKey : "",
|
||||
JsonDuplicate(request)
|
||||
JsonDuplicate(request), NULL
|
||||
);
|
||||
filled = RoomEventSend(room, event, &err);
|
||||
JsonFree(event);
|
||||
|
|
|
@ -139,12 +139,17 @@ ROUTE_IMPL(RouteSync, path, argp)
|
|||
|
||||
/* TODO: I only am manually parsing this because j2s does not support
|
||||
* a hashmap of unknown keys pointing to a known type. */
|
||||
sync.rooms.invite = HashMapCreate();
|
||||
sync.rooms.join = HashMapCreate();
|
||||
sync.account_data.events = ArrayCreate();
|
||||
sync.rooms.invite = NULL;
|
||||
sync.rooms.join = NULL;
|
||||
sync.account_data.events = NULL;
|
||||
sync.device_one_time_keys_count = UserGetOnetimeCounts(user);
|
||||
|
||||
/* account data */
|
||||
accountData = UserGetAccountDataSync(user, currBatch);
|
||||
if (ArraySize(accountData) > 0)
|
||||
{
|
||||
sync.account_data.events = ArrayCreate();
|
||||
}
|
||||
for (i = 0; i < ArraySize(accountData); i++)
|
||||
{
|
||||
char *key = ArrayGet(accountData, i);
|
||||
|
@ -158,6 +163,10 @@ ROUTE_IMPL(RouteSync, path, argp)
|
|||
|
||||
/* invites */
|
||||
invites = UserGetInvites(user, currBatch);
|
||||
if (ArraySize(invites) > 0)
|
||||
{
|
||||
sync.rooms.invite = HashMapCreate();
|
||||
}
|
||||
for (i = 0; i < ArraySize(invites); i++)
|
||||
{
|
||||
char *roomId = ArrayGet(invites, i);
|
||||
|
@ -171,7 +180,7 @@ ROUTE_IMPL(RouteSync, path, argp)
|
|||
invited = Malloc(sizeof(*invited));
|
||||
memset(invited, 0, sizeof(*invited));
|
||||
|
||||
/* TODO: Populate the invitestate */
|
||||
// TODO: Populate the invitestate
|
||||
invited->invite_state.events = ArrayCreate();
|
||||
HashMapSet(sync.rooms.invite, roomId, invited);
|
||||
}
|
||||
|
@ -179,9 +188,12 @@ ROUTE_IMPL(RouteSync, path, argp)
|
|||
|
||||
/* Joins */
|
||||
joins = UserGetJoins(user, currBatch);
|
||||
if (ArraySize(joins) > 0)
|
||||
{
|
||||
sync.rooms.join = HashMapCreate();
|
||||
}
|
||||
for (i = 0; i < ArraySize(joins); i++)
|
||||
{
|
||||
/* TODO: Rename these variables */
|
||||
char *roomId = ArrayGet(joins, i);
|
||||
JoinedRooms *joined;
|
||||
char *firstEvent = NULL;
|
||||
|
@ -230,8 +242,8 @@ ROUTE_IMPL(RouteSync, path, argp)
|
|||
joined->timeline.prev_batch = UserNewMessageToken(
|
||||
user, roomId, firstEvent
|
||||
);
|
||||
/* TODO: Don't shove the entire state.
|
||||
* That's a recipe for disaster, especially on large rooms. */
|
||||
// TODO: Don't shove the entire state.
|
||||
// That's a recipe for disaster, especially on large rooms.
|
||||
joined->state.events = ArrayCreate();
|
||||
while (StateIterate(state, &type, &key, (void **) &id))
|
||||
{
|
||||
|
@ -253,12 +265,13 @@ ROUTE_IMPL(RouteSync, path, argp)
|
|||
if (prevBatch)
|
||||
{
|
||||
/* TODO: Should we be dropping syncs? */
|
||||
UserDropSync(user, prevBatch);
|
||||
//UserDropSync(user, prevBatch);
|
||||
nextBatch = UserInitSyncDiff(user);
|
||||
}
|
||||
sync.next_batch = nextBatch;
|
||||
response = SyncResponseToJson(&sync);
|
||||
SyncResponseFree(&sync);
|
||||
(void) i;
|
||||
finish:
|
||||
FilterDestroy(filterData);
|
||||
UserUnlock(user);
|
||||
|
|
|
@ -56,7 +56,7 @@ SendMembership(Db *db, User *user)
|
|||
HashMap *content = HashMapCreate();
|
||||
HashMap *membership = RoomEventCreate(
|
||||
sender, "m.room.member", sender,
|
||||
content
|
||||
content, NULL
|
||||
);
|
||||
|
||||
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);
|
||||
if (!syncRef)
|
||||
{
|
||||
Log(LOG_ERR, "Tried to get batch=%s (user=%s), but it's gone?", batch, user->deviceId);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -2153,3 +2154,125 @@ UserSetAccountData(User *user, char *key, HashMap *obj)
|
|||
|
||||
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
|
||||
* .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
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
|
||||
#include <Parser.h>
|
||||
|
||||
#include <Schema/KeyUpload.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
|
@ -522,4 +524,26 @@ extern HashMap * UserGetAccountData(User *, char *);
|
|||
* Replaces an account data entry.
|
||||
*/
|
||||
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 */
|
||||
|
|
Loading…
Reference in a new issue