diff --git a/lib/matrix_server/room_server.ex b/lib/matrix_server/room_server.ex index 1a1c811..7436c93 100644 --- a/lib/matrix_server/room_server.ex +++ b/lib/matrix_server/room_server.ex @@ -9,11 +9,6 @@ defmodule MatrixServer.RoomServer do @registry MatrixServer.RoomServer.Registry @supervisor MatrixServer.RoomServer.Supervisor - def start_link(opts) do - {name, opts} = Keyword.pop(opts, :name) - GenServer.start_link(__MODULE__, opts, name: name) - end - def create_room(input, account) do %Room{id: room_id} = room = Repo.insert!(Room.create_changeset(input)) @@ -27,6 +22,11 @@ defmodule MatrixServer.RoomServer do DynamicSupervisor.start_child(@supervisor, {__MODULE__, opts}) end + def start_link(opts) do + {name, opts} = Keyword.pop(opts, :name) + GenServer.start_link(__MODULE__, opts, name: name) + end + @impl true def init(opts) do %Room{id: room_id} = Keyword.fetch!(opts, :room) @@ -36,6 +36,8 @@ defmodule MatrixServer.RoomServer do Repo.transaction(fn -> with {:ok, state_set} <- insert_create_room_event(account, input, room_id) do {:ok, %{room_id: room_id, state_set: state_set}} + else + _ -> {:error, :something} end end) end @@ -47,27 +49,30 @@ defmodule MatrixServer.RoomServer do ) do create_room_event = Event.create_room(room_id, MatrixServer.get_mxid(localpart), room_version) - verify_and_insert_event(create_room_event) - - {:ok, %{}} + verify_and_insert_event(create_room_event, %{}) end - defp verify_and_insert_event(event) do + defp verify_and_insert_event(event, current_state_set) 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". + # 6. 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 state_set = StateResolution.resolve(event, false) if StateResolution.is_authorized(event, state_set) do - # TODO: Assume the event is a forward extremity, should check this actually. - Room.update_forward_extremities(event) - {:ok, event} = Repo.insert(event) - {:ok, state_set} + if StateResolution.is_authorized(event, current_state_set) do + # TODO: Assume the event is a forward extremity, should check this actually. + Room.update_forward_extremities(event) + {:ok, event} = Repo.insert(event) + state_set = StateResolution.resolve_forward_extremities(event) + {:ok, state_set} + else + {:error, :soft_failed} + end else {:error, :rejected} end diff --git a/lib/matrix_server/state_resolution.ex b/lib/matrix_server/state_resolution.ex index 094cf16..8591664 100644 --- a/lib/matrix_server/state_resolution.ex +++ b/lib/matrix_server/state_resolution.ex @@ -1,7 +1,9 @@ defmodule MatrixServer.StateResolution do import Ecto.Query - alias MatrixServer.{Repo, Event} + alias MatrixServer.{Repo, Event, Room} + + def resolve(event), do: resolve(event, true) def resolve(%Event{room_id: room_id} = event, apply_state) do room_events = @@ -322,6 +324,23 @@ defmodule MatrixServer.StateResolution do is_authorized(event, state_set) end + def resolve_forward_extremities(%Event{room_id: room_id}) do + room_events = + Event + |> where([e], e.room_id == ^room_id) + |> select([e], {e.event_id, e}) + |> Repo.all() + |> Enum.into(%{}) + + Event + |> where([e], e.room_id == ^room_id) + |> join(:inner, [e], r in Room, on: e.room_id == r.id) + |> where([e, r], e.event_id == fragment("ANY(?)", r.forward_extremities)) + |> Repo.all() + |> Enum.map(&resolve/1) + |> do_resolve(room_events) + end + def testing do %Event{content: content} = event = Event.power_levels("room1", "charlie") event = %Event{event | content: %{content | "ban" => 0}} diff --git a/priv/repo/migrations/20210725151601_add_state_to_room.exs b/priv/repo/migrations/20210725151601_add_state_to_room.exs new file mode 100644 index 0000000..f7bc549 --- /dev/null +++ b/priv/repo/migrations/20210725151601_add_state_to_room.exs @@ -0,0 +1,9 @@ +defmodule MatrixServer.Repo.Migrations.AddStateToRoom do + use Ecto.Migration + + def change do + alter table(:rooms) do + add :state, :map, default: %{}, null: false + end + end +end