Only have one subscription per callback.
authorRoger Braun <roger@rogerbraun.net>
Sat, 22 Apr 2017 11:44:21 +0000 (13:44 +0200)
committerRoger Braun <roger@rogerbraun.net>
Sat, 22 Apr 2017 11:44:21 +0000 (13:44 +0200)
config/config.exs
config/test.exs
lib/pleroma/web/websub/websub.ex
lib/pleroma/web/websub/websub_controller.ex
test/web/websub/websub_controller_test.exs
test/web/websub/websub_test.exs

index 18a2490a468d2b06fcbf2ed17fe541ca2831d58d..3826dddff24bf89ceeb7626ad4fb3a0281a745b4 100644 (file)
@@ -30,6 +30,8 @@ config :mime, :types, %{
   "application/xrd+xml" => ["xrd+xml"]
 }
 
+config :pleroma, :websub_verifier, Pleroma.Web.Websub
+
 # Import environment specific config. This must remain at the bottom
 # of this file so it overrides the configuration defined above.
 import_config "#{Mix.env}.exs"
index f5d6f240d4fd20ff2597923d2b0ce5e79fc3518a..5d91279a22ae32927b22760825d6d3e0b73d7e73 100644 (file)
@@ -24,3 +24,5 @@ config :pleroma, Pleroma.Repo,
 
 # Reduce hash rounds for testing
 config :comeonin, :pbkdf2_rounds, 1
+
+config :pleroma, :websub_verifier, Pleroma.Web.WebsubMock
index 26a10788ae38a245752fec70d81a7952dc190ab7..50878e3c4ca4a9d2762c4fec0ccd42ab3323adce 100644 (file)
@@ -3,12 +3,15 @@ defmodule Pleroma.Web.Websub do
   alias Pleroma.Websub
   alias Pleroma.Web.Websub.WebsubServerSubscription
   alias Pleroma.Web.OStatus.FeedRepresenter
+  alias Pleroma.Web.OStatus
 
   import Ecto.Query
 
+  @websub_verifier Application.get_env(:pleroma, :websub_verifier)
+
   def verify(subscription, getter \\ &HTTPoison.get/3 ) do
     challenge = Base.encode16(:crypto.strong_rand_bytes(8))
-    lease_seconds = NaiveDateTime.diff(subscription.valid_until, subscription.inserted_at) |> to_string
+    lease_seconds = NaiveDateTime.diff(subscription.valid_until, subscription.updated_at) |> to_string
 
     params = %{
       "hub.challenge": challenge,
@@ -48,4 +51,53 @@ defmodule Pleroma.Web.Websub do
           ])
     end)
   end
+
+  def incoming_subscription_request(user, params) do
+    with {:ok, topic} <- valid_topic(params, user),
+         {:ok, lease_time} <- lease_time(params),
+         secret <- params["hub.secret"],
+         callback <- params["hub.callback"]
+    do
+      subscription = get_subscription(topic, callback)
+      data = %{
+        state: subscription.state || "requested",
+        topic: topic,
+        secret: secret,
+        callback: callback
+      }
+
+      change = Ecto.Changeset.change(subscription, data)
+      websub = Repo.insert_or_update!(change)
+
+      change = Ecto.Changeset.change(websub, %{valid_until: NaiveDateTime.add(websub.updated_at, lease_time)})
+      websub = Repo.update!(change)
+
+      # Just spawn that for now, maybe pool later.
+      spawn(fn -> @websub_verifier.verify(websub) end)
+
+      {:ok, websub}
+    else {:error, reason} ->
+      {:error, reason}
+    end
+  end
+
+  defp get_subscription(topic, callback) do
+    Repo.get_by(WebsubServerSubscription, topic: topic, callback: callback) || %WebsubServerSubscription{}
+  end
+
+  defp lease_time(%{"hub.lease_seconds" => lease_seconds}) do
+    {:ok, String.to_integer(lease_seconds)}
+  end
+
+  defp lease_time(_) do
+    {:ok, 60 * 60 * 24 * 3} # three days
+  end
+
+  defp valid_topic(%{"hub.topic" => topic}, user) do
+    if topic == OStatus.feed_path(user) do
+      {:ok, topic}
+    else
+      {:error, "Wrong topic requested, expected #{OStatus.feed_path(user)}, got #{topic}"}
+    end
+  end
 end
index 5766dff649d76c535da7b9b1a6ae4fe55a022741..5d54c6ef5c936c10cf4ba128712f5dab93230c62 100644 (file)
@@ -1,32 +1,13 @@
 defmodule Pleroma.Web.Websub.WebsubController do
   use Pleroma.Web, :controller
-  alias Pleroma.Web.Websub.WebsubServerSubscription
-  alias Pleroma.{Repo, User}
-  alias Pleroma.Web.OStatus
+  alias Pleroma.User
   alias Pleroma.Web.Websub
+
   def websub_subscription_request(conn, %{"nickname" => nickname} = params) do
     user = User.get_cached_by_nickname(nickname)
 
-    with {:ok, topic} <- valid_topic(params, user),
-         {:ok, lease_time} <- lease_time(params),
-         secret <- params["hub.secret"]
+    with {:ok, _websub} <- Websub.incoming_subscription_request(user, params)
     do
-      data = %{
-        state: "requested",
-        topic: topic,
-        secret: secret,
-        callback: params["hub.callback"]
-      }
-
-      change = Ecto.Changeset.change(%WebsubServerSubscription{}, data)
-      websub = Repo.insert!(change)
-
-      change = Ecto.Changeset.change(websub, %{valid_until: NaiveDateTime.add(websub.inserted_at, lease_time)})
-      websub = Repo.update!(change)
-
-      # Just spawn that for now, maybe pool later.
-      spawn(fn -> Websub.verify(websub) end)
-
       conn
       |> send_resp(202, "Accepted")
     else {:error, reason} ->
@@ -34,20 +15,4 @@ defmodule Pleroma.Web.Websub.WebsubController do
       |> send_resp(500, reason)
     end
   end
-
-  defp lease_time(%{"hub.lease_seconds" => lease_seconds}) do
-    {:ok, String.to_integer(lease_seconds)}
-  end
-
-  defp lease_time(_) do
-    {:ok, 60 * 60 * 24 * 3} # three days
-  end
-
-  defp valid_topic(%{"hub.topic" => topic}, user) do
-    if topic == OStatus.feed_path(user) do
-      {:ok, topic}
-    else
-      {:error, "Wrong topic requested, expected #{OStatus.feed_path(user)}, got #{topic}"}
-    end
-  end
 end
index 584db0a1957fae45852958a0ab619980f8e1074b..9a0a5c61bea282e9d6f6a3f729436f1f4411717e 100644 (file)
@@ -1,8 +1,6 @@
 defmodule Pleroma.Web.Websub.WebsubControllerTest do
   use Pleroma.Web.ConnCase
   import Pleroma.Factory
-  alias Pleroma.Repo
-  alias Pleroma.Web.Websub.WebsubServerSubscription
 
   test "websub subscription request", %{conn: conn} do
     user = insert(:user)
@@ -21,11 +19,5 @@ defmodule Pleroma.Web.Websub.WebsubControllerTest do
     |> post(path, data)
 
     assert response(conn, 202) == "Accepted"
-    subscription = Repo.one!(WebsubServerSubscription)
-    assert subscription.topic == Pleroma.Web.OStatus.feed_path(user)
-    assert subscription.state == "requested"
-    assert subscription.secret == "a random secret"
-    assert subscription.callback == "http://example.org/sub"
-    assert subscription.valid_until == NaiveDateTime.add(subscription.inserted_at, 100)
   end
 end
index 36ea822990959574ddbbbad54d2a7628e45cdcca..5fe91d0f86950107ec169f61fb1e9fa8c1be543b 100644 (file)
@@ -1,6 +1,12 @@
+defmodule Pleroma.Web.WebsubMock do
+  def verify(sub) do
+    {:ok, sub}
+  end
+end
 defmodule Pleroma.Web.WebsubTest do
   use Pleroma.DataCase
   alias Pleroma.Web.Websub
+  alias Pleroma.Web.Websub.WebsubServerSubscription
   import Pleroma.Factory
 
   test "a verification of a request that is accepted" do
@@ -29,7 +35,6 @@ defmodule Pleroma.Web.WebsubTest do
 
   test "a verification of a request that doesn't return 200" do
     sub = insert(:websub_subscription)
-    topic = sub.topic
 
     getter = fn (_path, _headers, _options) ->
       {:ok, %HTTPoison.Response{
@@ -41,4 +46,45 @@ defmodule Pleroma.Web.WebsubTest do
     {:error, sub} = Websub.verify(sub, getter)
     assert sub.state == "rejected"
   end
+
+  test "an incoming subscription request" do
+    user = insert(:user)
+
+    data = %{
+      "hub.callback" => "http://example.org/sub",
+      "hub.mode" => "subscription",
+      "hub.topic" => Pleroma.Web.OStatus.feed_path(user),
+      "hub.secret" => "a random secret",
+      "hub.lease_seconds" => "100"
+    }
+
+
+    {:ok, subscription } = Websub.incoming_subscription_request(user, data)
+    assert subscription.topic == Pleroma.Web.OStatus.feed_path(user)
+    assert subscription.state == "requested"
+    assert subscription.secret == "a random secret"
+    assert subscription.callback == "http://example.org/sub"
+  end
+
+  test "an incoming subscription request for an existing subscription" do
+    user = insert(:user)
+    sub = insert(:websub_subscription, state: "accepted", topic: Pleroma.Web.OStatus.feed_path(user))
+
+    data = %{
+      "hub.callback" => sub.callback,
+      "hub.mode" => "subscription",
+      "hub.topic" => Pleroma.Web.OStatus.feed_path(user),
+      "hub.secret" => "a random secret",
+      "hub.lease_seconds" => "100"
+    }
+
+
+    {:ok, subscription } = Websub.incoming_subscription_request(user, data)
+    assert subscription.topic == Pleroma.Web.OStatus.feed_path(user)
+    assert subscription.state == sub.state
+    assert subscription.secret == "a random secret"
+    assert subscription.callback == sub.callback
+    assert length(Repo.all(WebsubServerSubscription)) == 1
+    assert subscription.id == sub.id
+  end
 end