diff --git a/lib/matrix_server/room_server.ex b/lib/matrix_server/room_server.ex index b9b3891..b1d4994 100644 --- a/lib/matrix_server/room_server.ex +++ b/lib/matrix_server/room_server.ex @@ -1,7 +1,9 @@ defmodule MatrixServer.RoomServer do use GenServer - alias MatrixServer.{Repo, Room, Event, Account} + import Ecto.Query + + alias MatrixServer.{Repo, Room, Event, Account, StateResolution} alias MatrixServerWeb.API.CreateRoom @registry MatrixServer.RoomServer.Registry @@ -43,11 +45,33 @@ defmodule MatrixServer.RoomServer do %CreateRoom{room_version: room_version}, room_id ) do - state_set = - Event.create_room(room_id, MatrixServer.get_mxid(localpart), room_version) - |> Repo.insert!() - |> MatrixServer.StateResolution.resolve(true) + create_room_event = Event.create_room(room_id, MatrixServer.get_mxid(localpart), room_version) + verify_event(create_room_event) + |> IO.inspect() - {:ok, state_set} + {:ok, %{}} + end + + defp verify_event(%Event{auth_events: auth_event_ids} = event) do + # Check the following things: + # 1. TODO: Is a valid event, otherwise it is dropped. + # 2. TODO: Passes signature checks, otherwise it is dropped. + # 3. TODO: Passes hash checks, otherwise it is redacted before being processed further. + # 4. Passes authorization rules based on the event's auth events, otherwise it is rejected. + # 5. Passes authorization rules based on the state at the event, otherwise it is rejected. + # 6. TODO: Passes authorization rules based on the current state of the room, otherwise it is "soft failed". + if StateResolution.is_authorized_by_auth_events(event) do + auth_events = + Event + |> where([e], e.event_id in ^auth_event_ids) + |> select([e], {e.event_id, e}) + |> Repo.all() + |> Enum.into(%{}) + # TODO: make the state set a mapping to Event struct. + state_set = StateResolution.resolve(event, false) + StateResolution.is_authorized(event, state_set, auth_events) + else + false + end end end diff --git a/lib/matrix_server/state_resolution.ex b/lib/matrix_server/state_resolution.ex index 548ad93..305a606 100644 --- a/lib/matrix_server/state_resolution.ex +++ b/lib/matrix_server/state_resolution.ex @@ -12,7 +12,7 @@ defmodule MatrixServer.StateResolution do |> Map.put(:auth_events, ["create", "join_charlie", "b"]) end - def resolve(%Event{room_id: room_id} = event, apply_state \\ false) do + def resolve(%Event{room_id: room_id} = event, apply_state) do room_events = Event |> where([e], e.room_id == ^room_id) @@ -31,7 +31,7 @@ defmodule MatrixServer.StateResolution do state_sets = prev_event_ids |> Enum.map(&room_events[&1]) - |> Enum.map(&resolve(&1, room_events)) + |> Enum.map(&resolve(&1, room_events, apply_state)) resolved_state = do_resolve(state_sets, room_events) # TODO: check if state event @@ -55,6 +55,7 @@ defmodule MatrixServer.StateResolution do end def do_resolve(state_sets, room_events, unconflicted_state_map, conflicted_state_set) do + # TODO: make the state set a hashmap instead of a set. full_conflicted_set = MapSet.union(conflicted_state_set, auth_difference(state_sets, room_events)) @@ -82,8 +83,8 @@ defmodule MatrixServer.StateResolution do conflicted_control_events_with_auth_ids |> MapSet.difference(full_conflicted_set) - |> Enum.map(&room_events[&1]) |> Enum.sort(mainline_order(resolved_power_levels, room_events)) + |> Enum.map(&room_events[&1]) |> iterative_auth_checks(partial_resolved_state, room_events) |> Map.merge(unconflicted_state_map) end @@ -205,8 +206,9 @@ defmodule MatrixServer.StateResolution do |> Enum.with_index() |> Enum.into(%{}) - fn %Event{origin_server_ts: timestamp1, event_id: event_id1} = event1, - %Event{origin_server_ts: timestamp2, event_id: event_id2} = event2 -> + fn event_id1, event_id2 -> + %Event{origin_server_ts: timestamp1} = event1 = room_events[event_id1] + %Event{origin_server_ts: timestamp2} = event2 = room_events[event_id2] mainline_depth1 = get_mainline_depth(mainline_map, event1, room_events) mainline_depth2 = get_mainline_depth(mainline_map, event2, room_events) @@ -344,4 +346,21 @@ defmodule MatrixServer.StateResolution do event_id = state_set[{"m.room.create", ""}] room_events[event_id].sender == user end + + def is_authorized_by_auth_events(%Event{auth_events: auth_event_ids} = event) do + # We assume the auth events are validated beforehand. + auth_events = + Event + |> where([e], e.event_id in ^auth_event_ids) + |> select([e], {e.event_id, e}) + |> Repo.all() + |> Enum.into(%{}) + + # TODO: make the state set a mapping to Event struct. + state_set = Enum.reduce(auth_events, %{}, fn {event_id, %Event{type: type, state_key: state_key}}, acc -> + Map.put(acc, {type, state_key}, event_id) + end) + + is_authorized(event, state_set, auth_events) + end end