Merge branch '2046-default-restrict-unauthenticated-basing-on-instance-privacy' into 'develop'

[#2046] Defaulted pleroma/restrict_unauthenticated basing on instance privacy

Closes #2046

See merge request pleroma/pleroma!2890
This commit is contained in:
lain 2020-08-17 12:26:53 +00:00
commit e154fcf525
10 changed files with 53 additions and 39 deletions

View file

@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Configuration: `:media_proxy, whitelist` format changed to host with scheme (e.g. `http://example.com` instead of `example.com`). Domain format is deprecated. - Configuration: `:media_proxy, whitelist` format changed to host with scheme (e.g. `http://example.com` instead of `example.com`). Domain format is deprecated.
- **Breaking:** Configuration: `:instance, welcome_user_nickname` moved to `:welcome, :direct_message, :sender_nickname`, `:instance, :welcome_message` moved to `:welcome, :direct_message, :message`. Old config namespace is deprecated. - **Breaking:** Configuration: `:instance, welcome_user_nickname` moved to `:welcome, :direct_message, :sender_nickname`, `:instance, :welcome_message` moved to `:welcome, :direct_message, :message`. Old config namespace is deprecated.
- **Breaking:** LDAP: Fallback to local database authentication has been removed for security reasons and lack of a mechanism to ensure the passwords are synchronized when LDAP passwords are updated. - **Breaking:** LDAP: Fallback to local database authentication has been removed for security reasons and lack of a mechanism to ensure the passwords are synchronized when LDAP passwords are updated.
- **Breaking** Changed defaults for `:restrict_unauthenticated` so that when `:instance, :public` is set to `false` then all `:restrict_unauthenticated` items be effectively set to `true`. If you'd like to allow unauthenticated access to specific API endpoints on a private instance, please explicitly set `:restrict_unauthenticated` to non-default value in `config/prod.secret.exs`.
<details> <details>
<summary>API Changes</summary> <summary>API Changes</summary>

View file

@ -725,10 +725,12 @@ config :pleroma, :hackney_pools,
timeout: 300_000 timeout: 300_000
] ]
private_instance? = :if_instance_is_private
config :pleroma, :restrict_unauthenticated, config :pleroma, :restrict_unauthenticated,
timelines: %{local: false, federated: false}, timelines: %{local: private_instance?, federated: private_instance?},
profiles: %{local: false, remote: false}, profiles: %{local: private_instance?, remote: private_instance?},
activities: %{local: false, remote: false} activities: %{local: private_instance?, remote: private_instance?}
config :pleroma, Pleroma.Web.ApiSpec.CastAndValidate, strict: false config :pleroma, Pleroma.Web.ApiSpec.CastAndValidate, strict: false

View file

@ -38,7 +38,7 @@ To add configuration to your config file, you can copy it from the base config.
* `federation_incoming_replies_max_depth`: Max. depth of reply-to activities fetching on incoming federation, to prevent out-of-memory situations while fetching very long threads. If set to `nil`, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes. * `federation_incoming_replies_max_depth`: Max. depth of reply-to activities fetching on incoming federation, to prevent out-of-memory situations while fetching very long threads. If set to `nil`, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes.
* `federation_reachability_timeout_days`: Timeout (in days) of each external federation target being unreachable prior to pausing federating to it. * `federation_reachability_timeout_days`: Timeout (in days) of each external federation target being unreachable prior to pausing federating to it.
* `allow_relay`: Enable Pleromas Relay, which makes it possible to follow a whole instance. * `allow_relay`: Enable Pleromas Relay, which makes it possible to follow a whole instance.
* `public`: Makes the client API in authenticated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. See also: `restrict_unauthenticated`. * `public`: Makes the client API in authenticated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. Note that there is a dependent setting restricting or allowing unauthenticated access to specific resources, see `restrict_unauthenticated` for more details.
* `quarantined_instances`: List of ActivityPub instances where private (DMs, followers-only) activities will not be send. * `quarantined_instances`: List of ActivityPub instances where private (DMs, followers-only) activities will not be send.
* `managed_config`: Whenether the config for pleroma-fe is configured in [:frontend_configurations](#frontend_configurations) or in ``static/config.json``. * `managed_config`: Whenether the config for pleroma-fe is configured in [:frontend_configurations](#frontend_configurations) or in ``static/config.json``.
* `allowed_post_formats`: MIME-type list of formats allowed to be posted (transformed into HTML). * `allowed_post_formats`: MIME-type list of formats allowed to be posted (transformed into HTML).
@ -1051,6 +1051,8 @@ Restrict access for unauthenticated users to timelines (public and federated), u
* `local` * `local`
* `remote` * `remote`
Note: when `:instance, :public` is set to `false`, all `:restrict_unauthenticated` items be effectively set to `true` by default. If you'd like to allow unauthenticated access to specific API endpoints on a private instance, please explicitly set `:restrict_unauthenticated` to non-default value in `config/prod.secret.exs`.
Note: setting `restrict_unauthenticated/timelines/local` to `true` has no practical sense if `restrict_unauthenticated/timelines/federated` is set to `false` (since local public activities will still be delivered to unauthenticated users as part of federated timeline). Note: setting `restrict_unauthenticated/timelines/local` to `true` has no practical sense if `restrict_unauthenticated/timelines/federated` is set to `false` (since local public activities will still be delivered to unauthenticated users as part of federated timeline).
## Pleroma.Web.ApiSpec.CastAndValidate ## Pleroma.Web.ApiSpec.CastAndValidate

View file

@ -81,6 +81,16 @@ defmodule Pleroma.Config do
Application.delete_env(:pleroma, key) Application.delete_env(:pleroma, key)
end end
def restrict_unauthenticated_access?(resource, kind) do
setting = get([:restrict_unauthenticated, resource, kind])
if setting in [nil, :if_instance_is_private] do
!get!([:instance, :public])
else
setting
end
end
def oauth_consumer_strategies, do: get([:auth, :oauth_consumer_strategies], []) def oauth_consumer_strategies, do: get([:auth, :oauth_consumer_strategies], [])
def oauth_consumer_enabled?, do: oauth_consumer_strategies() != [] def oauth_consumer_enabled?, do: oauth_consumer_strategies() != []

View file

@ -311,10 +311,12 @@ defmodule Pleroma.User do
def visible_for(_, _), do: :invisible def visible_for(_, _), do: :invisible
defp restrict_unauthenticated?(%User{local: local}) do defp restrict_unauthenticated?(%User{local: true}) do
config_key = if local, do: :local, else: :remote Config.restrict_unauthenticated_access?(:profiles, :local)
end
Config.get([:restrict_unauthenticated, :profiles, config_key], false) defp restrict_unauthenticated?(%User{local: _}) do
Config.restrict_unauthenticated_access?(:profiles, :remote)
end end
defp visible_account_status(user) do defp visible_account_status(user) do

View file

@ -59,12 +59,9 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
end end
def visible_for_user?(%{local: local} = activity, nil) do def visible_for_user?(%{local: local} = activity, nil) do
cfg_key = cfg_key = if local, do: :local, else: :remote
if local,
do: :local,
else: :remote
if Pleroma.Config.get([:restrict_unauthenticated, :activities, cfg_key]), if Pleroma.Config.restrict_unauthenticated_access?(:activities, cfg_key),
do: false, do: false,
else: is_public?(activity) else: is_public?(activity)
end end

View file

@ -8,6 +8,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
import Pleroma.Web.ControllerHelper, import Pleroma.Web.ControllerHelper,
only: [add_link_headers: 2, add_link_headers: 3] only: [add_link_headers: 2, add_link_headers: 3]
alias Pleroma.Config
alias Pleroma.Pagination alias Pleroma.Pagination
alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
alias Pleroma.Plugs.OAuthScopesPlug alias Pleroma.Plugs.OAuthScopesPlug
@ -89,11 +90,11 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
end end
defp restrict_unauthenticated?(true = _local_only) do defp restrict_unauthenticated?(true = _local_only) do
Pleroma.Config.get([:restrict_unauthenticated, :timelines, :local]) Config.restrict_unauthenticated_access?(:timelines, :local)
end end
defp restrict_unauthenticated?(_) do defp restrict_unauthenticated?(_) do
Pleroma.Config.get([:restrict_unauthenticated, :timelines, :federated]) Config.restrict_unauthenticated_access?(:timelines, :federated)
end end
# GET /api/v1/timelines/public # GET /api/v1/timelines/public

View file

@ -16,7 +16,7 @@ defmodule Pleroma.Web.Preload.Providers.Timelines do
end end
def build_public_tag(acc, params) do def build_public_tag(acc, params) do
if Pleroma.Config.get([:restrict_unauthenticated, :timelines, :federated], true) do if Pleroma.Config.restrict_unauthenticated_access?(:timelines, :federated) do
acc acc
else else
Map.put(acc, @public_url, public_timeline(params)) Map.put(acc, @public_url, public_timeline(params))

View file

@ -445,6 +445,23 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
assert length(json_response(res_conn, 200)) == 2 assert length(json_response(res_conn, 200)) == 2
end end
test "with default settings on private instances, returns 403 for unauthenticated users", %{
conn: conn,
base_uri: base_uri,
error_response: error_response
} do
clear_config([:instance, :public], false)
clear_config([:restrict_unauthenticated, :timelines])
for local <- [true, false] do
res_conn = get(conn, "#{base_uri}?local=#{local}")
assert json_response(res_conn, :unauthorized) == error_response
end
ensure_authenticated_access(base_uri)
end
test "with `%{local: true, federated: true}`, returns 403 for unauthenticated users", %{ test "with `%{local: true, federated: true}`, returns 403 for unauthenticated users", %{
conn: conn, conn: conn,
base_uri: base_uri, base_uri: base_uri,

View file

@ -12,16 +12,8 @@ defmodule Pleroma.Web.Preload.Providers.TimelineTest do
@public_url "/api/v1/timelines/public" @public_url "/api/v1/timelines/public"
describe "unauthenticated timeliness when restricted" do describe "unauthenticated timeliness when restricted" do
setup do setup do: clear_config([:restrict_unauthenticated, :timelines, :local], true)
svd_config = Pleroma.Config.get([:restrict_unauthenticated, :timelines]) setup do: clear_config([:restrict_unauthenticated, :timelines, :federated], true)
Pleroma.Config.put([:restrict_unauthenticated, :timelines], %{local: true, federated: true})
on_exit(fn ->
Pleroma.Config.put([:restrict_unauthenticated, :timelines], svd_config)
end)
:ok
end
test "return nothing" do test "return nothing" do
tl_data = Timelines.generate_terms(%{}) tl_data = Timelines.generate_terms(%{})
@ -31,20 +23,10 @@ defmodule Pleroma.Web.Preload.Providers.TimelineTest do
end end
describe "unauthenticated timeliness when unrestricted" do describe "unauthenticated timeliness when unrestricted" do
setup do setup do: clear_config([:restrict_unauthenticated, :timelines, :local], false)
svd_config = Pleroma.Config.get([:restrict_unauthenticated, :timelines]) setup do: clear_config([:restrict_unauthenticated, :timelines, :federated], false)
Pleroma.Config.put([:restrict_unauthenticated, :timelines], %{ setup do: {:ok, user: insert(:user)}
local: false,
federated: false
})
on_exit(fn ->
Pleroma.Config.put([:restrict_unauthenticated, :timelines], svd_config)
end)
{:ok, user: insert(:user)}
end
test "returns the timeline when not restricted" do test "returns the timeline when not restricted" do
assert Timelines.generate_terms(%{}) assert Timelines.generate_terms(%{})