Merge branch 'feature/http-signature' into 'master'

Add digest, date and request-target in HTTP signature

See merge request framasoft/mobilizon!24
This commit is contained in:
Thomas Citharel 2018-12-07 16:19:27 +01:00
commit 7cee8c2231
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.Service.Federator
alias Mobilizon.Service.HTTPSignatures
require Logger
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
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 =
Mobilizon.Service.HTTPSignatures.sign(actor, %{
HTTPSignatures.sign(actor, %{
host: host,
"content-length": byte_size(json)
"content-length": byte_size(json),
"(request-target)": request_target,
digest: digest,
date: date
})
HTTPoison.post(
inbox,
json,
[{"Content-Type", "application/activity+json"}, {"signature", signature}],
[
{"Content-Type", "application/activity+json"},
{"signature", signature},
{"digest", digest},
{"date", date}
],
hackney: [pool: :default]
)
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()
defp fetch_and_prepare_actor_from_url(url) do
Logger.debug("Fetching and preparing actor from url")

View file

@ -94,6 +94,24 @@ defmodule Mobilizon.Service.HTTPSignatures do
err ->
Logger.error("Unable to sign headers")
Logger.error(inspect(err))
nil
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

View file

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

View file

@ -6,6 +6,7 @@ defmodule Mobilizon.Service.Activitypub.ActivitypubTest do
alias Mobilizon.Events
alias Mobilizon.Actors.Actor
alias Mobilizon.Actors
alias Mobilizon.Service.HTTPSignatures
alias Mobilizon.Service.ActivityPub
use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
@ -13,6 +14,23 @@ defmodule Mobilizon.Service.Activitypub.ActivitypubTest do
HTTPoison.start()
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
test "returns an actor from nickname" do
use_cassette "activity_pub/fetch_tcit@framapiaf.org" do