| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
 | # Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Integration.MastodonWebsocketTest do
  use Pleroma.DataCase
  import ExUnit.CaptureLog
  import Pleroma.Factory
  alias Pleroma.Integration.WebsocketClient
  alias Pleroma.Web.CommonAPI
  alias Pleroma.Web.OAuth
  @path Pleroma.Web.Endpoint.url()
        |> URI.parse()
        |> Map.put(:scheme, "ws")
        |> Map.put(:path, "/api/v1/streaming")
        |> URI.to_string()
  setup_all do
    start_supervised(Pleroma.Web.Streamer.supervisor())
    :ok
  end
  def start_socket(qs \\ nil, headers \\ []) do
    path =
      case qs do
        nil -> @path
        qs -> @path <> qs
      end
    WebsocketClient.start_link(self(), path, headers)
  end
  test "refuses invalid requests" do
    capture_log(fn ->
      assert {:error, {400, _}} = start_socket()
      assert {:error, {404, _}} = start_socket("?stream=ncjdk")
      Process.sleep(30)
    end)
  end
  test "requires authentication and a valid token for protected streams" do
    capture_log(fn ->
      assert {:error, {403, _}} = start_socket("?stream=user&access_token=aaaaaaaaaaaa")
      assert {:error, {403, _}} = start_socket("?stream=user")
      Process.sleep(30)
    end)
  end
  test "allows public streams without authentication" do
    assert {:ok, _} = start_socket("?stream=public")
    assert {:ok, _} = start_socket("?stream=public:local")
    assert {:ok, _} = start_socket("?stream=hashtag&tag=lain")
  end
  test "receives well formatted events" do
    user = insert(:user)
    {:ok, _} = start_socket("?stream=public")
    {:ok, activity} = CommonAPI.post(user, %{"status" => "nice echo chamber"})
    assert_receive {:text, raw_json}, 1_000
    assert {:ok, json} = Jason.decode(raw_json)
    assert "update" == json["event"]
    assert json["payload"]
    assert {:ok, json} = Jason.decode(json["payload"])
    view_json =
      Pleroma.Web.MastodonAPI.StatusView.render("show.json", activity: activity, for: nil)
      |> Jason.encode!()
      |> Jason.decode!()
    assert json == view_json
  end
  describe "with a valid user token" do
    setup do
      {:ok, app} =
        Pleroma.Repo.insert(
          OAuth.App.register_changeset(%OAuth.App{}, %{
            client_name: "client",
            scopes: ["scope"],
            redirect_uris: "url"
          })
        )
      user = insert(:user)
      {:ok, auth} = OAuth.Authorization.create_authorization(app, user)
      {:ok, token} = OAuth.Token.exchange_token(app, auth)
      %{user: user, token: token}
    end
    test "accepts valid tokens", state do
      assert {:ok, _} = start_socket("?stream=user&access_token=#{state.token.token}")
    end
    test "accepts the 'user' stream", %{token: token} = _state do
      assert {:ok, _} = start_socket("?stream=user&access_token=#{token.token}")
      assert capture_log(fn ->
               assert {:error, {403, "Forbidden"}} = start_socket("?stream=user")
               Process.sleep(30)
             end) =~ ":badarg"
    end
    test "accepts the 'user:notification' stream", %{token: token} = _state do
      assert {:ok, _} = start_socket("?stream=user:notification&access_token=#{token.token}")
      assert capture_log(fn ->
               assert {:error, {403, "Forbidden"}} = start_socket("?stream=user:notification")
               Process.sleep(30)
             end) =~ ":badarg"
    end
    test "accepts valid token on Sec-WebSocket-Protocol header", %{token: token} do
      assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}])
      assert capture_log(fn ->
               assert {:error, {403, "Forbidden"}} =
                        start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}])
               Process.sleep(30)
             end) =~ ":badarg"
    end
  end
end
 |