signature: refetch key upon verification failure
This matches behaviour prioir to the SigningKey migration and the expected semantics of the http_signatures lib. Additionally add a min interval paramter, to avoid refetch floods on bugs causing incompatible signatures (like e.g. currently with Bridgy)
This commit is contained in:
parent
a7b4e4bfd9
commit
9cc5fe9a5f
4 changed files with 38 additions and 3 deletions
|
@ -370,6 +370,7 @@
|
||||||
note_replies_output_limit: 5,
|
note_replies_output_limit: 5,
|
||||||
sign_object_fetches: true,
|
sign_object_fetches: true,
|
||||||
authorized_fetch_mode: false,
|
authorized_fetch_mode: false,
|
||||||
|
min_key_refetch_interval: 86_400,
|
||||||
max_collection_objects: 50
|
max_collection_objects: 50
|
||||||
|
|
||||||
config :pleroma, :streamer,
|
config :pleroma, :streamer,
|
||||||
|
|
|
@ -27,12 +27,18 @@ def fetch_public_key(conn) do
|
||||||
|
|
||||||
def refetch_public_key(conn) do
|
def refetch_public_key(conn) do
|
||||||
with {_, %{"keyId" => kid}} <- {:keyid, HTTPSignatures.signature_for_conn(conn)},
|
with {_, %{"keyId" => kid}} <- {:keyid, HTTPSignatures.signature_for_conn(conn)},
|
||||||
# TODO: force a refetch of stale keys (perhaps with a backoff time based on updated_at)
|
{_, {:ok, %SigningKey{} = sk}, _} <- {:fetch, SigningKey.refresh_by_key_id(kid), kid},
|
||||||
{_, {:ok, %SigningKey{} = sk}, _} <-
|
|
||||||
{:fetch, SigningKey.get_or_fetch_by_key_id(kid), kid},
|
|
||||||
{_, {:ok, decoded_key}} <- {:decode, SigningKey.public_key_decoded(sk)} do
|
{_, {:ok, decoded_key}} <- {:decode, SigningKey.public_key_decoded(sk)} do
|
||||||
{:ok, decoded_key}
|
{:ok, decoded_key}
|
||||||
else
|
else
|
||||||
|
{:fetch, {:error, :too_young}, kid} ->
|
||||||
|
Logger.debug("Refusing to refetch recently updated key: #{kid}")
|
||||||
|
{:error, {:fetch, :too_young}}
|
||||||
|
|
||||||
|
{:fetch, {:error, :unknown}, kid} ->
|
||||||
|
Logger.warning("Attempted to refresh unknown key; this should not happen: #{kid}")
|
||||||
|
{:error, {:fetch, :unknown}}
|
||||||
|
|
||||||
{:fetch, error, kid} ->
|
{:fetch, error, kid} ->
|
||||||
Logger.error("Failed to refresh stale key from signature: #{kid} #{inspect(error)}")
|
Logger.error("Failed to refresh stale key from signature: #{kid} #{inspect(error)}")
|
||||||
{:error, {:fetch, error}}
|
{:error, {:fetch, error}}
|
||||||
|
|
|
@ -218,6 +218,23 @@ def fetch_remote_key(key_id) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp refresh_key(%__MODULE__{} = key) do
|
||||||
|
min_backoff = Pleroma.Config.get!([:activitypub, :min_key_refetch_interval])
|
||||||
|
|
||||||
|
if Timex.diff(Timex.now(), key.updated_at, :seconds) >= min_backoff do
|
||||||
|
fetch_remote_key(key.key_id)
|
||||||
|
else
|
||||||
|
{:error, :too_young}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def refresh_by_key_id(key_id) do
|
||||||
|
case Repo.get_by(__MODULE__, key_id: key_id) do
|
||||||
|
nil -> {:error, :unknown}
|
||||||
|
key -> refresh_key(key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Take the response from the remote instance and extract the key details
|
# Take the response from the remote instance and extract the key details
|
||||||
# will check if the key ID matches the owner of the key, if not, error
|
# will check if the key ID matches the owner of the key, if not, error
|
||||||
defp extract_key_details(%{"id" => ap_id, "publicKey" => public_key}) do
|
defp extract_key_details(%{"id" => ap_id, "publicKey" => public_key}) do
|
||||||
|
|
|
@ -56,8 +56,19 @@ test "it returns error if public key is nil" do
|
||||||
|
|
||||||
describe "refetch_public_key/1" do
|
describe "refetch_public_key/1" do
|
||||||
test "it returns key" do
|
test "it returns key" do
|
||||||
|
clear_config([:activitypub, :min_key_refetch_interval], 0)
|
||||||
ap_id = "https://mastodon.social/users/lambadalambda"
|
ap_id = "https://mastodon.social/users/lambadalambda"
|
||||||
|
|
||||||
|
%Pleroma.User{signing_key: sk} =
|
||||||
|
Pleroma.User.get_or_fetch_by_ap_id(ap_id)
|
||||||
|
|> then(fn {:ok, u} -> u end)
|
||||||
|
|> Pleroma.User.SigningKey.load_key()
|
||||||
|
|
||||||
|
{:ok, _} =
|
||||||
|
%{sk | public_key: "-----BEGIN PUBLIC KEY-----\nasdfghjkl"}
|
||||||
|
|> Ecto.Changeset.change()
|
||||||
|
|> Pleroma.Repo.update()
|
||||||
|
|
||||||
assert Signature.refetch_public_key(make_fake_conn(ap_id)) == {:ok, @rsa_public_key}
|
assert Signature.refetch_public_key(make_fake_conn(ap_id)) == {:ok, @rsa_public_key}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue