From a9c23e1c321c1bee5f315604358f3208a95784bb Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 12 Dec 2017 10:17:21 +0100 Subject: [PATCH] Add plug to validate signed http requests. --- lib/pleroma/plugs/http_signature.ex | 19 +++++++++++++++++++ lib/pleroma/user.ex | 10 ++++++++++ .../web/http_signatures/http_signatures.ex | 15 ++++++++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 lib/pleroma/plugs/http_signature.ex diff --git a/lib/pleroma/plugs/http_signature.ex b/lib/pleroma/plugs/http_signature.ex new file mode 100644 index 000000000..17030cdbf --- /dev/null +++ b/lib/pleroma/plugs/http_signature.ex @@ -0,0 +1,19 @@ +defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do + alias Pleroma.Web.HTTPSignatures + import Plug.Conn + + def init(options) do + options + end + + def call(conn, opts) do + if get_req_header(conn, "signature") do + conn = conn + |> put_req_header("(request-target)", String.downcase("#{conn.method} #{conn.request_path}")) + + assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn)) + else + conn + end + end +end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 09bcf0cb4..4580f30fb 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -376,4 +376,14 @@ def delete (%User{} = user) do :ok end + + def get_public_key_for_ap_id(ap_id) do + with %User{} = user <- get_cached_by_ap_id(ap_id), + %{info: %{"magic_key" => magic_key}} <- user, + public_key <- Pleroma.Web.Salmon.decode_key(magic_key) do + {:ok, public_key} + else + _ -> :error + end + end end diff --git a/lib/pleroma/web/http_signatures/http_signatures.ex b/lib/pleroma/web/http_signatures/http_signatures.ex index 8603cb671..830ddf64d 100644 --- a/lib/pleroma/web/http_signatures/http_signatures.ex +++ b/lib/pleroma/web/http_signatures/http_signatures.ex @@ -1,5 +1,7 @@ # https://tools.ietf.org/html/draft-cavage-http-signatures-08 defmodule Pleroma.Web.HTTPSignatures do + alias Pleroma.User + def split_signature(sig) do default = %{"headers" => "date"} @@ -18,7 +20,18 @@ def split_signature(sig) do def validate(headers, signature, public_key) do sigstring = build_signing_string(headers, signature["headers"]) {:ok, sig} = Base.decode64(signature["signature"]) - verify = :public_key.verify(sigstring, :sha256, sig, public_key) + :public_key.verify(sigstring, :sha256, sig, public_key) + end + + def validate_conn(conn) do + # TODO: How to get the right key and see if it is actually valid for that request. + # For now, fetch the key for the actor. + with actor_id <- conn.params["actor"], + {:ok, public_key} <- User.get_public_key_for_ap_id(actor_id) do + validate_conn(conn, public_key) + else + _ -> false + end end def validate_conn(conn, public_key) do