Compare commits

...

2 commits

Author SHA1 Message Date
lda
cacc72bf84 [ADD/WIP] Basic preset code
Some checks are pending
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run
I still need to find a solution to a problem related to j2s.
Right now I kind of want to have a way for users to send events
from the endpoints.
2024-05-19 15:17:56 +02:00
lda
a99798a312 [ADD/WIP] Start abstracting aliasing 2024-05-19 00:30:28 +02:00
4 changed files with 249 additions and 74 deletions

View file

@ -88,6 +88,11 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
JsonValue *val; JsonValue *val;
size_t i; size_t i;
char *join_rules_preset = NULL;
char *history_visibility_preset = NULL;
char *guest_access_preset = NULL;
/* TODO: Manage trusted private chat */
sender.sigil = '@'; sender.sigil = '@';
sender.local = UserGetName(user); sender.local = UserGetName(user);
sender.server = s; sender.server = s;
@ -135,16 +140,59 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
switch (req->preset) switch (req->preset)
{ {
case ROOM_CREATE_PUBLIC: case ROOM_CREATE_PUBLIC:
/* TODO */ join_rules_preset = "public";
history_visibility_preset = "shared";
guest_access_preset = "forbidden";
break; break;
case ROOM_CREATE_TRUSTED: case ROOM_CREATE_TRUSTED:
/* TODO */ /* TODO */
break; /* Fallthrough */
case ROOM_CREATE_PRIVATE: case ROOM_CREATE_PRIVATE:
/* TODO */ join_rules_preset = "invite";
history_visibility_preset = "shared";
guest_access_preset = "can_join";
break;
default:
switch (req->visibility)
{
case ROOM_PUBLIC:
join_rules_preset = "public";
history_visibility_preset = "shared";
guest_access_preset = "forbidden";
break;
case ROOM_PRIVATE:
join_rules_preset = "invite";
history_visibility_preset = "shared";
guest_access_preset = "can_join";
break;
}
break; break;
} }
/* Write out presets */
#define SetIfExistent(pset) do { \
if (pset##_preset) \
{ \
content = HashMapCreate(); \
JsonSet( \
content, \
JsonValueString(join_rules_preset) \
, 1, #pset); \
event = RoomEventCreate( \
sender_str, \
"m.room." #pset, "", content); \
JsonFree(RoomEventSend(room, event)); \
JsonFree(event); \
} \
} \
while (0)
SetIfExistent(join_rules);
SetIfExistent(history_visibility);
SetIfExistent(guest_access);
/* TODO: On a trusted room, set invitees PLs to the owner's. */
#undef SetIfExistent
/* User-provided initial states */ /* User-provided initial states */
initial_states = req->initial_state; initial_states = req->initial_state;
for (i = 0; i < ArraySize(initial_states); i++) for (i = 0; i < ArraySize(initial_states); i++)
@ -181,67 +229,30 @@ RoomPopulate(Room *room, User *user, RoomCreateRequest *req, ServerPart s)
} }
/* Custom alias */ /* Custom alias */
if (req->room_alias_name) if (req->room_alias_name && !RoomResolveAlias(room->db, room->id))
{ {
DbRef *aliasesRef = DbLock(room->db, 1, "aliases"); CommonID full;
HashMap *aliasesJson; char *fullStr, *serverStr;
if (!aliasesRef)
{
aliasesRef = DbCreate(room->db, 1, "aliases");
}
if (aliasesRef) full.sigil = '#';
{ full.local = req->room_alias_name;
CommonID full; full.server = s;
char *fullStr, *serverStr; fullStr = ParserRecomposeCommonID(full);
HashMap *alias, *idObject;
Array *servers, *ids;
full.sigil = '#'; serverStr = ParserRecomposeServerPart(room->creator);
full.local = req->room_alias_name;
full.server = s; RoomAddAlias(room->db, fullStr, room->id, sender_str, serverStr);
aliasesJson = DbJson(aliasesRef);
fullStr = ParserRecomposeCommonID(full);
servers = ArrayCreate(); content = HashMapCreate();
serverStr = ParserRecomposeServerPart(room->creator); JsonSet(content, JsonValueString(fullStr), 1, "alias");
ArrayAdd(servers, JsonValueString(serverStr)); event = RoomEventCreate(
Free(serverStr); sender_str,
"m.room.canonical_alias", "", content);
JsonFree(RoomEventSend(room, event));
JsonFree(event);
alias = HashMapCreate(); Free(fullStr);
HashMapSet(alias, "createdBy", JsonValueString(sender_str)); Free(serverStr);
HashMapSet(alias, "id", JsonValueString(room->id));
HashMapSet(alias, "servers", JsonValueArray(servers));
JsonValueFree(JsonSet(
aliasesJson, JsonValueObject(alias), 2,
"aliases", fullStr));
if (!(idObject =
JsonValueAsObject(JsonGet(aliasesJson, 2, "id", room->id))))
{
ids = ArrayCreate();
idObject = HashMapCreate();
HashMapSet(idObject, "aliases", JsonValueArray(ids));
JsonSet(
aliasesJson,
JsonValueObject(idObject),
2, "id", room->id);
}
ids = JsonValueAsArray(HashMapGet(idObject, "aliases"));
ArrayAdd(ids, JsonValueString(fullStr));
content = HashMapCreate();
JsonSet(content, JsonValueString(fullStr), 1, "alias");
event = RoomEventCreate(
sender_str,
"m.room.canonical_alias", "", content);
JsonFree(RoomEventSend(room, event));
JsonFree(event);
Free(fullStr);
DbUnlock(room->db, aliasesRef);
}
} }
/* TODO: The rest of the events mandated by the specification on /* TODO: The rest of the events mandated by the specification on
* POST /createRoom, and error management. */ * POST /createRoom, and error management. */
@ -582,9 +593,8 @@ PopulateEventV1(Room * room, HashMap * event, PduV1 * pdu, ServerPart serv)
JsonDuplicate(JsonValueAsObject(JsonGet(event, 1, "content"))); JsonDuplicate(JsonValueAsObject(JsonGet(event, 1, "content")));
pdu->room_id = StrDuplicate(room->id); pdu->room_id = StrDuplicate(room->id);
pdu->signatures = HashMapCreate(); pdu->signatures = HashMapCreate();
pdu->depth = RoomGetDepth(room) + 1; /* TODO: Clamp this value. */ pdu->depth = RoomGetDepth(room) + 1;
pdu->depth = pdu->depth >= (int64_t) INT64_MAX ? pdu->depth = pdu->depth >= INT64_MAX ? INT64_MAX : pdu->depth;
(int64_t) INT64_MAX : pdu->depth;
/* Create a random event ID for this PDU. /* Create a random event ID for this PDU.
* TODO: Optionally verify whenever it's already used, but that * TODO: Optionally verify whenever it's already used, but that
@ -1804,3 +1814,129 @@ RoomGetDepth(Room *room)
return max; return max;
} }
void
RoomAddAlias(Db *db, char *roomAlias, char *roomId, char *sender, char *serv)
{
DbRef *aliasRef;
HashMap *json, *alias, *idObject;
Array *servers, *ids;
if (!db || !roomAlias || !roomId || !sender || !serv)
{
return;
}
aliasRef = DbLock(db, 1, "aliases");
if (!aliasRef)
{
aliasRef = DbCreate(db, 1, "aliases");
if (!aliasRef)
{
return;
}
}
json = DbJson(aliasRef);
servers = ArrayCreate();
ArrayAdd(servers, JsonValueString(serv));
/* alias => ID */
alias = HashMapCreate();
JsonSet(alias, JsonValueString(roomId), 1, "id");
JsonSet(alias, JsonValueString(sender), 1, "createdBy");
JsonSet(alias, JsonValueArray(servers), 1, "servers");
JsonValueFree(
JsonSet(json, JsonValueObject(alias), 2, "aliases", roomAlias));
/* ID => alias(es) */
if (!(idObject =
JsonValueAsObject(JsonGet(json, 2, "id", roomId))))
{
ids = ArrayCreate();
idObject = HashMapCreate();
HashMapSet(idObject, "aliases", JsonValueArray(ids));
JsonSet(
json,
JsonValueObject(idObject),
2, "id", roomId);
}
ids = JsonValueAsArray(HashMapGet(idObject, "aliases"));
ArrayAdd(ids, JsonValueString(roomAlias));
DbUnlock(db, aliasRef);
}
char *
RoomResolveAlias(Db *db, char *roomAlias)
{
DbRef *aliasRef;
HashMap *json;
char *ret;
if (!db || !roomAlias)
{
return NULL;
}
aliasRef = DbLock(db, 1, "aliases");
if (!aliasRef)
{
return NULL;
}
json = DbJson(aliasRef);
ret = JsonValueAsString(JsonGet(json, 3, "aliases", roomAlias, "id"));
ret = StrDuplicate(ret);
DbUnlock(db, aliasRef);
return ret;
}
Array *
RoomReverseAlias(Db *db, char *roomId)
{
DbRef *aliasRef;
HashMap *json, *idObject;
Array *ret, *original;
size_t i;
if (!db || !roomId)
{
return NULL;
}
aliasRef = DbLock(db, 1, "aliases");
if (!aliasRef)
{
return NULL;
}
json = DbJson(aliasRef);
if (!(idObject =
JsonValueAsObject(JsonGet(json, 2, "id", roomId))))
{
DbUnlock(db, aliasRef);
return NULL;
}
original = JsonValueAsArray(HashMapGet(idObject, "aliases"));
ret = ArrayCreate();
for (i = 0; i < ArraySize(original); i++)
{
JsonValue *v = ArrayGet(original, i);
ArrayAdd(ret, StrDuplicate(JsonValueAsString(v)));
}
DbUnlock(db, aliasRef);
return ret;
}
void
RoomFreeReverse(Array *arr)
{
size_t i;
if (!arr)
{
return;
}
for (i = 0; i < ArraySize(arr); i++)
{
Free(ArrayGet(arr, i));
}
ArrayFree(arr);
}

View file

@ -80,7 +80,19 @@ ROUTE_IMPL(RouteCreateRoom, path, argp)
response = MatrixErrorCreate(M_NOT_JSON, NULL); response = MatrixErrorCreate(M_NOT_JSON, NULL);
goto finish; goto finish;
} }
/* j2s hack: Setting to a default value like that.
* It's definitely NOT good(you can't rely on enums to
* store values outside their limits in the C standard,
* and this line will need to be changed everytime the
* preset list is changed).
*
* I do believe a decent solution to this would be to
* add a 'default' type(maybe initialised to 0 so that
* memsets would work as intended), that *wouldn't* be
* returned by j2s itself.
* TODO. */
parsed.preset = ROOM_CREATE_PRIVATE + 1;
if (!RoomCreateRequestFromJson(request, &parsed, &err)) if (!RoomCreateRequestFromJson(request, &parsed, &err))
{ {
HttpResponseStatus(args->context, HTTP_BAD_REQUEST); HttpResponseStatus(args->context, HTTP_BAD_REQUEST);

View file

@ -31,6 +31,7 @@
#include <Matrix.h> #include <Matrix.h>
#include <User.h> #include <User.h>
#include <Room.h>
ROUTE_IMPL(RouteRoomAliases, path, argp) ROUTE_IMPL(RouteRoomAliases, path, argp)
{ {
@ -40,16 +41,15 @@ ROUTE_IMPL(RouteRoomAliases, path, argp)
char *msg; char *msg;
HashMap *response = NULL; HashMap *response = NULL;
HashMap *aliases = NULL;
HashMap *reversealias = NULL;
JsonValue *val; Array *alias = NULL, *arr;
Db *db = args->matrixArgs->db; Db *db = args->matrixArgs->db;
DbRef *ref = NULL;
User *user = NULL; User *user = NULL;
size_t i;
if (HttpRequestMethodGet(args->context) != HTTP_GET) if (HttpRequestMethodGet(args->context) != HTTP_GET)
{ {
msg = "Route only accepts GET."; msg = "Route only accepts GET.";
@ -81,11 +81,10 @@ ROUTE_IMPL(RouteRoomAliases, path, argp)
response = MatrixErrorCreate(M_FORBIDDEN, msg); response = MatrixErrorCreate(M_FORBIDDEN, msg);
goto finish; goto finish;
} }
ref = DbLock(db, 1, "aliases"); alias = RoomReverseAlias(db, roomId);
aliases = DbJson(ref); if (!alias)
reversealias = JsonValueAsObject(JsonGet(aliases, 2, "id", roomId));
if (!reversealias)
{ {
/* We do not know about the room ID. */ /* We do not know about the room ID. */
msg = "Unknown room ID."; msg = "Unknown room ID.";
@ -93,12 +92,17 @@ ROUTE_IMPL(RouteRoomAliases, path, argp)
response = MatrixErrorCreate(M_INVALID_PARAM, msg); response = MatrixErrorCreate(M_INVALID_PARAM, msg);
goto finish; goto finish;
} }
arr = ArrayCreate();
for (i = 0; i < ArraySize(alias); i++)
{
char *str = ArrayGet(alias, i);
ArrayAdd(arr, JsonValueString(str));
}
response = HashMapCreate(); response = HashMapCreate();
val = JsonGet(reversealias, 1, "aliases"); HashMapSet(response, "aliases", JsonValueArray(arr));
HashMapSet(response, "aliases", JsonValueDuplicate(val));
finish: finish:
DbUnlock(db, ref); RoomFreeReverse(alias);
UserUnlock(user); UserUnlock(user);
return response; return response;
} }

View file

@ -176,4 +176,27 @@ extern HashMap * RoomEventCreate(char *, char *, char *, HashMap *);
*/ */
extern uint64_t RoomGetDepth(Room *); extern uint64_t RoomGetDepth(Room *);
/**
* Tries to find an alias from room alias to an ID stored
* on the heap, or NULL if it does not exist.
*/
extern char * RoomResolveAlias(Db *, char *);
/**
* Tries to resolve a list of aliases from a room ID into
* an array of strings stored on the heap.
*/
extern Array * RoomReverseAlias(Db *, char *);
/**
* Frees the array returned by
* .Fn RoomReverseAlias .
*/
extern void RoomFreeReverse(Array *);
/**
* Adds or overwrites a room alias.
*/
extern void RoomAddAlias(Db *, char *, char *, char *, char *);
#endif /* TELODENDRIA_ROOM_H */ #endif /* TELODENDRIA_ROOM_H */