[ADD/UNTESTED] Finalise powerlevels somewhat
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

Still too hacky for my taste...
This commit is contained in:
lda 2024-05-15 12:51:32 +02:00
parent 878b294030
commit 3066a0e8a8

View file

@ -26,6 +26,7 @@
#include <Cytoplasm/Array.h>
#include <Cytoplasm/Json.h>
/*#include "Cytoplasm/Stream.h"*/
#include "Cytoplasm/HashMap.h"
#include "Parser.h"
#include "User.h"
#include <Room.h>
@ -846,7 +847,7 @@ AuthoriseMemberV1(Room * room, PduV1 pdu)
/* Step 5.2: If membership is join. */
JumpIfMembership("join", AuthorizeJoinMembershipV1);
/* Step 5.3: If membership is invite. TODO */
/* Step 5.3: If membership is invite. */
JumpIfMembership("invite", AuthorizeInviteMembershipV1);
/* Step 5.4: If membership is leave. */
@ -862,9 +863,177 @@ AuthoriseMemberV1(Room * room, PduV1 pdu)
static bool
AuthorisePowerLevelsV1(Room * room, PduV1 pdu)
{
/* TODO: Implement this. */
(void) room;
(void) pdu;
/* Step 10.1: If the users property in content is not an object with
* keys that are valid user IDs with values that are integers
* (or a string that is an integer), reject. */
JsonValue *users = JsonGet(pdu.content, 1, "users");
HashMap *users_o, *state, *prev_plevent;
char *user_id, *prev_pl_id, *ev_type;
JsonValue *power_level, *ev_obj;
bool flag = true;
int64_t userpl = RoomUserPL(room, pdu.event_id, pdu.sender);
HashMap *event_obj;
if (JsonValueType(users) != JSON_OBJECT)
{
return false;
}
users_o = JsonValueAsObject(users);
while (HashMapIterate(users_o, &user_id, (void **) &power_level))
{
CommonID as_cid;
if (!flag)
{
continue;
}
if (!ParseCommonID(user_id, &as_cid))
{
flag = false;
}
if (as_cid.sigil != '@')
{
CommonIDFree(as_cid);
flag = false;
}
/* Verify powerlevels.
* We'll use INT64_MAX as a sentinel value, as this isn't
* a valid powervalue for the specification. */
if (ParsePL(power_level, INT64_MAX) == INT64_MAX)
{
flag = false;
}
}
/* HashMapIterate does not support breaking, so we just set a
* flag to be used. */
if (!flag)
{
return false;
}
/* Step 10.2: If there is no previous m.room.power_levels event
* in the room, allow. */
state = RoomStateGetID(room, pdu.event_id);
if (!(prev_pl_id = StateGet(state, "m.room.power_levels", "")))
{
StateFree(state);
return true;
}
/* Step 10.3: For the properties users_default, events_default,
* state_default, ban, redact, kick, invite, check if they were
* added, changed or removed. For each found alteration: */
prev_plevent = RoomEventFetch(room, prev_pl_id);
#define CheckChange(prop) do \
{ \
JsonValue *old = \
JsonGet(prev_plevent, 2, "content", prop);\
JsonValue *new = \
JsonGet(pdu.content, 1, prop); \
int64_t oldv, newv; \
if ((old && !new) || (!old && new) || \
((oldv = JsonValueAsInteger(old)) != \
(newv = JsonValueAsInteger(new)))) \
{ \
if (old && (oldv > userpl)) \
{ \
return false; \
} \
if (new && (newv > userpl)) \
{ \
return false; \
} \
} \
} \
while(0)
CheckChange("users_default");
CheckChange("events_default");
CheckChange("state_default");
CheckChange("ban");
CheckChange("redact");
CheckChange("kick");
CheckChange("invite");
#undef CheckChange
#define CheckPLOld(prop) \
event_obj = \
JsonValueAsObject(JsonGet(prev_plevent, 2, "content", prop)); \
flag = true; \
while (HashMapIterate(event_obj, &ev_type, (void **) &ev_obj)) \
{ \
JsonValue *new; \
int64_t new_pl, old_pl; \
\
if (!flag) \
{ \
continue; \
} \
\
new = JsonGet(pdu.content, 2, prop, ev_type); \
old_pl = ParsePL(new, INT64_MAX); \
if (((new_pl = ParsePL(new, INT64_MAX)) == INT64_MAX || \
new_pl != old_pl) && old_pl > userpl) \
{ \
flag = false; \
} \
} \
if (!flag) \
{ \
JsonFree(prev_plevent); \
StateFree(state); \
return false; \
} \
flag = true
#define CheckPLNew(prop) \
event_obj = \
JsonValueAsObject(JsonGet(pdu.content, 1, prop)); \
flag = true; \
while (HashMapIterate(event_obj, &ev_type, (void **) &ev_obj)) \
{ \
JsonValue *old; \
int64_t new_pl, old_pl; \
\
if (!flag) \
{ \
continue; \
} \
\
old = JsonGet(prev_plevent, 3, "content", prop, ev_type); \
new_pl = ParsePL(ev_obj, INT64_MAX); \
if (((old_pl = ParsePL(old, INT64_MAX)) == INT64_MAX || \
new_pl != old_pl) && new_pl > userpl) \
{ \
flag = false; \
} \
} \
if (!flag) \
{ \
JsonFree(prev_plevent); \
StateFree(state); \
return false; \
} \
flag = true
/* Step 10.4: For each entry being changed in, or removed from, the
* events property:
* - If the current value is greater than the sender's current
* power level, reject. */
CheckPLOld("events");
/* Step 10.5: For each entry being added to, or changed in, the events
* property:
* - If the new value is greater than the sender's current power level,
* reject. */
CheckPLNew("events");
/* Steps 10.6 and 10.7 are effectively the same. */
CheckPLOld("users");
CheckPLNew("users");
#undef CheckPLOld
#undef CheckPLNew
/* Step 10.8: Otherwise, allow. */
JsonFree(prev_plevent);
StateFree(state);
return true;
}
bool