forked from Telodendria/Telodendria
[MOD] Start softfailing/dropped, and fix leaks
Some checks failed
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Has been cancelled
Some checks failed
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Has been cancelled
This commit is contained in:
parent
283455b1a0
commit
d07880b24b
7 changed files with 167 additions and 52 deletions
|
@ -2,6 +2,16 @@
|
|||
"guard": "TELODENDRIA_SCHEMA_PDUV1_H",
|
||||
"header": "Schema/PduV1.h",
|
||||
"types": {
|
||||
"PduV1Status": {
|
||||
"type": "enum",
|
||||
"fields": {
|
||||
"dropped": { "name": "PDUV1_STATUS_DROPPED" },
|
||||
"softfail": { "name": "PDUV1_STATUS_SOFTFAIL" },
|
||||
|
||||
"accepted": { "name": "PDUV1_STATUS_ACCEPTED" },
|
||||
"rejected": { "name": "PDUV1_STATUS_REJECTED" }
|
||||
}
|
||||
},
|
||||
"PduV1EventHash": {
|
||||
"type": "struct",
|
||||
"fields": {
|
||||
|
@ -20,6 +30,10 @@
|
|||
"next_events": {
|
||||
"type": "[string]",
|
||||
"required": false
|
||||
},
|
||||
"pdu_status": {
|
||||
"type": "PduV1Status",
|
||||
"required": false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -163,6 +163,7 @@ start:
|
|||
userInfo = NULL;
|
||||
groupInfo = NULL;
|
||||
cron = NULL;
|
||||
tConfig.ok = false;
|
||||
|
||||
token = NULL;
|
||||
|
||||
|
@ -633,9 +634,11 @@ finish:
|
|||
CronFree(cron);
|
||||
Log(LOG_DEBUG, "Stopped and freed job scheduler.");
|
||||
}
|
||||
|
||||
ConfigUnlock(&tConfig);
|
||||
Log(LOG_DEBUG, "Unlocked configuration.");
|
||||
if (tConfig.ok)
|
||||
{
|
||||
ConfigUnlock(&tConfig);
|
||||
Log(LOG_DEBUG, "Unlocked configuration.");
|
||||
}
|
||||
|
||||
DbClose(matrixArgs.db);
|
||||
Log(LOG_DEBUG, "Closed database.");
|
||||
|
|
170
src/Room.c
170
src/Room.c
|
@ -633,6 +633,9 @@ PopulateEventV1(Room * room, HashMap * event, PduV1 * pdu, ServerPart serv)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Consider the PDU dropped by default */
|
||||
pdu->_unsigned.pdu_status = PDUV1_STATUS_DROPPED;
|
||||
|
||||
/* TODO: Create a PDU of our own, signed and everything.
|
||||
* https://telodendria.io/blog/matrix-protocol-overview
|
||||
* has some ideas on how this could be done(up until stage 5). */
|
||||
|
@ -788,7 +791,15 @@ VerifyPDUV1(PduV1 *auth_pdu)
|
|||
/* TODO:
|
||||
* https://spec.matrix.org/v1.7/server-server-api/
|
||||
* #checks-performed-on-receipt-of-a-pdu */
|
||||
(void) auth_pdu;
|
||||
if (RoomIsRejectedV1(*auth_pdu))
|
||||
{
|
||||
Log(LOG_ERR, "Auth PDU has been rejected.");
|
||||
return false;
|
||||
}
|
||||
if (RoomIsSoftfailedV1(*auth_pdu))
|
||||
{
|
||||
Log(LOG_ERR, "Auth PDU has been softfailed.");
|
||||
}
|
||||
return true; /* This only shows whenever an event was rejected, not
|
||||
* soft-failed */
|
||||
}
|
||||
|
@ -1559,6 +1570,41 @@ EventFitsV1(PduV1 pdu)
|
|||
JsonFree(hm);
|
||||
return ret;
|
||||
}
|
||||
static PduV1Status
|
||||
RoomGetEventStatusV1(Room *room, PduV1 *pdu, State *prev, bool client)
|
||||
{
|
||||
if (!room || !pdu || !prev)
|
||||
{
|
||||
return PDUV1_STATUS_DROPPED;
|
||||
}
|
||||
|
||||
if (!EventFitsV1(*pdu))
|
||||
{
|
||||
/* Reject this event as it is too large. */
|
||||
return PDUV1_STATUS_DROPPED;
|
||||
}
|
||||
if (!RoomAuthoriseEventV1(room, *pdu, prev))
|
||||
{
|
||||
/* Reject this event as the current state does not allow it.
|
||||
* TODO: Make the auth check function return a string showing the
|
||||
* errorr status to the user. */
|
||||
return PDUV1_STATUS_DROPPED;
|
||||
}
|
||||
|
||||
if (!client)
|
||||
{
|
||||
State *current = StateCurrent(room);
|
||||
|
||||
if (!RoomAuthoriseEventV1(room, *pdu, current))
|
||||
{
|
||||
StateFree(current);
|
||||
return PDUV1_STATUS_SOFTFAIL;
|
||||
}
|
||||
StateFree(current);
|
||||
}
|
||||
|
||||
return PDUV1_STATUS_ACCEPTED;
|
||||
}
|
||||
static HashMap *
|
||||
RoomEventSendV1(Room * room, HashMap * event)
|
||||
{
|
||||
|
@ -1566,6 +1612,7 @@ RoomEventSendV1(Room * room, HashMap * event)
|
|||
HashMap *pdu_object = NULL;
|
||||
bool client_event, valid = false;
|
||||
State *state = NULL;
|
||||
PduV1Status status;
|
||||
|
||||
client_event = !PopulateEventV1(room, event, &pdu, RoomGetCreator(room));
|
||||
pdu_object = PduV1ToJson(&pdu);
|
||||
|
@ -1630,21 +1677,40 @@ RoomEventSendV1(Room * room, HashMap * event)
|
|||
pdu.hashes.sha256 = RoomHashEventV1(pdu);
|
||||
#undef AddState
|
||||
}
|
||||
/* TODO: It seems like we need to behave differently in terms of
|
||||
* verifying PDUs from the client/federation.
|
||||
* - In the client, we just do not care about any events that
|
||||
* are incorrect. We simply drop them, as if they never existed.
|
||||
* - In the server on the otherhand, the only place where we can
|
||||
* possibly drop events as such is if it fails signatures. In
|
||||
* other cases, we *have* to store it(ableit with flags, to
|
||||
* restrict what we can do).
|
||||
* - Rejection: We avoid relaying/linking those to anything.
|
||||
* They must NOT be used for stateres.
|
||||
* - Softfail: Essentially almost the same as rejects, except
|
||||
* that they *are* used for stateres.
|
||||
* I guess a way to do this may be to add a CheckAuthStatus
|
||||
* function that also verifies if it is a client event, and returns
|
||||
* an enum:
|
||||
* - DROPPED: Do NOT process it _at all_
|
||||
* - REJECT: Process that event as if it was rejected
|
||||
* - SOFTFAIL: Process the event as if it was softfailed
|
||||
* The main issue is storing it in the PDU. A naive approach would be to
|
||||
* add the status to the unsigned field of the PDU, and add functions to
|
||||
* return the status. I guess that is possible, but then again, can we
|
||||
* really abuse the unsigned field for this?
|
||||
*/
|
||||
|
||||
/* TODO: For PDU events, we should verify their hashes. */
|
||||
if (!EventFitsV1(pdu))
|
||||
status = RoomGetEventStatusV1(room, &pdu, state, client_event);
|
||||
Log(LOG_INFO, "status='%s'", PduV1StatusToStr(status));
|
||||
if (status == PDUV1_STATUS_DROPPED)
|
||||
{
|
||||
/* Reject this event as it is too large. */
|
||||
goto finish;
|
||||
}
|
||||
if (!RoomAuthoriseEventV1(room, pdu, state))
|
||||
{
|
||||
/* Reject this event as the current state does not allow it.
|
||||
* TODO: Make the auth check function return a string showing the
|
||||
* errorr status to the user. */
|
||||
goto finish;
|
||||
}
|
||||
StateFree(state);
|
||||
state = NULL;
|
||||
pdu._unsigned.pdu_status = status;
|
||||
|
||||
RoomAddEventV1(room, pdu);
|
||||
valid = true;
|
||||
|
@ -1766,8 +1832,8 @@ bool
|
|||
RoomAddEventV1(Room *room, PduV1 pdu)
|
||||
{
|
||||
DbRef *event_ref;
|
||||
Array *prev_events, *leaves;
|
||||
HashMap *leaves_json, *pdu_json;
|
||||
Array *prev_events = NULL, *leaves = NULL;
|
||||
HashMap *leaves_json = NULL, *pdu_json = NULL;
|
||||
JsonValue *leaves_val;
|
||||
char *safe_id;
|
||||
size_t i;
|
||||
|
@ -1777,37 +1843,41 @@ RoomAddEventV1(Room *room, PduV1 pdu)
|
|||
return false;
|
||||
}
|
||||
|
||||
leaves_json = DbJson(room->leaves_ref);
|
||||
leaves_val = JsonValueDuplicate(JsonGet(leaves_json, 1, "leaves"));
|
||||
leaves = JsonValueAsArray(leaves_val);
|
||||
Free(leaves_val);
|
||||
|
||||
prev_events = pdu.prev_events;
|
||||
for (i = 0; i < ArraySize(prev_events); i++)
|
||||
/* Only accepted PDUs get to do the news */
|
||||
if (pdu._unsigned.pdu_status == PDUV1_STATUS_ACCEPTED)
|
||||
{
|
||||
JsonValue *event_val = ArrayGet(prev_events, i);
|
||||
char *event_id = JsonValueAsString(event_val);
|
||||
size_t j;
|
||||
ssize_t delete_index = -1;
|
||||
leaves_json = DbJson(room->leaves_ref);
|
||||
leaves_val = JsonValueDuplicate(JsonGet(leaves_json, 1, "leaves"));
|
||||
leaves = JsonValueAsArray(leaves_val);
|
||||
Free(leaves_val);
|
||||
|
||||
for (j = 0; j < ArraySize(leaves); j++)
|
||||
prev_events = pdu.prev_events;
|
||||
for (i = 0; i < ArraySize(prev_events); i++)
|
||||
{
|
||||
JsonValue *leaf_val = ArrayGet(leaves, j);
|
||||
HashMap *leaf_object = JsonValueAsObject(leaf_val);
|
||||
char *leaf_id =
|
||||
JsonValueAsString(JsonGet(leaf_object, 1, "event_id"));
|
||||
JsonValue *event_val = ArrayGet(prev_events, i);
|
||||
char *event_id = JsonValueAsString(event_val);
|
||||
size_t j;
|
||||
ssize_t delete_index = -1;
|
||||
|
||||
if (StrEquals(leaf_id, event_id))
|
||||
for (j = 0; j < ArraySize(leaves); j++)
|
||||
{
|
||||
delete_index = j;
|
||||
break;
|
||||
JsonValue *leaf_val = ArrayGet(leaves, j);
|
||||
HashMap *leaf_object = JsonValueAsObject(leaf_val);
|
||||
char *leaf_id =
|
||||
JsonValueAsString(JsonGet(leaf_object, 1, "event_id"));
|
||||
|
||||
if (StrEquals(leaf_id, event_id))
|
||||
{
|
||||
delete_index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (delete_index == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
JsonValueFree(ArrayDelete(leaves, delete_index));
|
||||
}
|
||||
if (delete_index == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
JsonValueFree(ArrayDelete(leaves, delete_index));
|
||||
}
|
||||
|
||||
safe_id = CreateSafeID(pdu.event_id);
|
||||
|
@ -1817,12 +1887,16 @@ RoomAddEventV1(Room *room, PduV1 pdu)
|
|||
pdu_json = PduV1ToJson(&pdu);
|
||||
DbJsonSet(event_ref, pdu_json);
|
||||
|
||||
ArrayAdd(leaves, JsonValueObject(pdu_json));
|
||||
leaves_json = JsonDuplicate(leaves_json);
|
||||
JsonValueFree(HashMapDelete(leaves_json, "leaves"));
|
||||
JsonSet(leaves_json, JsonValueArray(leaves), 1, "leaves");
|
||||
DbJsonSet(room->leaves_ref, leaves_json);
|
||||
JsonFree(leaves_json);
|
||||
/* Only accepted PDUs get to do the news */
|
||||
if (pdu._unsigned.pdu_status == PDUV1_STATUS_ACCEPTED)
|
||||
{
|
||||
ArrayAdd(leaves, JsonValueObject(pdu_json));
|
||||
leaves_json = JsonDuplicate(leaves_json);
|
||||
JsonValueFree(HashMapDelete(leaves_json, "leaves"));
|
||||
JsonSet(leaves_json, JsonValueArray(leaves), 1, "leaves");
|
||||
DbJsonSet(room->leaves_ref, leaves_json);
|
||||
JsonFree(leaves_json);
|
||||
}
|
||||
|
||||
DbUnlock(room->db, event_ref);
|
||||
|
||||
|
@ -2313,3 +2387,15 @@ failure:
|
|||
return NULL;
|
||||
#undef CopyField
|
||||
}
|
||||
|
||||
bool
|
||||
RoomIsSoftfailedV1(PduV1 pdu)
|
||||
{
|
||||
return pdu._unsigned.pdu_status == PDUV1_STATUS_SOFTFAIL;
|
||||
}
|
||||
|
||||
bool
|
||||
RoomIsRejectedV1(PduV1 pdu)
|
||||
{
|
||||
return pdu._unsigned.pdu_status == PDUV1_STATUS_SOFTFAIL;
|
||||
}
|
||||
|
|
|
@ -237,6 +237,7 @@ ROUTE_IMPL(RouteKickRoom, path, argp)
|
|||
id->sigil = '@';
|
||||
sender = ParserRecomposeCommonID(*id);
|
||||
|
||||
Log(LOG_INFO, "sender=%s", sender);
|
||||
room = RoomLock(db, roomId);
|
||||
if (!RoomContainsUser(room, sender))
|
||||
{
|
||||
|
|
|
@ -233,16 +233,13 @@ ROUTE_IMPL(RouteSendState, path, argp)
|
|||
goto finish;
|
||||
}
|
||||
|
||||
Log(LOG_INFO, "State event (%s,%s) coming this way", eventType, stateKey);
|
||||
event = RoomEventCreate(
|
||||
sender,
|
||||
eventType, stateKey ? stateKey : "",
|
||||
JsonDuplicate(request)
|
||||
);
|
||||
filled = RoomEventSend(room, event);
|
||||
Log(LOG_INFO, "State event (%s,%s) coming this way", eventType, stateKey);
|
||||
JsonFree(event);
|
||||
Log(LOG_INFO, "And thats freed!");
|
||||
|
||||
if (!filled)
|
||||
{
|
||||
|
|
12
src/User.c
12
src/User.c
|
@ -1040,7 +1040,7 @@ UserAddInvite(User *user, char *roomId)
|
|||
|
||||
data = DbJson(user->inviteRef);
|
||||
|
||||
JsonFree(HashMapSet(data, roomId, JsonValueNull()));
|
||||
JsonValueFree(HashMapSet(data, roomId, JsonValueNull()));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1091,7 +1091,7 @@ UserAddJoin(User *user, char *roomId)
|
|||
|
||||
if (!HashMapGet(data, roomId))
|
||||
{
|
||||
JsonFree(HashMapSet(data, roomId, JsonValueNull()));
|
||||
JsonValueFree(HashMapSet(data, roomId, JsonValueNull()));
|
||||
}
|
||||
UserNotifyUser(user);
|
||||
}
|
||||
|
@ -1238,7 +1238,9 @@ UserPushJoinSync(User *user, char *roomId)
|
|||
|
||||
if (!HashMapGet(join, roomId))
|
||||
{
|
||||
JsonFree(HashMapSet(join, roomId, JsonValueObject(joinEntry)));
|
||||
JsonValueFree(HashMapSet(join,
|
||||
roomId, JsonValueObject(joinEntry)
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1370,7 +1372,9 @@ UserFillSyncDiff(User *user, char *batch)
|
|||
|
||||
if (!HashMapGet(join, roomId))
|
||||
{
|
||||
JsonFree(HashMapSet(join, roomId, JsonValueObject(joinEntry)));
|
||||
JsonValueFree(HashMapSet(join,
|
||||
roomId, JsonValueObject(joinEntry)
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -236,4 +236,14 @@ extern bool RoomJoin(Room *, User *);
|
|||
*/
|
||||
extern void RoomAddAlias(Db *, char *, char *, char *, char *);
|
||||
|
||||
/**
|
||||
* Checks if a PDU has been qualified as 'soft-failed'.
|
||||
*/
|
||||
extern bool RoomIsSoftfailedV1(PduV1);
|
||||
|
||||
/**
|
||||
* Checks if a PDU has been qualified as 'rejected'.
|
||||
*/
|
||||
extern bool RoomIsRejectedV1(PduV1);
|
||||
|
||||
#endif /* TELODENDRIA_ROOM_H */
|
||||
|
|
Loading…
Reference in a new issue