websub_controller.ex (2748B)
1 # Pleroma: A lightweight social networking server 2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> 3 # SPDX-License-Identifier: AGPL-3.0-only 4 5 defmodule Pleroma.Web.Websub.WebsubController do 6 use Pleroma.Web, :controller 7 8 alias Pleroma.Repo 9 alias Pleroma.User 10 alias Pleroma.Web.Federator 11 alias Pleroma.Web.Websub 12 alias Pleroma.Web.Websub.WebsubClientSubscription 13 14 require Logger 15 16 plug( 17 Pleroma.Web.FederatingPlug 18 when action in [ 19 :websub_subscription_request, 20 :websub_subscription_confirmation, 21 :websub_incoming 22 ] 23 ) 24 25 def websub_subscription_request(conn, %{"nickname" => nickname} = params) do 26 user = User.get_cached_by_nickname(nickname) 27 28 with {:ok, _websub} <- Websub.incoming_subscription_request(user, params) do 29 conn 30 |> send_resp(202, "Accepted") 31 else 32 {:error, reason} -> 33 conn 34 |> send_resp(500, reason) 35 end 36 end 37 38 # TODO: Extract this into the Websub module 39 def websub_subscription_confirmation( 40 conn, 41 %{ 42 "id" => id, 43 "hub.mode" => "subscribe", 44 "hub.challenge" => challenge, 45 "hub.topic" => topic 46 } = params 47 ) do 48 Logger.debug("Got WebSub confirmation") 49 Logger.debug(inspect(params)) 50 51 lease_seconds = 52 if params["hub.lease_seconds"] do 53 String.to_integer(params["hub.lease_seconds"]) 54 else 55 # Guess 3 days 56 60 * 60 * 24 * 3 57 end 58 59 with %WebsubClientSubscription{} = websub <- 60 Repo.get_by(WebsubClientSubscription, id: id, topic: topic) do 61 valid_until = NaiveDateTime.add(NaiveDateTime.utc_now(), lease_seconds) 62 change = Ecto.Changeset.change(websub, %{state: "accepted", valid_until: valid_until}) 63 {:ok, _websub} = Repo.update(change) 64 65 conn 66 |> send_resp(200, challenge) 67 else 68 _e -> 69 conn 70 |> send_resp(500, "Error") 71 end 72 end 73 74 def websub_subscription_confirmation(conn, params) do 75 Logger.info("Invalid WebSub confirmation request: #{inspect(params)}") 76 77 conn 78 |> send_resp(500, "Invalid parameters") 79 end 80 81 def websub_incoming(conn, %{"id" => id}) do 82 with "sha1=" <> signature <- hd(get_req_header(conn, "x-hub-signature")), 83 signature <- String.downcase(signature), 84 %WebsubClientSubscription{} = websub <- Repo.get(WebsubClientSubscription, id), 85 {:ok, body, _conn} = read_body(conn), 86 ^signature <- Websub.sign(websub.secret, body) do 87 Federator.incoming_doc(body) 88 89 conn 90 |> send_resp(200, "OK") 91 else 92 _e -> 93 Logger.debug("Can't handle incoming subscription post") 94 95 conn 96 |> send_resp(500, "Error") 97 end 98 end 99 end