2021-09-01 12:43:55 +00:00
|
|
|
defmodule ArchitexWeb.Federation.Middleware.SignRequest do
|
2021-08-14 13:20:42 +00:00
|
|
|
@behaviour Tesla.Middleware
|
|
|
|
|
|
|
|
def call(%Tesla.Env{opts: opts} = env, next, _opts) do
|
|
|
|
sign = Keyword.get(opts, :sign, true)
|
|
|
|
|
|
|
|
case sign_request(env, sign) do
|
|
|
|
%Tesla.Env{} = env -> Tesla.run(env, next)
|
|
|
|
:error -> {:error, :sign_request}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defp sign_request(env, false), do: env
|
|
|
|
|
2021-08-14 15:15:02 +00:00
|
|
|
defp sign_request(%Tesla.Env{method: method, url: path, opts: opts, body: body} = env, true) do
|
2021-09-01 12:43:55 +00:00
|
|
|
origin = Architex.server_name()
|
2021-08-14 13:20:42 +00:00
|
|
|
|
|
|
|
object_to_sign = %{
|
|
|
|
method: Atom.to_string(method) |> String.upcase(),
|
|
|
|
origin: origin,
|
|
|
|
uri: URI.decode_www_form(path),
|
|
|
|
destination: Keyword.fetch!(opts, :server_name)
|
|
|
|
}
|
|
|
|
|
2021-08-14 15:15:02 +00:00
|
|
|
object_to_sign =
|
|
|
|
if not is_nil(body), do: Map.put(object_to_sign, :content, body), else: object_to_sign
|
|
|
|
|
2021-09-01 12:43:55 +00:00
|
|
|
with {:ok, sig, key_id} <- Architex.KeyServer.sign_object(object_to_sign) do
|
2021-08-14 13:20:42 +00:00
|
|
|
sigs = %{origin => %{key_id => sig}}
|
|
|
|
auth_headers = create_signature_authorization_headers(sigs, origin)
|
|
|
|
|
|
|
|
Tesla.put_headers(env, auth_headers)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defp create_signature_authorization_headers(signatures, origin) do
|
|
|
|
Enum.map(signatures[origin], fn {key, sig} ->
|
|
|
|
{"Authorization", "X-Matrix origin=#{origin},key=\"#{key}\",sig=\"#{sig}\""}
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
end
|