1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do
6 use Pleroma.Web.ConnCase
10 alias Pleroma.Web.ActivityPub.ActivityPub
11 alias Pleroma.Web.ActivityPub.Transmogrifier
12 alias Pleroma.Web.ActivityPub.Utils
13 alias Pleroma.Web.CommonAPI
15 import Pleroma.Factory
17 setup_all do: clear_config([:static_fe, :enabled], true)
19 setup %{conn: conn} do
20 conn = put_req_header(conn, "accept", "text/html")
23 %{conn: conn, user: user}
26 describe "user profile html" do
27 test "just the profile as HTML", %{conn: conn, user: user} do
28 conn = get(conn, "/users/#{user.nickname}")
30 assert html_response(conn, 200) =~ user.nickname
33 test "404 when user not found", %{conn: conn} do
34 conn = get(conn, "/users/limpopo")
36 assert html_response(conn, 404) =~ "not found"
39 test "profile does not include private messages", %{conn: conn, user: user} do
40 CommonAPI.post(user, %{status: "public"})
41 CommonAPI.post(user, %{status: "private", visibility: "private"})
43 conn = get(conn, "/users/#{user.nickname}")
45 html = html_response(conn, 200)
47 assert html =~ "\npublic\n"
48 refute html =~ "\nprivate\n"
51 test "main page does not include replies", %{conn: conn, user: user} do
52 {:ok, op} = CommonAPI.post(user, %{status: "beep"})
53 CommonAPI.post(user, %{status: "boop", in_reply_to_id: op})
55 conn = get(conn, "/users/#{user.nickname}")
57 html = html_response(conn, 200)
59 assert html =~ "\nbeep\n"
60 refute html =~ "\nboop\n"
63 test "media page only includes posts with attachments", %{conn: conn, user: user} do
65 content_type: "image/jpeg",
66 path: Path.absname("test/fixtures/image.jpg"),
67 filename: "an_image.jpg"
70 {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id)
72 CommonAPI.post(user, %{status: "virgin text post"})
73 CommonAPI.post(user, %{status: "chad post with attachment", media_ids: [media_id]})
75 conn = get(conn, "/users/#{user.nickname}/media")
77 html = html_response(conn, 200)
79 assert html =~ "\nchad post with attachment\n"
80 refute html =~ "\nvirgin text post\n"
83 test "show follower list", %{conn: conn, user: user} do
84 follower = insert(:user)
85 CommonAPI.follow(follower, user)
87 conn = get(conn, "/users/#{user.nickname}/followers")
89 html = html_response(conn, 200)
91 assert html =~ "user-card"
94 test "don't show followers if hidden", %{conn: conn, user: user} do
95 follower = insert(:user)
96 CommonAPI.follow(follower, user)
100 |> User.update_changeset(%{hide_followers: true})
101 |> User.update_and_set_cache()
103 conn = get(conn, "/users/#{user.nickname}/followers")
105 html = html_response(conn, 200)
107 refute html =~ "user-card"
110 test "pagination", %{conn: conn, user: user} do
111 Enum.map(1..30, fn i -> CommonAPI.post(user, %{status: "test#{i}"}) end)
113 conn = get(conn, "/users/#{user.nickname}")
115 html = html_response(conn, 200)
117 assert html =~ "\ntest30\n"
118 assert html =~ "\ntest11\n"
119 refute html =~ "\ntest10\n"
120 refute html =~ "\ntest1\n"
123 test "pagination, page 2", %{conn: conn, user: user} do
124 activities = Enum.map(1..30, fn i -> CommonAPI.post(user, %{status: "test#{i}"}) end)
125 {:ok, a11} = Enum.at(activities, 11)
127 conn = get(conn, "/users/#{user.nickname}?max_id=#{a11.id}")
129 html = html_response(conn, 200)
131 assert html =~ "\ntest1\n"
132 assert html =~ "\ntest10\n"
133 refute html =~ "\ntest20\n"
134 refute html =~ "\ntest29\n"
137 test "does not require authentication on non-federating instances", %{
141 clear_config([:instance, :federating], false)
143 conn = get(conn, "/users/#{user.nickname}")
145 assert html_response(conn, 200) =~ user.nickname
148 test "returns 404 for local user with `restrict_unauthenticated/profiles/local` setting", %{
151 clear_config([:restrict_unauthenticated, :profiles, :local], true)
153 local_user = insert(:user, local: true)
156 |> get("/users/#{local_user.nickname}")
157 |> html_response(404)
161 describe "notice html" do
162 test "single notice page", %{conn: conn, user: user} do
163 {:ok, activity} = CommonAPI.post(user, %{status: "testing a thing!"})
165 conn = get(conn, "/notice/#{activity.id}")
167 html = html_response(conn, 200)
168 assert html =~ "<div class=\"panel conversation\">"
169 assert html =~ user.nickname
170 assert html =~ "testing a thing!"
173 test "redirects to json if requested", %{conn: conn, user: user} do
174 {:ok, activity} = CommonAPI.post(user, %{status: "testing a thing!"})
180 "Accept: application/activity+json, application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\", text/html"
182 |> get("/notice/#{activity.id}")
184 assert redirected_to(conn, 302) =~ activity.data["object"]
187 test "filters HTML tags", %{conn: conn} do
189 {:ok, activity} = CommonAPI.post(user, %{status: "<script>alert('xss')</script>"})
193 |> put_req_header("accept", "text/html")
194 |> get("/notice/#{activity.id}")
196 html = html_response(conn, 200)
197 assert html =~ ~s[<script>alert('xss')</script>]
200 test "shows the whole thread", %{conn: conn, user: user} do
201 {:ok, activity} = CommonAPI.post(user, %{status: "space: the final frontier"})
203 CommonAPI.post(user, %{
204 status: "these are the voyages or something",
205 in_reply_to_status_id: activity.id
208 conn = get(conn, "/notice/#{activity.id}")
210 html = html_response(conn, 200)
211 assert html =~ "the final frontier"
212 assert html =~ "voyages"
215 test "redirect by AP object ID", %{conn: conn, user: user} do
216 {:ok, %Activity{data: %{"object" => object_url}}} =
217 CommonAPI.post(user, %{status: "beam me up"})
219 conn = get(conn, URI.parse(object_url).path)
221 assert html_response(conn, 302) =~ "redirected"
224 test "redirect by activity ID", %{conn: conn, user: user} do
225 {:ok, %Activity{data: %{"id" => id}}} =
226 CommonAPI.post(user, %{status: "I'm a doctor, not a devops!"})
228 conn = get(conn, URI.parse(id).path)
230 assert html_response(conn, 302) =~ "redirected"
233 test "404 when notice not found", %{conn: conn} do
234 conn = get(conn, "/notice/88c9c317")
236 assert html_response(conn, 404) =~ "not found"
239 test "404 for private status", %{conn: conn, user: user} do
240 {:ok, activity} = CommonAPI.post(user, %{status: "don't show me!", visibility: "private"})
242 conn = get(conn, "/notice/#{activity.id}")
244 assert html_response(conn, 404) =~ "not found"
247 test "302 for remote cached status", %{conn: conn, user: user} do
249 "@context" => "https://www.w3.org/ns/activitystreams",
251 "actor" => user.ap_id,
253 "to" => user.follower_address,
254 "cc" => "https://www.w3.org/ns/activitystreams#Public",
255 "id" => Utils.generate_object_id(),
256 "content" => "blah blah blah",
258 "attributedTo" => user.ap_id
262 assert {:ok, activity} = Transmogrifier.handle_incoming(message)
264 conn = get(conn, "/notice/#{activity.id}")
266 assert html_response(conn, 302) =~ "redirected"
269 test "does not require authentication on non-federating instances", %{
273 clear_config([:instance, :federating], false)
275 {:ok, activity} = CommonAPI.post(user, %{status: "testing a thing!"})
277 conn = get(conn, "/notice/#{activity.id}")
279 assert html_response(conn, 200) =~ "testing a thing!"
282 test "returns 404 for local public activity with `restrict_unauthenticated/activities/local` setting",
283 %{conn: conn, user: user} do
284 clear_config([:restrict_unauthenticated, :activities, :local], true)
286 {:ok, activity} = CommonAPI.post(user, %{status: "testing a thing!"})
289 |> get("/notice/#{activity.id}")
290 |> html_response(404)