websub_test.exs (7263B)
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.WebsubTest do 6 use Pleroma.DataCase 7 use Oban.Testing, repo: Pleroma.Repo 8 9 alias Pleroma.Tests.ObanHelpers 10 alias Pleroma.Web.Router.Helpers 11 alias Pleroma.Web.Websub 12 alias Pleroma.Web.Websub.WebsubClientSubscription 13 alias Pleroma.Web.Websub.WebsubServerSubscription 14 alias Pleroma.Workers.SubscriberWorker 15 16 import Pleroma.Factory 17 import Tesla.Mock 18 19 setup do 20 mock(fn env -> apply(HttpRequestMock, :request, [env]) end) 21 :ok 22 end 23 24 test "a verification of a request that is accepted" do 25 sub = insert(:websub_subscription) 26 topic = sub.topic 27 28 getter = fn _path, _headers, options -> 29 %{ 30 "hub.challenge": challenge, 31 "hub.lease_seconds": seconds, 32 "hub.topic": ^topic, 33 "hub.mode": "subscribe" 34 } = Keyword.get(options, :params) 35 36 assert String.to_integer(seconds) > 0 37 38 {:ok, 39 %Tesla.Env{ 40 status: 200, 41 body: challenge 42 }} 43 end 44 45 {:ok, sub} = Websub.verify(sub, getter) 46 assert sub.state == "active" 47 end 48 49 test "a verification of a request that doesn't return 200" do 50 sub = insert(:websub_subscription) 51 52 getter = fn _path, _headers, _options -> 53 {:ok, 54 %Tesla.Env{ 55 status: 500, 56 body: "" 57 }} 58 end 59 60 {:error, sub} = Websub.verify(sub, getter) 61 # Keep the current state. 62 assert sub.state == "requested" 63 end 64 65 test "an incoming subscription request" do 66 user = insert(:user) 67 68 data = %{ 69 "hub.callback" => "http://example.org/sub", 70 "hub.mode" => "subscribe", 71 "hub.topic" => Pleroma.Web.OStatus.feed_path(user), 72 "hub.secret" => "a random secret", 73 "hub.lease_seconds" => "100" 74 } 75 76 {:ok, subscription} = Websub.incoming_subscription_request(user, data) 77 assert subscription.topic == Pleroma.Web.OStatus.feed_path(user) 78 assert subscription.state == "requested" 79 assert subscription.secret == "a random secret" 80 assert subscription.callback == "http://example.org/sub" 81 end 82 83 test "an incoming subscription request for an existing subscription" do 84 user = insert(:user) 85 86 sub = 87 insert(:websub_subscription, state: "accepted", topic: Pleroma.Web.OStatus.feed_path(user)) 88 89 data = %{ 90 "hub.callback" => sub.callback, 91 "hub.mode" => "subscribe", 92 "hub.topic" => Pleroma.Web.OStatus.feed_path(user), 93 "hub.secret" => "a random secret", 94 "hub.lease_seconds" => "100" 95 } 96 97 {:ok, subscription} = Websub.incoming_subscription_request(user, data) 98 assert subscription.topic == Pleroma.Web.OStatus.feed_path(user) 99 assert subscription.state == sub.state 100 assert subscription.secret == "a random secret" 101 assert subscription.callback == sub.callback 102 assert length(Repo.all(WebsubServerSubscription)) == 1 103 assert subscription.id == sub.id 104 end 105 106 def accepting_verifier(subscription) do 107 {:ok, %{subscription | state: "accepted"}} 108 end 109 110 test "initiate a subscription for a given user and topic" do 111 subscriber = insert(:user) 112 user = insert(:user, %{info: %Pleroma.User.Info{topic: "some_topic", hub: "some_hub"}}) 113 114 {:ok, websub} = Websub.subscribe(subscriber, user, &accepting_verifier/1) 115 assert websub.subscribers == [subscriber.ap_id] 116 assert websub.topic == "some_topic" 117 assert websub.hub == "some_hub" 118 assert is_binary(websub.secret) 119 assert websub.user == user 120 assert websub.state == "accepted" 121 end 122 123 test "discovers the hub and canonical url" do 124 topic = "https://mastodon.social/users/lambadalambda.atom" 125 126 {:ok, discovered} = Websub.gather_feed_data(topic) 127 128 expected = %{ 129 "hub" => "https://mastodon.social/api/push", 130 "uri" => "https://mastodon.social/users/lambadalambda", 131 "nickname" => "lambadalambda", 132 "name" => "Critical Value", 133 "host" => "mastodon.social", 134 "bio" => "a cool dude.", 135 "avatar" => %{ 136 "type" => "Image", 137 "url" => [ 138 %{ 139 "href" => 140 "https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif?1492379244", 141 "mediaType" => "image/gif", 142 "type" => "Link" 143 } 144 ] 145 } 146 } 147 148 assert expected == discovered 149 end 150 151 test "calls the hub, requests topic" do 152 hub = "https://social.heldscal.la/main/push/hub" 153 topic = "https://social.heldscal.la/api/statuses/user_timeline/23211.atom" 154 websub = insert(:websub_client_subscription, %{hub: hub, topic: topic}) 155 156 poster = fn ^hub, {:form, data}, _headers -> 157 assert Keyword.get(data, :"hub.mode") == "subscribe" 158 159 assert Keyword.get(data, :"hub.callback") == 160 Helpers.websub_url( 161 Pleroma.Web.Endpoint, 162 :websub_subscription_confirmation, 163 websub.id 164 ) 165 166 {:ok, %{status: 202}} 167 end 168 169 task = Task.async(fn -> Websub.request_subscription(websub, poster) end) 170 171 change = Ecto.Changeset.change(websub, %{state: "accepted"}) 172 {:ok, _} = Repo.update(change) 173 174 {:ok, websub} = Task.await(task) 175 176 assert websub.state == "accepted" 177 end 178 179 test "rejects the subscription if it can't be accepted" do 180 hub = "https://social.heldscal.la/main/push/hub" 181 topic = "https://social.heldscal.la/api/statuses/user_timeline/23211.atom" 182 websub = insert(:websub_client_subscription, %{hub: hub, topic: topic}) 183 184 poster = fn ^hub, {:form, _data}, _headers -> 185 {:ok, %{status: 202}} 186 end 187 188 {:error, websub} = Websub.request_subscription(websub, poster, 1000) 189 assert websub.state == "rejected" 190 191 websub = insert(:websub_client_subscription, %{hub: hub, topic: topic}) 192 193 poster = fn ^hub, {:form, _data}, _headers -> 194 {:ok, %{status: 400}} 195 end 196 197 {:error, websub} = Websub.request_subscription(websub, poster, 1000) 198 assert websub.state == "rejected" 199 end 200 201 test "sign a text" do 202 signed = Websub.sign("secret", "text") 203 assert signed == "B8392C23690CCF871F37EC270BE1582DEC57A503" |> String.downcase() 204 205 _signed = Websub.sign("secret", [["て"], ['す']]) 206 end 207 208 describe "renewing subscriptions" do 209 test "it renews subscriptions that have less than a day of time left" do 210 day = 60 * 60 * 24 211 now = NaiveDateTime.utc_now() 212 213 still_good = 214 insert(:websub_client_subscription, %{ 215 valid_until: NaiveDateTime.add(now, 2 * day), 216 topic: "http://example.org/still_good", 217 hub: "http://example.org/still_good", 218 state: "accepted" 219 }) 220 221 needs_refresh = 222 insert(:websub_client_subscription, %{ 223 valid_until: NaiveDateTime.add(now, day - 100), 224 topic: "http://example.org/needs_refresh", 225 hub: "http://example.org/needs_refresh", 226 state: "accepted" 227 }) 228 229 _refresh = Websub.refresh_subscriptions() 230 ObanHelpers.perform(all_enqueued(worker: SubscriberWorker)) 231 232 assert still_good == Repo.get(WebsubClientSubscription, still_good.id) 233 refute needs_refresh == Repo.get(WebsubClientSubscription, needs_refresh.id) 234 end 235 end 236 end