diff --git a/src/Room.c b/src/Room.c index bdd6398..331a17a 100644 --- a/src/Room.c +++ b/src/Room.c @@ -599,9 +599,101 @@ AuthoriseAliasV1(PduV1 pdu) static bool AuthorizeInviteMembershipV1(Room * room, PduV1 pdu) { - /* TODO */ - (void) room; - (void) pdu; + int64_t invite_level; + int64_t pdu_level; + JsonValue *third_pi; + /* Step 5.3.1: If content has a third_party_invite property */ + if ((third_pi = JsonGet(pdu.content, 1, "third_party_invite"))) + { + JsonValue *signed_val, *mxid, *token; + HashMap *third_pi_obj = JsonValueAsObject(third_pi), *signed_obj; + HashMap *state, *third_pi_event; + char *third_pi_id, *thirdpi_event_sender; + /* Step 5.3.1.1: If target user is banned, reject. */ + if (RoomUserHasMembership(room, pdu.event_id, pdu.state_key, "ban")) + { + return false; + } + /* Step 5.3.1.2: If content.third_party_invite does not have a signed + * property, reject. */ + if (!(signed_val = JsonGet(third_pi_obj, 1, "signed"))) + { + return false; + } + signed_obj = JsonValueAsObject(signed_val); + + /* Step 5.3.1.3: If signed does not have mxid and token properties, + * reject. */ + if (!(mxid = JsonGet(signed_obj, 1, "mxid"))) + { + return false; + } + if (!(token = JsonGet(signed_obj, 1, "token"))) + { + return false; + } + + /* Step 5.3.1.4: If mxid does not match state_key, reject. */ + if (!StrEquals(JsonValueAsString(mxid), pdu.state_key)) + { + return false; + } + + /* Step 5.3.1.5: If there is no m.room.third_party_invite event + * in the current room state with state_key matching token, reject. */ + state = RoomStateGetID(room, pdu.event_id); + if (!(third_pi_id = StateGet( + state, + "m.room.third_party_invite", JsonValueAsString(token)))) + { + StateFree(state); + return false; + } + third_pi_event = RoomEventFetch(room, third_pi_id); + StateFree(state); + + /* Step 5.3.1.6: If sender does not match sender of the + * m.room.third_party_invite, reject. */ + thirdpi_event_sender = JsonValueAsString(JsonGet(third_pi_event, 1, "sender")); + if (!StrEquals(thirdpi_event_sender, pdu.sender)) + { + return false; + } + + /* TODO: + * Step 5.3.1.7: If any signature in signed matches any public key in + * the m.room.third_party_invite event, allow. + * + * The public keys are in content of m.room.third_party_invite as: + * - A single public key in the public_key property. + * - A list of public keys in the public_keys property. */ + + /* Step 5.3.1.8: Otherwise, reject. */ + return false; + } + + /* Step 5.3.2: If the sender's current membership state is not join, + * reject. */ + if (!RoomUserHasMembership(room, pdu.event_id, pdu.sender, "join")) + { + return false; + } + /* Step 5.3.3: If target user’s current membership state is join or ban, reject. */ + if (RoomUserHasMembership(room, pdu.event_id, pdu.state_key, "join") || + RoomUserHasMembership(room, pdu.event_id, pdu.state_key, "join")) + { + return false; + } + + /* Step 5.3.4: If the sender's power level is greater than or equal to the + * invite level, allow. */ + invite_level = RoomMinPL(room, pdu.event_id, NULL, "invite"); + pdu_level = RoomUserPL(room, pdu.event_id, pdu.sender); + if (pdu_level >= invite_level) + { + return true; + } + /* Step 5.3.5: Otherwise, reject. */ return false; } static bool