From 3c93ddd76844dc3181921f5769a5000afee58160 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Mon, 26 Jul 2021 23:42:35 +0200 Subject: [PATCH] Save name and topic events when creating room --- lib/matrix_server/event.ex | 38 ++++++----- lib/matrix_server/room.ex | 23 +++---- lib/matrix_server/room_server.ex | 111 +++++++++++++++++++++---------- priv/repo/seeds.exs | 23 ++++--- 4 files changed, 119 insertions(+), 76 deletions(-) diff --git a/lib/matrix_server/event.ex b/lib/matrix_server/event.ex index df0473b..f5b6840 100644 --- a/lib/matrix_server/event.ex +++ b/lib/matrix_server/event.ex @@ -17,7 +17,7 @@ defmodule MatrixServer.Event do belongs_to :room, Room, type: :string end - def new(room_id, sender) do + def new(%Room{id: room_id}, sender) do %Event{ room_id: room_id, sender: sender, @@ -28,9 +28,9 @@ defmodule MatrixServer.Event do } end - def create_room(room_id, creator, room_version) do + def create_room(room, creator, room_version) do %Event{ - new(room_id, creator) + new(room, creator) | type: "m.room.create", state_key: "", content: %{ @@ -40,9 +40,9 @@ defmodule MatrixServer.Event do } end - def join(room_id, sender) do + def join(room, sender) do %Event{ - new(room_id, sender) + new(room, sender) | type: "m.room.member", state_key: sender, content: %{ @@ -51,9 +51,9 @@ defmodule MatrixServer.Event do } end - def power_levels(room_id, sender) do + def power_levels(room, sender) do %Event{ - new(room_id, sender) + new(room, sender) | type: "m.room.power_levels", state_key: "", content: %{ @@ -75,9 +75,9 @@ defmodule MatrixServer.Event do } end - def room_name(room_id, sender, name) do + def name(room, sender, name) do %Event{ - new(room_id, sender) + new(room, sender) | type: "m.room.name", state_key: "", content: %{ @@ -86,9 +86,9 @@ defmodule MatrixServer.Event do } end - def room_topic(room_id, sender, topic) do + def topic(room, sender, topic) do %Event{ - new(room_id, sender) + new(room, sender) | type: "m.room.topic", state_key: "", content: %{ @@ -122,13 +122,15 @@ defmodule MatrixServer.Event do # We assume that required keys, as well as in the content, is already validated. # Rule 1.4 is left to changeset validation. - def prevalidate(%Event{ - type: "m.room.create", - prev_events: prev_events, - auth_events: auth_events, - room_id: room_id, - sender: sender - }) do + def prevalidate( + %Event{ + type: "m.room.create", + prev_events: prev_events, + auth_events: auth_events, + room_id: room_id, + sender: sender + } = event + ) do # TODO: error check on domains? # TODO: rule 1.3 diff --git a/lib/matrix_server/room.ex b/lib/matrix_server/room.ex index 9d23993..bb9910f 100644 --- a/lib/matrix_server/room.ex +++ b/lib/matrix_server/room.ex @@ -10,6 +10,7 @@ defmodule MatrixServer.Room do @primary_key {:id, :string, []} schema "rooms" do field :visibility, Ecto.Enum, values: [:public, :private] + field :state, :map field :forward_extremities, {:array, :string} has_many :events, Event, foreign_key: :event_id end @@ -21,28 +22,24 @@ defmodule MatrixServer.Room do def create_changeset(%CreateRoom{} = input) do visibility = input.visibility || :public - %Room{} + %Room{id: generate_room_id(), forward_extremities: [], state: %{}} |> changeset(%{visibility: visibility}) - |> put_change(:id, generate_room_id()) end def generate_room_id do "!" <> MatrixServer.random_string(18) <> ":" <> MatrixServer.server_name() end - def update_forward_extremities(%Event{ - event_id: event_id, - prev_events: prev_event_ids, - room_id: room_id - }) do - %Room{forward_extremities: forward_extremities} = - Room - |> where([r], r.id == ^room_id) - |> Repo.one!() - + def update_forward_extremities( + %Event{ + event_id: event_id, + prev_events: prev_event_ids + }, + %Room{id: room_id, forward_extremities: forward_extremities} + ) do new_forward_extremities = [event_id | forward_extremities -- prev_event_ids] - {_, [room | _]} = + {_, [room]} = from(r in Room, where: r.id == ^room_id, select: r) |> Repo.update_all(set: [forward_extremities: new_forward_extremities]) diff --git a/lib/matrix_server/room_server.ex b/lib/matrix_server/room_server.ex index cba4cd7..79d9462 100644 --- a/lib/matrix_server/room_server.ex +++ b/lib/matrix_server/room_server.ex @@ -29,28 +29,37 @@ defmodule MatrixServer.RoomServer do @impl true def init(opts) do - %Room{id: room_id} = room = Keyword.fetch!(opts, :room) + room = Keyword.fetch!(opts, :room) input = Keyword.fetch!(opts, :input) account = Keyword.fetch!(opts, :account) - state_set = %{} - Repo.transaction(fn -> - with {:ok, create_room_event, state_set} <- - room_creation_create_room(account, input, room, state_set), - {:ok, join_creator_event, state_set} <- - room_creation_join_creator(account, room, state_set, create_room_event), - {:ok, _power_levels_event, state_set} <- + with {:ok, create_room_id, state_set, room} <- + room_creation_create_room(account, input, room), + {:ok, join_creator_id, state_set, room} <- + room_creation_join_creator(account, room, state_set, [create_room_id]), + {:ok, pl_id, state_set, room} <- room_creation_power_levels( account, room, state_set, - create_room_event, - join_creator_event - ) do - {:ok, %{room_id: room_id, state_set: state_set}} + [create_room_id, join_creator_id] + ), + {:ok, _, state_set, room} <- + room_creation_name(account, input, room, state_set, [ + create_room_id, + join_creator_id, + pl_id + ]), + {:ok, _, state_set, room} <- + room_creation_topic(account, input, room, state_set, [ + create_room_id, + join_creator_id, + pl_id + ]) do + {:ok, %{room: room, state_set: state_set}} else - _ -> {:error, :something} + _ -> {:error, :validation} end end) end @@ -58,39 +67,71 @@ defmodule MatrixServer.RoomServer do defp room_creation_create_room( %Account{localpart: localpart}, %CreateRoom{room_version: room_version}, - %Room{id: room_id}, - _state_set + room ) do - Event.create_room(room_id, MatrixServer.get_mxid(localpart), room_version) - |> verify_and_insert_event(%{}) + Event.create_room(room, MatrixServer.get_mxid(localpart), room_version) + |> verify_and_insert_event(%{}, room) end defp room_creation_join_creator( %Account{localpart: localpart}, - %Room{id: room_id}, + room, state_set, - %Event{event_id: create_room_id} + auth_events ) do - Event.join(room_id, MatrixServer.get_mxid(localpart)) - |> Map.put(:auth_events, [create_room_id]) - |> Map.put(:prev_events, [create_room_id]) - |> verify_and_insert_event(state_set) + Event.join(room, MatrixServer.get_mxid(localpart)) + |> Map.put(:auth_events, auth_events) + |> verify_and_insert_event(state_set, room) end defp room_creation_power_levels( %Account{localpart: localpart}, - %Room{id: room_id}, + room, state_set, - %Event{event_id: create_room_id}, - %Event{event_id: join_creator_id} + auth_events ) do - Event.power_levels(room_id, MatrixServer.get_mxid(localpart)) - |> Map.put(:auth_events, [create_room_id, join_creator_id]) - |> Map.put(:prev_events, [join_creator_id]) - |> verify_and_insert_event(state_set) + Event.power_levels(room, MatrixServer.get_mxid(localpart)) + |> Map.put(:auth_events, auth_events) + |> verify_and_insert_event(state_set, room) end - defp verify_and_insert_event(event, current_state_set) do + defp room_creation_name(_, %CreateRoom{name: nil}, room, state_set, _) do + {:ok, nil, state_set, room} + end + + defp room_creation_name( + %Account{localpart: localpart}, + %CreateRoom{name: name}, + room, + state_set, + auth_events + ) do + Event.name(room, MatrixServer.get_mxid(localpart), name) + |> Map.put(:auth_events, auth_events) + |> verify_and_insert_event(state_set, room) + end + + defp room_creation_topic(_, %CreateRoom{topic: nil}, room, state_set, _) do + {:ok, nil, state_set, room} + end + + defp room_creation_topic( + %Account{localpart: localpart}, + %CreateRoom{topic: topic}, + room, + state_set, + auth_events + ) do + Event.topic(room, MatrixServer.get_mxid(localpart), topic) + |> Map.put(:auth_events, auth_events) + |> verify_and_insert_event(state_set, room) + end + + defp verify_and_insert_event( + %Event{event_id: event_id} = event, + current_state_set, + %Room{forward_extremities: forward_extremities} = room + ) do # Check the following things: # 1. TODO: Is a valid event, otherwise it is dropped. # 2. TODO: Passes signature checks, otherwise it is dropped. @@ -98,6 +139,8 @@ defmodule MatrixServer.RoomServer do # 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. Passes authorization rules based on the current state of the room, otherwise it is "soft failed". + event = %Event{event | prev_events: forward_extremities} + if Event.prevalidate(event) do if StateResolution.is_authorized_by_auth_events(event) do state_set = StateResolution.resolve(event, false) @@ -105,10 +148,10 @@ defmodule MatrixServer.RoomServer do if StateResolution.is_authorized(event, state_set) do if StateResolution.is_authorized(event, current_state_set) do # We assume here that the event is always a forward extremity. - Room.update_forward_extremities(event) + room = Room.update_forward_extremities(event, room) {:ok, event} = Repo.insert(event) state_set = StateResolution.resolve_forward_extremities(event) - {:ok, event, state_set} + {:ok, event_id, state_set, room} else {:error, :soft_failed} end @@ -125,6 +168,6 @@ defmodule MatrixServer.RoomServer do def testing do account = Repo.one!(from a in Account, limit: 1) - create_room(%CreateRoom{}, account) + create_room(%CreateRoom{name: "Sneed", topic: "City slickers"}, account) end end diff --git a/priv/repo/seeds.exs b/priv/repo/seeds.exs index e471462..8cc72ea 100644 --- a/priv/repo/seeds.exs +++ b/priv/repo/seeds.exs @@ -14,19 +14,20 @@ Repo.insert(%Device{ # Auth difference example from here: # https://matrix.org/docs/guides/implementing-stateres#auth-differences -Repo.insert!(%Room{ - id: "room1", - visibility: :public -}) +room = + Repo.insert!(%Room{ + id: "room1", + visibility: :public + }) Repo.insert!( - Event.create_room("room1", "alice", "v1") + Event.create_room(room, "alice", "v1") |> Map.put(:origin_server_ts, 0) |> Map.put(:event_id, "create") ) Repo.insert!( - Event.join("room1", "alice") + Event.join(room, "alice") |> Map.put(:prev_events, ["create"]) |> Map.put(:auth_events, ["create"]) |> Map.put(:origin_server_ts, 1) @@ -34,7 +35,7 @@ Repo.insert!( ) Repo.insert!( - Event.join("room1", "bob") + Event.join(room, "bob") |> Map.put(:prev_events, ["join_alice"]) |> Map.put(:auth_events, ["create"]) |> Map.put(:origin_server_ts, 2) @@ -42,14 +43,14 @@ Repo.insert!( ) Repo.insert!( - Event.join("room1", "charlie") + Event.join(room, "charlie") |> Map.put(:prev_events, ["join_bob"]) |> Map.put(:auth_events, ["create"]) |> Map.put(:origin_server_ts, 3) |> Map.put(:event_id, "join_charlie") ) -%Event{content: content} = event = Event.power_levels("room1", "alice") +%Event{content: content} = event = Event.power_levels(room, "alice") event = %Event{event | content: %{content | "users" => %{"alice" => 100, "bob" => 100}}} Repo.insert!( @@ -60,7 +61,7 @@ Repo.insert!( |> Map.put(:event_id, "a") ) -%Event{content: content} = event = Event.power_levels("room1", "bob") +%Event{content: content} = event = Event.power_levels(room, "bob") event = %Event{ event @@ -76,7 +77,7 @@ Repo.insert!( ) Repo.insert!( - Event.room_topic("room1", "alice", "sneed") + Event.topic(room, "alice", "sneed") |> Map.put(:prev_events, ["a"]) |> Map.put(:auth_events, ["create", "join_alice", "a"]) |> Map.put(:origin_server_ts, 5)