### Added
- NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list.
+- Configuration: `:restrict_unauthenticated` setting, restrict access for unauthenticated users to timelines (public and federate), user profiles and statuses.
<details>
<summary>API Changes</summary>
- Mastodon API: Support for `include_types` in `/api/v1/notifications`.
parameters: [gin_fuzzy_search_limit: "500"],
prepare: :unnamed
+config :pleroma, :restrict_unauthenticated,
+ timelines: %{local: false, federated: false},
+ profiles: %{local: false, remote: false},
+ activities: %{local: false, remote: false}
+
# 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"
suggestions: [2]
}
]
+ },
+ %{
+ group: :pleroma,
+ key: :restrict_unauthenticated,
+ type: :group,
+ description:
+ "Disallow viewing timelines, user profiles and statuses for unauthenticated users.",
+ children: [
+ %{
+ key: :timelines,
+ type: :map,
+ description: "Settings for public and federated timelines.",
+ children: [
+ %{
+ key: :local,
+ type: :boolean,
+ description: "Disallow view public timeline."
+ },
+ %{
+ key: :federated,
+ type: :boolean,
+ description: "Disallow view federated timeline."
+ }
+ ]
+ },
+ %{
+ key: :profiles,
+ type: :map,
+ description: "Settings for user profiles.",
+ children: [
+ %{
+ key: :local,
+ type: :boolean,
+ description: "Disallow view local user profiles."
+ },
+ %{
+ key: :remote,
+ type: :boolean,
+ description: "Disallow view remote user profiles."
+ }
+ ]
+ },
+ %{
+ key: :activities,
+ type: :map,
+ description: "Settings for statuses.",
+ children: [
+ %{
+ key: :local,
+ type: :boolean,
+ description: "Disallow view local statuses."
+ },
+ %{
+ key: :remote,
+ type: :boolean,
+ description: "Disallow view remote statuses."
+ }
+ ]
+ }
+ ]
}
]
## :configurable_from_database
Boolean, enables/disables in-database configuration. Read [Transfering the config to/from the database](../administration/CLI_tasks/config.md) for more information.
+
+
+
+## Restrict entities access for unauthenticated users
+
+### :restrict_unauthenticated
+
+Restrict access for unauthenticated users to timelines (public and federate), user profiles and statuses.
+
+* `timelines` - public and federated timelines
+ * `local` - public timeline
+ * `federated`
+* `profiles` - user profiles
+ * `local`
+ * `remote`
+* `activities` - statuses
+ * `local`
+ * `remote`
\ No newline at end of file
def visible_for?(%User{invisible: true}, _), do: false
- def visible_for?(%User{id: user_id}, %User{id: for_id}) when user_id == for_id, do: true
+ def visible_for?(%User{id: user_id}, %User{id: user_id}), do: true
+
+ def visible_for?(%User{local: local} = user, nil) do
+ cfg_key =
+ if local,
+ do: :local,
+ else: :remote
+
+ if Config.get([:restrict_unauthenticated, :profiles, cfg_key]),
+ do: false,
+ else: account_status(user) == :active
+ end
def visible_for?(%User{} = user, for_user) do
account_status(user) == :active || superuser?(for_user)
def is_list?(%{data: %{"listMessage" => _}}), do: true
def is_list?(_), do: false
+ @spec visible_for_user?(Activity.t(), User.t() | nil) :: boolean()
def visible_for_user?(%{actor: ap_id}, %User{ap_id: ap_id}), do: true
def visible_for_user?(%{data: %{"listMessage" => list_ap_id}} = activity, %User{} = user) do
def visible_for_user?(%{data: %{"listMessage" => _}}, nil), do: false
- def visible_for_user?(activity, nil) do
- is_public?(activity)
+ def visible_for_user?(%{local: local} = activity, nil) do
+ cfg_key =
+ if local,
+ do: :local,
+ else: :remote
+
+ if Pleroma.Config.get([:restrict_unauthenticated, :activities, cfg_key]),
+ do: false,
+ else: is_public?(activity)
end
def visible_for_user?(activity, user) do
x = [user.ap_id | User.following(user)]
y = [activity.actor] ++ activity.data["to"] ++ (activity.data["cc"] || [])
- visible_for_user?(activity, nil) || Enum.any?(x, &(&1 in y))
+ is_public?(activity) || Enum.any?(x, &(&1 in y))
end
def entire_thread_visible_for_user?(%Activity{} = activity, %User{} = user) do
plug(
Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
- when action != :create
+ when action not in [:create, :show, :statuses]
)
@relations [:follow, :unfollow]
@doc "GET /api/v1/accounts/:id/statuses"
def statuses(%{assigns: %{user: reading_user}} = conn, params) do
- with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do
+ with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user),
+ true <- User.visible_for?(user, reading_user) do
params =
params
|> Map.put("tag", params["tagged"])
|> add_link_headers(activities)
|> put_view(StatusView)
|> render("index.json", activities: activities, for: reading_user, as: :activity)
+ else
+ _e -> render_error(conn, :not_found, "Can't find user")
end
end
%{scopes: ["write:bookmarks"]} when action in [:bookmark, :unbookmark]
)
- plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
+ plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug when action not in [:index, :show])
@rate_limited_status_actions ~w(reblog unreblog favourite unfavourite create delete)a
plug(OAuthScopesPlug, %{scopes: ["read:statuses"]} when action in [:home, :direct])
plug(OAuthScopesPlug, %{scopes: ["read:lists"]} when action == :list)
- plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
+ plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug when action != :public)
plug(:put_view, Pleroma.Web.MastodonAPI.StatusView)
def public(%{assigns: %{user: user}} = conn, params) do
local_only = truthy_param?(params["local"])
- activities =
- params
- |> Map.put("type", ["Create", "Announce"])
- |> Map.put("local_only", local_only)
- |> Map.put("blocking_user", user)
- |> Map.put("muting_user", user)
- |> ActivityPub.fetch_public_activities()
+ cfg_key =
+ if local_only do
+ :local
+ else
+ :federated
+ end
- conn
- |> add_link_headers(activities, %{"local" => local_only})
- |> render("index.json", activities: activities, for: user, as: :activity)
+ restrict? = Pleroma.Config.get([:restrict_unauthenticated, :timelines, cfg_key])
+
+ if not (restrict? and is_nil(user)) do
+ activities =
+ params
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", local_only)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> ActivityPub.fetch_public_activities()
+
+ conn
+ |> add_link_headers(activities, %{"local" => local_only})
+ |> render("index.json", activities: activities, for: user, as: :activity)
+ else
+ render_error(conn, :unauthorized, "authorization required for timeline view")
+ end
end
def hashtag_fetching(params, user, local_only) do
defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
use Pleroma.Web.ConnCase
+ alias Pleroma.Config
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
end
test "works by nickname for remote users" do
- Pleroma.Config.put([:instance, :limit_to_local_content], false)
+ Config.put([:instance, :limit_to_local_content], false)
user = insert(:user, nickname: "user@example.com", local: false)
conn =
end
test "respects limit_to_local_content == :all for remote user nicknames" do
- Pleroma.Config.put([:instance, :limit_to_local_content], :all)
+ Config.put([:instance, :limit_to_local_content], :all)
user = insert(:user, nickname: "user@example.com", local: false)
end
test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
- Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
+ Config.put([:instance, :limit_to_local_content], :unauthenticated)
user = insert(:user, nickname: "user@example.com", local: false)
reading_user = insert(:user)
end
end
+ defp local_and_remote_users do
+ local = insert(:user)
+ remote = insert(:user, local: false)
+ {:ok, local: local, remote: remote}
+ end
+
+ describe "user fetching with restrict unauthenticated profiles for local and remote" do
+ setup do: local_and_remote_users()
+
+ clear_config([:restrict_unauthenticated, :profiles, :local]) do
+ Config.put([:restrict_unauthenticated, :profiles, :local], true)
+ end
+
+ clear_config([:restrict_unauthenticated, :profiles, :remote]) do
+ Config.put([:restrict_unauthenticated, :profiles, :remote], true)
+ end
+
+ test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
+ res_conn = get(conn, "/api/v1/accounts/#{local.id}")
+
+ assert json_response(res_conn, :not_found) == %{
+ "error" => "Can't find user"
+ }
+
+ res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
+
+ assert json_response(res_conn, :not_found) == %{
+ "error" => "Can't find user"
+ }
+ end
+
+ test "if user is authenticated", %{local: local, remote: remote} do
+ %{conn: conn} = oauth_access(["read"])
+
+ res_conn = get(conn, "/api/v1/accounts/#{local.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+
+ res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+ end
+ end
+
+ describe "user fetching with restrict unauthenticated profiles for local" do
+ setup do: local_and_remote_users()
+
+ clear_config([:restrict_unauthenticated, :profiles, :local]) do
+ Config.put([:restrict_unauthenticated, :profiles, :local], true)
+ end
+
+ test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
+ res_conn = get(conn, "/api/v1/accounts/#{local.id}")
+
+ assert json_response(res_conn, :not_found) == %{
+ "error" => "Can't find user"
+ }
+
+ res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+ end
+
+ test "if user is authenticated", %{local: local, remote: remote} do
+ %{conn: conn} = oauth_access(["read"])
+
+ res_conn = get(conn, "/api/v1/accounts/#{local.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+
+ res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+ end
+ end
+
+ describe "user fetching with restrict unauthenticated profiles for remote" do
+ setup do: local_and_remote_users()
+
+ clear_config([:restrict_unauthenticated, :profiles, :remote]) do
+ Config.put([:restrict_unauthenticated, :profiles, :remote], true)
+ end
+
+ test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
+ res_conn = get(conn, "/api/v1/accounts/#{local.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+
+ res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
+
+ assert json_response(res_conn, :not_found) == %{
+ "error" => "Can't find user"
+ }
+ end
+
+ test "if user is authenticated", %{local: local, remote: remote} do
+ %{conn: conn} = oauth_access(["read"])
+
+ res_conn = get(conn, "/api/v1/accounts/#{local.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+
+ res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+ end
+ end
+
describe "user timelines" do
setup do: oauth_access(["read:statuses"])
end
end
+ defp local_and_remote_activities(%{local: local, remote: remote}) do
+ insert(:note_activity, user: local)
+ insert(:note_activity, user: remote, local: false)
+
+ :ok
+ end
+
+ describe "statuses with restrict unauthenticated profiles for local and remote" do
+ setup do: local_and_remote_users()
+ setup :local_and_remote_activities
+
+ clear_config([:restrict_unauthenticated, :profiles, :local]) do
+ Config.put([:restrict_unauthenticated, :profiles, :local], true)
+ end
+
+ clear_config([:restrict_unauthenticated, :profiles, :remote]) do
+ Config.put([:restrict_unauthenticated, :profiles, :remote], true)
+ end
+
+ test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
+ res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
+
+ assert json_response(res_conn, :not_found) == %{
+ "error" => "Can't find user"
+ }
+
+ res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
+
+ assert json_response(res_conn, :not_found) == %{
+ "error" => "Can't find user"
+ }
+ end
+
+ test "if user is authenticated", %{local: local, remote: remote} do
+ %{conn: conn} = oauth_access(["read"])
+
+ res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
+ assert length(json_response(res_conn, 200)) == 1
+
+ res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
+ assert length(json_response(res_conn, 200)) == 1
+ end
+ end
+
+ describe "statuses with restrict unauthenticated profiles for local" do
+ setup do: local_and_remote_users()
+ setup :local_and_remote_activities
+
+ clear_config([:restrict_unauthenticated, :profiles, :local]) do
+ Config.put([:restrict_unauthenticated, :profiles, :local], true)
+ end
+
+ test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
+ res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
+
+ assert json_response(res_conn, :not_found) == %{
+ "error" => "Can't find user"
+ }
+
+ res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
+ assert length(json_response(res_conn, 200)) == 1
+ end
+
+ test "if user is authenticated", %{local: local, remote: remote} do
+ %{conn: conn} = oauth_access(["read"])
+
+ res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
+ assert length(json_response(res_conn, 200)) == 1
+
+ res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
+ assert length(json_response(res_conn, 200)) == 1
+ end
+ end
+
+ describe "statuses with restrict unauthenticated profiles for remote" do
+ setup do: local_and_remote_users()
+ setup :local_and_remote_activities
+
+ clear_config([:restrict_unauthenticated, :profiles, :remote]) do
+ Config.put([:restrict_unauthenticated, :profiles, :remote], true)
+ end
+
+ test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
+ res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
+ assert length(json_response(res_conn, 200)) == 1
+
+ res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
+
+ assert json_response(res_conn, :not_found) == %{
+ "error" => "Can't find user"
+ }
+ end
+
+ test "if user is authenticated", %{local: local, remote: remote} do
+ %{conn: conn} = oauth_access(["read"])
+
+ res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
+ assert length(json_response(res_conn, 200)) == 1
+
+ res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
+ assert length(json_response(res_conn, 200)) == 1
+ end
+ end
+
describe "followers" do
setup do: oauth_access(["read:accounts"])
describe "create account by app / rate limit" do
clear_config([:rate_limit, :app_account_creation]) do
- Pleroma.Config.put([:rate_limit, :app_account_creation], {10_000, 2})
+ Config.put([:rate_limit, :app_account_creation], {10_000, 2})
end
test "respects rate limit setting", %{conn: conn} do
assert id == to_string(activity.id)
end
+ defp local_and_remote_activities do
+ local = insert(:note_activity)
+ remote = insert(:note_activity, local: false)
+ {:ok, local: local, remote: remote}
+ end
+
+ describe "status with restrict unauthenticated activities for local and remote" do
+ setup do: local_and_remote_activities()
+
+ clear_config([:restrict_unauthenticated, :activities, :local]) do
+ Config.put([:restrict_unauthenticated, :activities, :local], true)
+ end
+
+ clear_config([:restrict_unauthenticated, :activities, :remote]) do
+ Config.put([:restrict_unauthenticated, :activities, :remote], true)
+ end
+
+ test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
+ res_conn = get(conn, "/api/v1/statuses/#{local.id}")
+
+ assert json_response(res_conn, :not_found) == %{
+ "error" => "Record not found"
+ }
+
+ res_conn = get(conn, "/api/v1/statuses/#{remote.id}")
+
+ assert json_response(res_conn, :not_found) == %{
+ "error" => "Record not found"
+ }
+ end
+
+ test "if user is authenticated", %{local: local, remote: remote} do
+ %{conn: conn} = oauth_access(["read"])
+ res_conn = get(conn, "/api/v1/statuses/#{local.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+
+ res_conn = get(conn, "/api/v1/statuses/#{remote.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+ end
+ end
+
+ describe "status with restrict unauthenticated activities for local" do
+ setup do: local_and_remote_activities()
+
+ clear_config([:restrict_unauthenticated, :activities, :local]) do
+ Config.put([:restrict_unauthenticated, :activities, :local], true)
+ end
+
+ test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
+ res_conn = get(conn, "/api/v1/statuses/#{local.id}")
+
+ assert json_response(res_conn, :not_found) == %{
+ "error" => "Record not found"
+ }
+
+ res_conn = get(conn, "/api/v1/statuses/#{remote.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+ end
+
+ test "if user is authenticated", %{local: local, remote: remote} do
+ %{conn: conn} = oauth_access(["read"])
+ res_conn = get(conn, "/api/v1/statuses/#{local.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+
+ res_conn = get(conn, "/api/v1/statuses/#{remote.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+ end
+ end
+
+ describe "status with restrict unauthenticated activities for remote" do
+ setup do: local_and_remote_activities()
+
+ clear_config([:restrict_unauthenticated, :activities, :remote]) do
+ Config.put([:restrict_unauthenticated, :activities, :remote], true)
+ end
+
+ test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
+ res_conn = get(conn, "/api/v1/statuses/#{local.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+
+ res_conn = get(conn, "/api/v1/statuses/#{remote.id}")
+
+ assert json_response(res_conn, :not_found) == %{
+ "error" => "Record not found"
+ }
+ end
+
+ test "if user is authenticated", %{local: local, remote: remote} do
+ %{conn: conn} = oauth_access(["read"])
+ res_conn = get(conn, "/api/v1/statuses/#{local.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+
+ res_conn = get(conn, "/api/v1/statuses/#{remote.id}")
+ assert %{"id" => _} = json_response(res_conn, 200)
+ end
+ end
+
test "getting a status that doesn't exist returns 404" do
%{conn: conn} = oauth_access(["read:statuses"])
activity = insert(:note_activity)
assert [%{"id" => ^id1}, %{"id" => ^id2}] = Enum.sort_by(json_response(conn, :ok), & &1["id"])
end
+ describe "getting statuses by ids with restricted unauthenticated for local and remote" do
+ setup do: local_and_remote_activities()
+
+ clear_config([:restrict_unauthenticated, :activities, :local]) do
+ Config.put([:restrict_unauthenticated, :activities, :local], true)
+ end
+
+ clear_config([:restrict_unauthenticated, :activities, :remote]) do
+ Config.put([:restrict_unauthenticated, :activities, :remote], true)
+ end
+
+ test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
+ res_conn = get(conn, "/api/v1/statuses", %{ids: [local.id, remote.id]})
+
+ assert json_response(res_conn, 200) == []
+ end
+
+ test "if user is authenticated", %{local: local, remote: remote} do
+ %{conn: conn} = oauth_access(["read"])
+
+ res_conn = get(conn, "/api/v1/statuses", %{ids: [local.id, remote.id]})
+
+ assert length(json_response(res_conn, 200)) == 2
+ end
+ end
+
+ describe "getting statuses by ids with restricted unauthenticated for local" do
+ setup do: local_and_remote_activities()
+
+ clear_config([:restrict_unauthenticated, :activities, :local]) do
+ Config.put([:restrict_unauthenticated, :activities, :local], true)
+ end
+
+ test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
+ res_conn = get(conn, "/api/v1/statuses", %{ids: [local.id, remote.id]})
+
+ remote_id = remote.id
+ assert [%{"id" => ^remote_id}] = json_response(res_conn, 200)
+ end
+
+ test "if user is authenticated", %{local: local, remote: remote} do
+ %{conn: conn} = oauth_access(["read"])
+
+ res_conn = get(conn, "/api/v1/statuses", %{ids: [local.id, remote.id]})
+
+ assert length(json_response(res_conn, 200)) == 2
+ end
+ end
+
+ describe "getting statuses by ids with restricted unauthenticated for remote" do
+ setup do: local_and_remote_activities()
+
+ clear_config([:restrict_unauthenticated, :activities, :remote]) do
+ Config.put([:restrict_unauthenticated, :activities, :remote], true)
+ end
+
+ test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
+ res_conn = get(conn, "/api/v1/statuses", %{ids: [local.id, remote.id]})
+
+ local_id = local.id
+ assert [%{"id" => ^local_id}] = json_response(res_conn, 200)
+ end
+
+ test "if user is authenticated", %{local: local, remote: remote} do
+ %{conn: conn} = oauth_access(["read"])
+
+ res_conn = get(conn, "/api/v1/statuses", %{ids: [local.id, remote.id]})
+
+ assert length(json_response(res_conn, 200)) == 2
+ end
+ end
+
describe "deleting a status" do
test "when you created it" do
%{user: author, conn: conn} = oauth_access(["write:statuses"])
alias Pleroma.User
alias Pleroma.Web.CommonAPI
- clear_config([:instance, :public])
-
setup do
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
:ok
assert [%{"content" => "test"}] = json_response(conn, :ok)
end
- test "the public timeline when public is set to false", %{conn: conn} do
- Config.put([:instance, :public], false)
-
- assert %{"error" => "This resource requires authentication."} ==
- conn
- |> get("/api/v1/timelines/public", %{"local" => "False"})
- |> json_response(:forbidden)
- end
-
test "the public timeline includes only public statuses for an authenticated user" do
%{user: user, conn: conn} = oauth_access(["read:statuses"])
end
end
+ defp local_and_remote_activities do
+ insert(:note_activity)
+ insert(:note_activity, local: false)
+ :ok
+ end
+
+ describe "public with restrict unauthenticated timeline for local and federated timelines" do
+ setup do: local_and_remote_activities()
+
+ clear_config([:restrict_unauthenticated, :timelines, :local]) do
+ Config.put([:restrict_unauthenticated, :timelines, :local], true)
+ end
+
+ clear_config([:restrict_unauthenticated, :timelines, :federated]) do
+ Config.put([:restrict_unauthenticated, :timelines, :federated], true)
+ end
+
+ test "if user is unauthenticated", %{conn: conn} do
+ res_conn = get(conn, "/api/v1/timelines/public", %{"local" => "true"})
+
+ assert json_response(res_conn, :unauthorized) == %{
+ "error" => "authorization required for timeline view"
+ }
+
+ res_conn = get(conn, "/api/v1/timelines/public", %{"local" => "false"})
+
+ assert json_response(res_conn, :unauthorized) == %{
+ "error" => "authorization required for timeline view"
+ }
+ end
+
+ test "if user is authenticated" do
+ %{conn: conn} = oauth_access(["read:statuses"])
+
+ res_conn = get(conn, "/api/v1/timelines/public", %{"local" => "true"})
+ assert length(json_response(res_conn, 200)) == 1
+
+ res_conn = get(conn, "/api/v1/timelines/public", %{"local" => "false"})
+ assert length(json_response(res_conn, 200)) == 2
+ end
+ end
+
+ describe "public with restrict unauthenticated timeline for local" do
+ setup do: local_and_remote_activities()
+
+ clear_config([:restrict_unauthenticated, :timelines, :local]) do
+ Config.put([:restrict_unauthenticated, :timelines, :local], true)
+ end
+
+ test "if user is unauthenticated", %{conn: conn} do
+ res_conn = get(conn, "/api/v1/timelines/public", %{"local" => "true"})
+
+ assert json_response(res_conn, :unauthorized) == %{
+ "error" => "authorization required for timeline view"
+ }
+
+ res_conn = get(conn, "/api/v1/timelines/public", %{"local" => "false"})
+ assert length(json_response(res_conn, 200)) == 2
+ end
+
+ test "if user is authenticated", %{conn: _conn} do
+ %{conn: conn} = oauth_access(["read:statuses"])
+
+ res_conn = get(conn, "/api/v1/timelines/public", %{"local" => "true"})
+ assert length(json_response(res_conn, 200)) == 1
+
+ res_conn = get(conn, "/api/v1/timelines/public", %{"local" => "false"})
+ assert length(json_response(res_conn, 200)) == 2
+ end
+ end
+
+ describe "public with restrict unauthenticated timeline for remote" do
+ setup do: local_and_remote_activities()
+
+ clear_config([:restrict_unauthenticated, :timelines, :federated]) do
+ Config.put([:restrict_unauthenticated, :timelines, :federated], true)
+ end
+
+ test "if user is unauthenticated", %{conn: conn} do
+ res_conn = get(conn, "/api/v1/timelines/public", %{"local" => "true"})
+ assert length(json_response(res_conn, 200)) == 1
+
+ res_conn = get(conn, "/api/v1/timelines/public", %{"local" => "false"})
+
+ assert json_response(res_conn, :unauthorized) == %{
+ "error" => "authorization required for timeline view"
+ }
+ end
+
+ test "if user is authenticated", %{conn: _conn} do
+ %{conn: conn} = oauth_access(["read:statuses"])
+
+ res_conn = get(conn, "/api/v1/timelines/public", %{"local" => "true"})
+ assert length(json_response(res_conn, 200)) == 1
+
+ res_conn = get(conn, "/api/v1/timelines/public", %{"local" => "false"})
+ assert length(json_response(res_conn, 200)) == 2
+ end
+ end
+
describe "direct" do
test "direct timeline", %{conn: conn} do
user_one = insert(:user)