#include "Room/internal.h" #include "Room/V1/Auth/internal.h" #include <Schema/PduV1.h> #include <Cytoplasm/Log.h> #include <Parser.h> static bool VerifyPDUV1(PduV1 *auth_pdu) { /* TODO: The PDU could come from an unknown source, which may lack * the tools to verify softfailing(or we may not trust them)*/ /* TODO: * https://spec.matrix.org/v1.7/server-server-api/ * #checks-performed-on-receipt-of-a-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 */ } static bool ValidAuthEventV1(PduV1 *auth_pdu, PduV1 *pdu) { if (IsState(auth_pdu, "m.room.create", "")) { return true; } if (IsState(auth_pdu, "m.room.power_levels", "")) { /* TODO: Check if it's the latest in terms of [pdu] */ return true; } if (IsState(auth_pdu, "m.room.member", pdu->sender)) { /* TODO: Check if it's the latest in terms of [pdu] */ return true; } if (StrEquals(pdu->type, "m.room.member")) { char *membership = JsonValueAsString(JsonGet(pdu->content, 1, "membership")); JsonValue *third_pid = JsonGet(pdu->content, 1, "third_party_invite"); /* The PDU's state_key is the target. So we check if if the * auth PDU would count as the target's membership. Was very fun to * find that out when I wanted to kick my 'yukari' alt. */ if (IsState(auth_pdu, "m.room.member", pdu->state_key)) { /* TODO: Check if it's the latest in terms of [pdu] */ return true; } if ((StrEquals(membership, "join") || StrEquals(membership, "invite")) && IsState(auth_pdu, "m.room.join_rules","")) { /* TODO: Check if it's the latest in terms of [pdu] */ return true; } if (StrEquals(membership, "invite") && third_pid) { HashMap *tpid = JsonValueAsObject(third_pid); JsonValue *token = JsonGet(tpid, 2, "signed", "token"); char *token_str = JsonValueAsString(token); if (IsState(auth_pdu, "m.room.third_party_invite", token_str)) { /* TODO: Check if it is the latest. */ return true; } } /* V1 simply doesn't have the concept of restricted rooms, * so we can safely skip this one for this function. */ } return false; } bool ConsiderAuthEventsV1(Room * room, PduV1 pdu, char **errp) { char *ignored; size_t i; bool room_create = false; HashMap *state_keytype; state_keytype = HashMapCreate(); for (i = 0; i < ArraySize(pdu.auth_events); i++) { char *event_id = JsonValueAsString(ArrayGet(pdu.auth_events, i)); HashMap *event = RoomEventFetchRaw(room, event_id); PduV1 auth_pdu = { 0 }; char *key_type_id; if (!PduV1FromJson(event, &auth_pdu, &ignored)) { JsonFree(event); HashMapFree(state_keytype); if (errp) { *errp = "Couldn't parse an auth event"; } return false; /* Yeah... we aren't doing that. */ } /* TODO: Find a better way to do this. Using HashMaps as sets * *works*, but it's not the best of ideas here. Also, we're using * strings to compare things, which yeah. */ key_type_id = StrConcat(3, auth_pdu.type, ",", auth_pdu.state_key); if (HashMapGet(state_keytype, key_type_id)) { /* Duplicate found! We actually ignore it's actual value. */ if (errp) { *errp = "Duplicate auth event was found"; } JsonFree(event); PduV1Free(&auth_pdu); HashMapFree(state_keytype); Free(key_type_id); return false; } /* Whenever event is valid or not really doesn't matter, as we're * not using it's value anywhere. */ HashMapSet(state_keytype, key_type_id, event); Free(key_type_id); /* Step 2.2: If there are entries whose type and state_key don't * match those specified by the auth events selection algorithm * described in the server specification, reject. */ if (!ValidAuthEventV1(&auth_pdu, &pdu)) { if (errp) { *errp = "Invalid authevent given."; } JsonFree(event); PduV1Free(&auth_pdu); HashMapFree(state_keytype); return false; } /* Step 2.3: If there are entries which were themselves rejected * under the checks performed on receipt of a PDU, reject. * TODO */ if (!VerifyPDUV1(&auth_pdu)) { if (errp) { *errp = "Event depends on rejected PDUs"; } PduV1Free(&auth_pdu); JsonFree(event); HashMapFree(state_keytype); return false; } /* Step 2.4: If there is no m.room.create event among the entries, * reject. */ if (!room_create && IsState(&auth_pdu, "m.room.create", "")) { room_create = true; /* Here, we check for the opposite. */ } JsonFree(event); PduV1Free(&auth_pdu); } HashMapFree(state_keytype); if (!room_create && errp) { *errp = "Room creation event was not in the PDU's auth events"; } return room_create; /* Step 2.4 is actually done here. */ }