Add digest, date and request-target in HTTP signature

This commit is contained in:
Chocobozzz 2018-12-07 10:47:31 +01:00
parent ace427c223
commit fa0f47d8e1
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
4 changed files with 55 additions and 6 deletions

View File

@ -15,6 +15,7 @@ defmodule Mobilizon.Service.ActivityPub do
alias Mobilizon.Actors.Actor alias Mobilizon.Actors.Actor
alias Mobilizon.Service.Federator alias Mobilizon.Service.Federator
alias Mobilizon.Service.HTTPSignatures
require Logger require Logger
import Mobilizon.Service.ActivityPub.Utils import Mobilizon.Service.ActivityPub.Utils
@ -277,23 +278,35 @@ defmodule Mobilizon.Service.ActivityPub do
def publish_one(%{inbox: inbox, json: json, actor: actor, id: id}) do def publish_one(%{inbox: inbox, json: json, actor: actor, id: id}) do
Logger.info("Federating #{id} to #{inbox}") Logger.info("Federating #{id} to #{inbox}")
host = URI.parse(inbox).host {host, path} = URI.parse(inbox)
digest = HTTPSignatures.build_digest(json)
date = HTTPSignatures.generate_date_header()
request_target = HTTPSignatures.generate_request_target("POST", path)
signature = signature =
Mobilizon.Service.HTTPSignatures.sign(actor, %{ HTTPSignatures.sign(actor, %{
host: host, host: host,
"content-length": byte_size(json) "content-length": byte_size(json),
"(request-target)": request_target,
digest: digest,
date: date
}) })
HTTPoison.post( HTTPoison.post(
inbox, inbox,
json, json,
[{"Content-Type", "application/activity+json"}, {"signature", signature}], [
{"Content-Type", "application/activity+json"},
{"signature", signature},
{"digest", digest},
{"date", date}
],
hackney: [pool: :default] hackney: [pool: :default]
) )
end end
# Fetching a remote actor's informations through it's AP ID # Fetching a remote actor's informations through it's AP ID
@spec fetch_and_prepare_actor_from_url(String.t()) :: {:ok, struct()} | {:error, atom()} | any() @spec fetch_and_prepare_actor_from_url(String.t()) :: {:ok, struct()} | {:error, atom()} | any()
defp fetch_and_prepare_actor_from_url(url) do defp fetch_and_prepare_actor_from_url(url) do
Logger.debug("Fetching and preparing actor from url") Logger.debug("Fetching and preparing actor from url")

View File

@ -94,6 +94,24 @@ defmodule Mobilizon.Service.HTTPSignatures do
err -> err ->
Logger.error("Unable to sign headers") Logger.error("Unable to sign headers")
Logger.error(inspect(err)) Logger.error(inspect(err))
nil
end end
end end
def generate_date_header(date \\ Timex.now("GMT")) do
with {:ok, date} <- Timex.format(date, "%a, %d %b %Y %H:%M:%S %Z", :strftime) do
date
else
{:error, err} ->
Logger.error("Unable to generate date header")
Logger.error(inspect(err))
nil
end
end
def generate_request_target(method, path), do: "#{method} #{path}"
def build_digest(body) do
"SHA-256=" <> (:crypto.hash(:sha256, body) |> Base.encode64())
end
end end

View File

@ -35,7 +35,7 @@ defmodule Mobilizon.Mixfile do
def application do def application do
[ [
mod: {Mobilizon.Application, []}, mod: {Mobilizon.Application, []},
extra_applications: [:logger, :runtime_tools, :guardian, :bamboo, :geolix] extra_applications: [:logger, :runtime_tools, :guardian, :bamboo, :geolix, :crypto]
] ]
end end

View File

@ -6,6 +6,7 @@ defmodule Mobilizon.Service.Activitypub.ActivitypubTest do
alias Mobilizon.Events alias Mobilizon.Events
alias Mobilizon.Actors.Actor alias Mobilizon.Actors.Actor
alias Mobilizon.Actors alias Mobilizon.Actors
alias Mobilizon.Service.HTTPSignatures
alias Mobilizon.Service.ActivityPub alias Mobilizon.Service.ActivityPub
use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
@ -13,6 +14,23 @@ defmodule Mobilizon.Service.Activitypub.ActivitypubTest do
HTTPoison.start() HTTPoison.start()
end end
describe "setting HTTP signature" do
test "set http signature header" do
actor = insert(:actor)
signature =
HTTPSignatures.sign(actor, %{
host: "example.com",
"content-length": 15,
digest: Jason.encode!(%{id: "my_id"}) |> HTTPSignatures.build_digest(),
"(request-target)": HTTPSignatures.generate_request_target("POST", "/inbox"),
date: HTTPSignatures.generate_date_header()
})
assert signature =~ "headers=\"(request-target) content-length date digest host\""
end
end
describe "fetching actor from it's url" do describe "fetching actor from it's url" do
test "returns an actor from nickname" do test "returns an actor from nickname" do
use_cassette "activity_pub/fetch_tcit@framapiaf.org" do use_cassette "activity_pub/fetch_tcit@framapiaf.org" do