Implement retrieving a single event over federation
Fix url encoding during homeserver signature check
This commit is contained in:
parent
1881b7f3d6
commit
e510c3bb6a
14 changed files with 173 additions and 22 deletions
|
@ -12,8 +12,18 @@ defmodule MatrixServerWeb.Federation.AuthenticateServer do
|
|||
method: method,
|
||||
query_string: query_string
|
||||
}) do
|
||||
# TODO: This will break if request ends with '?'.
|
||||
uri = URI.decode_www_form(path)
|
||||
|
||||
uri =
|
||||
if String.length(query_string) > 0 do
|
||||
uri <> "?" <> URI.decode_www_form(query_string)
|
||||
else
|
||||
uri
|
||||
end
|
||||
|
||||
object_to_sign = %{
|
||||
uri: path <> "?" <> URI.decode_www_form(query_string),
|
||||
uri: uri,
|
||||
method: method,
|
||||
destination: MatrixServer.server_name()
|
||||
}
|
||||
|
@ -39,6 +49,7 @@ defmodule MatrixServerWeb.Federation.AuthenticateServer do
|
|||
ServerKeyInfo.with_fresh_signing_keys(origin) do
|
||||
Enum.find_value(keys, false, fn %SigningKey{signing_key: signing_key} ->
|
||||
with {:ok, decoded_key} <- MatrixServer.decode_base64(signing_key) do
|
||||
IO.puts(encoded_object)
|
||||
MatrixServer.sign_verify(raw_sig, encoded_object, decoded_key)
|
||||
else
|
||||
_ -> false
|
||||
|
|
|
@ -2,9 +2,44 @@ defmodule MatrixServerWeb.Federation.EventController do
|
|||
use MatrixServerWeb, :controller
|
||||
use MatrixServerWeb.Federation.AuthenticateServer
|
||||
|
||||
def event(conn, %{"event_id" => _event_id}) do
|
||||
conn
|
||||
|> put_status(200)
|
||||
|> json(%{})
|
||||
import MatrixServerWeb.Error
|
||||
import Ecto.Query
|
||||
|
||||
alias MatrixServer.{Repo, Event, RoomServer}
|
||||
alias MatrixServerWeb.Federation.Transaction
|
||||
|
||||
def event(%Plug.Conn{assigns: %{origin: origin}} = conn, %{"event_id" => event_id}) do
|
||||
query =
|
||||
Event
|
||||
|> where([e], e.event_id == ^event_id)
|
||||
|> preload(:room)
|
||||
|
||||
case Repo.one(query) do
|
||||
%Event{room: room} = event ->
|
||||
case RoomServer.get_room_server(room) do
|
||||
{:ok, pid} ->
|
||||
if RoomServer.server_in_room(pid, origin) do
|
||||
data = Transaction.new([event])
|
||||
|
||||
conn
|
||||
|> put_status(200)
|
||||
|> json(data)
|
||||
else
|
||||
put_error(
|
||||
conn,
|
||||
:unauthorized,
|
||||
"Origin server is not allowed to see requested event."
|
||||
)
|
||||
end
|
||||
|
||||
_ ->
|
||||
put_error(conn, :unknown)
|
||||
end
|
||||
|
||||
nil ->
|
||||
put_error(conn, :not_found, "Event or room not found.")
|
||||
end
|
||||
end
|
||||
|
||||
def event(conn, _), do: put_error(conn, :bad_json)
|
||||
end
|
||||
|
|
|
@ -20,7 +20,7 @@ defmodule MatrixServerWeb.Federation.KeyController do
|
|||
server_name: MatrixServer.server_name(),
|
||||
verify_keys: keys,
|
||||
old_verify_keys: %{},
|
||||
valid_until_ts: valid_until
|
||||
valid_until_ts: DateTime.to_unix(valid_until, :millisecond)
|
||||
}
|
||||
|
||||
case KeyServer.sign_object(data) do
|
||||
|
|
|
@ -29,7 +29,9 @@ defmodule MatrixServerWeb.Federation.HTTPClient do
|
|||
with {:ok,
|
||||
%GetSigningKeys{server_name: server_name, verify_keys: verify_keys, signatures: sigs} =
|
||||
response} <- tesla_request(:get, client, path, GetSigningKeys),
|
||||
{:ok, encoded_body} <- MatrixServer.serialize_and_encode(response),
|
||||
serializable_response <- MatrixServer.to_serializable_map(response),
|
||||
serializable_response <- Map.drop(serializable_response, [:signatures]),
|
||||
{:ok, encoded_body} <- MatrixServer.encode_canonical_json(serializable_response),
|
||||
server_sigs when not is_nil(server_sigs) <- sigs[server_name] do
|
||||
# For each verify key, check if there is a matching signature.
|
||||
# If not, invalidate the whole response.
|
||||
|
@ -58,12 +60,20 @@ defmodule MatrixServerWeb.Federation.HTTPClient do
|
|||
Tesla.get(client, path)
|
||||
end
|
||||
|
||||
def get_event(client, event_id) do
|
||||
path = RouteHelpers.event_path(Endpoint, :event, event_id)
|
||||
|
||||
Tesla.get(client, path)
|
||||
end
|
||||
|
||||
defp tesla_request(method, client, path, request_schema) do
|
||||
with {:ok, %Tesla.Env{body: body}} <- Tesla.request(client, url: path, method: method),
|
||||
%Ecto.Changeset{valid?: true} = cs <- apply(request_schema, :changeset, [body]) do
|
||||
{:ok, Ecto.Changeset.apply_changes(cs)}
|
||||
else
|
||||
_ -> :error
|
||||
x ->
|
||||
IO.inspect(x)
|
||||
:error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
36
lib/matrix_server_web/federation/transaction.ex
Normal file
36
lib/matrix_server_web/federation/transaction.ex
Normal file
|
@ -0,0 +1,36 @@
|
|||
defmodule MatrixServerWeb.Federation.Transaction do
|
||||
alias MatrixServer.Event
|
||||
alias MatrixServerWeb.Federation.Transaction
|
||||
|
||||
# TODO
|
||||
@type edu :: any()
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
origin: String.t(),
|
||||
origin_server_ts: integer(),
|
||||
pdus: [Event.t()],
|
||||
edus: [edu()] | nil
|
||||
}
|
||||
|
||||
defstruct [:origin, :origin_server_ts, :pdus, :edus]
|
||||
|
||||
defimpl Jason.Encoder, for: Transaction do
|
||||
@fields [:origin, :origin_server_ts, :pdus, :edus]
|
||||
|
||||
def encode(transaction, opts) do
|
||||
transaction
|
||||
|> Map.take(@fields)
|
||||
|> Jason.Encode.map(opts)
|
||||
end
|
||||
end
|
||||
|
||||
@spec new([Event.t()], [edu()] | nil) :: t()
|
||||
def new(pdu_events, edus \\ nil) do
|
||||
%Transaction{
|
||||
origin: MatrixServer.server_name(),
|
||||
origin_server_ts: System.os_time(:millisecond),
|
||||
pdus: Enum.map(pdu_events, &MatrixServer.to_serializable_map/1),
|
||||
edus: edus
|
||||
}
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue