diff options
34 files changed, 457 insertions, 90 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 88850133b..5afc57017 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).  - Rate limiter is now disabled for localhost/socket (unless remoteip plug is enabled)  - Logger: default log level changed from `warn` to `info`.  - Config mix task `migrate_to_db` truncates `config` table before migrating the config file. +- Allow account registration without an email  - Default to `prepare: :unnamed` in the database configuration.  - Instance stats are now loaded on startup instead of being empty until next hourly job.  <details> diff --git a/docs/administration/CLI_tasks/database.md b/docs/administration/CLI_tasks/database.md index 51c7484ba..ff400c8ed 100644 --- a/docs/administration/CLI_tasks/database.md +++ b/docs/administration/CLI_tasks/database.md @@ -10,11 +10,11 @@  Replaces embedded objects with references to them in the `objects` table. Only needs to be ran once if the instance was created before Pleroma 1.0.5. The reason why this is not a migration is because it could significantly increase the database size after being ran, however after this `VACUUM FULL` will be able to reclaim about 20% (really depends on what is in the database, your mileage may vary) of the db size before the migration.  ```sh tab="OTP" -./bin/pleroma_ctl database remove_embedded_objects [<options>] +./bin/pleroma_ctl database remove_embedded_objects [option ...]  ```  ```sh tab="From Source" -mix pleroma.database remove_embedded_objects [<options>] +mix pleroma.database remove_embedded_objects [option ...]  ```  ### Options @@ -28,11 +28,11 @@ This will prune remote posts older than 90 days (configurable with [`config :ple      The disk space will only be reclaimed after `VACUUM FULL`. You may run out of disk space during the execution of the task or vacuuming if you don't have about 1/3rds of the database size free.  ```sh tab="OTP" -./bin/pleroma_ctl database prune_objects [<options>] +./bin/pleroma_ctl database prune_objects [option ...]  ```  ```sh tab="From Source" -mix pleroma.database prune_objects [<options>] +mix pleroma.database prune_objects [option ...]  ```  ### Options diff --git a/docs/administration/CLI_tasks/digest.md b/docs/administration/CLI_tasks/digest.md index 1badda8c3..2eb31379e 100644 --- a/docs/administration/CLI_tasks/digest.md +++ b/docs/administration/CLI_tasks/digest.md @@ -5,11 +5,11 @@  ## Send digest email since given date (user registration date by default) ignoring user activity status.  ```sh tab="OTP" - ./bin/pleroma_ctl digest test <nickname> [<since_date>] + ./bin/pleroma_ctl digest test <nickname> [since_date]  ```  ```sh tab="From Source" -mix pleroma.digest test <nickname> [<since_date>] +mix pleroma.digest test <nickname> [since_date]  ``` diff --git a/docs/administration/CLI_tasks/emoji.md b/docs/administration/CLI_tasks/emoji.md index a3207bc6c..efec8222c 100644 --- a/docs/administration/CLI_tasks/emoji.md +++ b/docs/administration/CLI_tasks/emoji.md @@ -5,11 +5,11 @@  ## Lists emoji packs and metadata specified in the manifest  ```sh tab="OTP" -./bin/pleroma_ctl emoji ls-packs [<options>] +./bin/pleroma_ctl emoji ls-packs [option ...]  ```  ```sh tab="From Source" -mix pleroma.emoji ls-packs [<options>] +mix pleroma.emoji ls-packs [option ...]  ``` @@ -19,11 +19,11 @@ mix pleroma.emoji ls-packs [<options>]  ## Fetch, verify and install the specified packs from the manifest into `STATIC-DIR/emoji/PACK-NAME`  ```sh tab="OTP" -./bin/pleroma_ctl emoji get-packs [<options>] <packs> +./bin/pleroma_ctl emoji get-packs [option ...] <pack ...>  ```  ```sh tab="From Source" -mix pleroma.emoji get-packs [<options>] <packs> +mix pleroma.emoji get-packs [option ...] <pack ...>  ```  ### Options diff --git a/docs/administration/CLI_tasks/instance.md b/docs/administration/CLI_tasks/instance.md index 1a3b268be..52e264bb1 100644 --- a/docs/administration/CLI_tasks/instance.md +++ b/docs/administration/CLI_tasks/instance.md @@ -4,11 +4,11 @@  ## Generate a new configuration file  ```sh tab="OTP" - ./bin/pleroma_ctl instance gen [<options>] + ./bin/pleroma_ctl instance gen [option ...]  ```  ```sh tab="From Source" -mix pleroma.instance gen [<options>] +mix pleroma.instance gen [option ...]  ``` diff --git a/docs/administration/CLI_tasks/uploads.md b/docs/administration/CLI_tasks/uploads.md index e36c94c38..6a15d22f6 100644 --- a/docs/administration/CLI_tasks/uploads.md +++ b/docs/administration/CLI_tasks/uploads.md @@ -4,11 +4,11 @@  ## Migrate uploads from local to remote storage  ```sh tab="OTP" - ./bin/pleroma_ctl uploads migrate_local <target_uploader> [<options>] + ./bin/pleroma_ctl uploads migrate_local <target_uploader> [option ...]  ```  ```sh tab="From Source" -mix pleroma.uploads migrate_local <target_uploader> [<options>] +mix pleroma.uploads migrate_local <target_uploader> [option ...]  ```  ### Options diff --git a/docs/administration/CLI_tasks/user.md b/docs/administration/CLI_tasks/user.md index da8363131..f535dad82 100644 --- a/docs/administration/CLI_tasks/user.md +++ b/docs/administration/CLI_tasks/user.md @@ -5,11 +5,11 @@  ## Create a user  ```sh tab="OTP" -./bin/pleroma_ctl user new <email> [<options>] +./bin/pleroma_ctl user new <nickname> <email> [option ...]  ```  ```sh tab="From Source" -mix pleroma.user new <email> [<options>] +mix pleroma.user new <nickname> <email> [option ...]  ``` @@ -33,11 +33,11 @@ mix pleroma.user list  ## Generate an invite link  ```sh tab="OTP" - ./bin/pleroma_ctl user invite [<options>] + ./bin/pleroma_ctl user invite [option ...]  ```  ```sh tab="From Source" -mix pleroma.user invite [<options>] +mix pleroma.user invite [option ...]  ``` @@ -137,11 +137,11 @@ mix pleroma.user reset_password <nickname>  ## Set the value of the given user's settings  ```sh tab="OTP" - ./bin/pleroma_ctl user set <nickname> [<options>] + ./bin/pleroma_ctl user set <nickname> [option ...]  ```  ```sh tab="From Source" -mix pleroma.user set <nickname> [<options>] +mix pleroma.user set <nickname> [option ...]  ```  ### Options diff --git a/docs/administration/backup.md b/docs/administration/backup.md index 692aa7368..be57bf74a 100644 --- a/docs/administration/backup.md +++ b/docs/administration/backup.md @@ -18,9 +18,8 @@  6. Run `sudo -Hu postgres pg_restore -d <pleroma_db> -v -1 </path/to/backup_location/pleroma.pgdump>`  7. If you installed a newer Pleroma version, you should run `mix ecto.migrate`[^1]. This task performs database migrations, if there were any.  8. Restart the Pleroma service. -9. After you've restarted Pleroma, you will notice that postgres will take up more cpu resources than usual. A lot in fact. To fix this you must do a VACUUM ANLAYZE. This can also be done while the instance is still running like so:  -   $ sudo -u postgres psql pleroma_database_name -   pleroma=# VACUUM ANALYZE; +9. Run `sudo -Hu postgres vacuumdb --all --analyze-in-stages`. This will quickly generate the statistics so that postgres can properly plan queries. +  [^1]: Prefix with `MIX_ENV=prod` to run it using the production config file.  ## Remove diff --git a/docs/installation/otp_en.md b/docs/installation/otp_en.md index 32551f7b6..fb99af699 100644 --- a/docs/installation/otp_en.md +++ b/docs/installation/otp_en.md @@ -156,8 +156,8 @@ cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/conf.d/pleroma.conf  ```  ```sh tab="Debian/Ubuntu" -cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/sites-available/pleroma.nginx -ln -s /etc/nginx/sites-available/pleroma.nginx /etc/nginx/sites-enabled/pleroma.nginx +cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/sites-available/pleroma.conf +ln -s /etc/nginx/sites-available/pleroma.conf /etc/nginx/sites-enabled/pleroma.conf  ```  If your distro does not have either of those you can append `include /etc/nginx/pleroma.conf` to the end of the http section in /etc/nginx/nginx.conf and diff --git a/lib/mix/tasks/pleroma/docs.ex b/lib/mix/tasks/pleroma/docs.ex index 3c870f876..6088fc71d 100644 --- a/lib/mix/tasks/pleroma/docs.ex +++ b/lib/mix/tasks/pleroma/docs.ex @@ -28,7 +28,7 @@ defmodule Mix.Tasks.Pleroma.Docs do    defp do_run(implementation) do      start_pleroma() -    with descriptions <- Pleroma.Config.Loader.load("config/description.exs"), +    with descriptions <- Pleroma.Config.Loader.read("config/description.exs"),           {:ok, file_path} <-             Pleroma.Docs.Generator.process(               implementation, diff --git a/lib/mix/tasks/pleroma/relay.ex b/lib/mix/tasks/pleroma/relay.ex index c6ca888d4..c3312507e 100644 --- a/lib/mix/tasks/pleroma/relay.ex +++ b/lib/mix/tasks/pleroma/relay.ex @@ -35,7 +35,7 @@ defmodule Mix.Tasks.Pleroma.Relay do    def run(["list"]) do      start_pleroma() -    with {:ok, list} <- Relay.list() do +    with {:ok, list} <- Relay.list(true) do        list |> Enum.each(&shell_info(&1))      else        {:error, e} -> shell_error("Error while fetching relay subscription list: #{inspect(e)}") diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 397eb6e3f..6ca05f74e 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -308,6 +308,13 @@ defmodule Pleroma.Activity do      |> where([a], fragment("? ->> 'state' = 'pending'", a.data))    end +  def following_requests_for_actor(%Pleroma.User{ap_id: ap_id}) do +    Queries.by_type("Follow") +    |> where([a], fragment("?->>'state' = 'pending'", a.data)) +    |> where([a], a.actor == ^ap_id) +    |> Repo.all() +  end +    def restrict_deactivated_users(query) do      deactivated_users =        from(u in User.Query.build(%{deactivated: true}), select: u.ap_id) diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 55b5be488..719114671 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -35,6 +35,7 @@ defmodule Pleroma.Application do    # See http://elixir-lang.org/docs/stable/elixir/Application.html    # for more information on OTP Applications    def start(_type, _args) do +    Pleroma.Config.Holder.save_default()      Pleroma.HTML.compile_scrubbers()      Config.DeprecationWarnings.warn()      Pleroma.Plugs.HTTPSecurityPlug.warn_if_disabled() diff --git a/lib/pleroma/config/holder.ex b/lib/pleroma/config/holder.ex index f1a339703..f037d5d48 100644 --- a/lib/pleroma/config/holder.ex +++ b/lib/pleroma/config/holder.ex @@ -3,14 +3,33 @@  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Config.Holder do -  @config Pleroma.Config.Loader.load_and_merge() +  @config Pleroma.Config.Loader.default_config() -  @spec config() :: keyword() -  def config, do: @config +  @spec save_default() :: :ok +  def save_default do +    default_config = +      if System.get_env("RELEASE_NAME") do +        release_config = +          [:code.root_dir(), "releases", System.get_env("RELEASE_VSN"), "releases.exs"] +          |> Path.join() +          |> Pleroma.Config.Loader.read() -  @spec config(atom()) :: any() -  def config(group), do: @config[group] +        Pleroma.Config.Loader.merge(@config, release_config) +      else +        @config +      end -  @spec config(atom(), atom()) :: any() -  def config(group, key), do: @config[group][key] +    Pleroma.Config.put(:default_config, default_config) +  end + +  @spec default_config() :: keyword() +  def default_config, do: get_default() + +  @spec default_config(atom()) :: keyword() +  def default_config(group), do: Keyword.get(get_default(), group) + +  @spec default_config(atom(), atom()) :: keyword() +  def default_config(group, key), do: get_in(get_default(), [group, key]) + +  defp get_default, do: Pleroma.Config.get(:default_config)  end diff --git a/lib/pleroma/config/loader.ex b/lib/pleroma/config/loader.ex index df2d18725..6ca6550bd 100644 --- a/lib/pleroma/config/loader.ex +++ b/lib/pleroma/config/loader.ex @@ -13,32 +13,28 @@ defmodule Pleroma.Config.Loader do    ]    if Code.ensure_loaded?(Config.Reader) do -    @spec load(Path.t()) :: keyword() -    def load(path), do: Config.Reader.read!(path) +    @reader Config.Reader -    defp do_merge(conf1, conf2), do: Config.Reader.merge(conf1, conf2) +    def read(path), do: @reader.read!(path)    else      # support for Elixir less than 1.9 -    @spec load(Path.t()) :: keyword() -    def load(path) do +    @reader Mix.Config +    def read(path) do        path -      |> Mix.Config.eval!() +      |> @reader.eval!()        |> elem(0)      end - -    defp do_merge(conf1, conf2), do: Mix.Config.merge(conf1, conf2)    end -  @spec load_and_merge() :: keyword() -  def load_and_merge do -    all_paths = -      if Pleroma.Config.get(:release), -        do: ["config/config.exs", "config/releases.exs"], -        else: ["config/config.exs"] +  @spec read(Path.t()) :: keyword() + +  @spec merge(keyword(), keyword()) :: keyword() +  def merge(c1, c2), do: @reader.merge(c1, c2) -    all_paths -    |> Enum.map(&load(&1)) -    |> Enum.reduce([], &do_merge(&2, &1)) +  @spec default_config() :: keyword() +  def default_config do +    "config/config.exs" +    |> read()      |> filter()    end diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index b6d80adb7..936bc9ab1 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -104,7 +104,7 @@ defmodule Pleroma.Config.TransferTask do        key = ConfigDB.from_string(setting.key)        group = ConfigDB.from_string(setting.group) -      default = Config.Holder.config(group, key) +      default = Config.Holder.default_config(group, key)        value = ConfigDB.from_binary(setting.value)        merged_value = diff --git a/lib/pleroma/docs/json.ex b/lib/pleroma/docs/json.ex index 6508a7bdb..74f8b2615 100644 --- a/lib/pleroma/docs/json.ex +++ b/lib/pleroma/docs/json.ex @@ -15,7 +15,7 @@ defmodule Pleroma.Docs.JSON do    end    def compile do -    with config <- Pleroma.Config.Loader.load("config/description.exs") do +    with config <- Pleroma.Config.Loader.read("config/description.exs") do        config[:pleroma][:config_description]        |> Pleroma.Docs.Generator.convert_to_strings()        |> Jason.encode!() diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 5fe79333e..7531757f5 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -530,7 +530,14 @@ defmodule Pleroma.User do    end    def maybe_validate_required_email(changeset, true), do: changeset -  def maybe_validate_required_email(changeset, _), do: validate_required(changeset, [:email]) + +  def maybe_validate_required_email(changeset, _) do +    if Pleroma.Config.get([:instance, :account_activation_required]) do +      validate_required(changeset, [:email]) +    else +      changeset +    end +  end    defp put_ap_id(changeset) do      ap_id = ap_id(%User{nickname: get_field(changeset, :nickname)}) diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex index bb5542c89..729c23af7 100644 --- a/lib/pleroma/web/activity_pub/relay.ex +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -60,15 +60,28 @@ defmodule Pleroma.Web.ActivityPub.Relay do    def publish(_), do: {:error, "Not implemented"} -  @spec list() :: {:ok, [String.t()]} | {:error, any()} -  def list do +  @spec list(boolean()) :: {:ok, [String.t()]} | {:error, any()} +  def list(with_not_accepted \\ false) do      with %User{} = user <- get_actor() do -      list = +      accepted =          user          |> User.following()          |> Enum.map(fn entry -> URI.parse(entry).host end)          |> Enum.uniq() +      list = +        if with_not_accepted do +          without_accept = +            user +            |> Pleroma.Activity.following_requests_for_actor() +            |> Enum.map(fn a -> URI.parse(a.data["object"]).host <> " (no Accept received)" end) +            |> Enum.uniq() + +          accepted ++ without_accept +        else +          accepted +        end +        {:ok, list}      else        error -> format_error(error) diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index de0755ee5..47b7d2da3 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -834,7 +834,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do        configs = ConfigDB.get_all_as_keyword()        merged = -        Config.Holder.config() +        Config.Holder.default_config()          |> ConfigDB.merge(configs)          |> Enum.map(fn {group, values} ->            Enum.map(values, fn {key, value} -> diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 8746273c4..348fdedf1 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -591,7 +591,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do      limit = Pleroma.Config.get([:instance, :limit])      length = String.length(full_payload) -    if length < limit do +    if length <= limit do        :ok      else        {:error, dgettext("errors", "The status is over the character limit")} diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index dc3b47415..88c997b9f 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -76,7 +76,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do    @doc "POST /api/v1/accounts"    def create(          %{assigns: %{app: app}} = conn, -        %{"username" => nickname, "email" => _, "password" => _, "agreement" => true} = params +        %{"username" => nickname, "password" => _, "agreement" => true} = params        ) do      params =        params @@ -93,7 +93,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do        |> Map.put("bio", params["bio"] || "")        |> Map.put("confirm", params["password"]) -    with {:ok, user} <- TwitterAPI.register_user(params, need_confirmation: true), +    with :ok <- validate_email_param(params), +         {:ok, user} <- TwitterAPI.register_user(params, need_confirmation: true),           {:ok, token} <- Token.create_token(app, user, %{scopes: app.scopes}) do        json(conn, %{          token_type: "Bearer", @@ -114,6 +115,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do      render_error(conn, :forbidden, "Invalid credentials")    end +  defp validate_email_param(%{"email" => _}), do: :ok + +  defp validate_email_param(_) do +    case Pleroma.Config.get([:instance, :account_activation_required]) do +      true -> {:error, %{"error" => "Missing parameters"}} +      _ -> :ok +    end +  end +    @doc "GET /api/v1/accounts/verify_credentials"    def verify_credentials(%{assigns: %{user: user}} = conn, _) do      chat_token = Phoenix.Token.sign(conn, "user socket", user.id) diff --git a/priv/static/static/static-fe.css b/priv/static/static/static-fe.css new file mode 100644 index 000000000..19c56387b --- /dev/null +++ b/priv/static/static/static-fe.css @@ -0,0 +1,176 @@ +body { +    background-color: #282c37; +    font-family: sans-serif; +    color: white; +} + +main { +    margin: 50px auto; +    max-width: 960px; +    padding: 40px; +    background-color: #313543; +    border-radius: 4px; +} + +header { +    margin: 50px auto; +    max-width: 960px; +    padding: 40px; +    background-color: #313543; +    border-radius: 4px; +} + +.activity { +    border-radius: 4px; +    padding: 1em; +    padding-bottom: 2em; +    margin-bottom: 1em; +} + +.avatar { +    cursor: pointer; +} + +.avatar img { +    float: left; +    border-radius: 4px; +    margin-right: 4px; +} + +.activity-content img, video, audio { +    padding: 1em; +    max-width: 800px; +    max-height: 800px; +} + +#selected { +    background-color: #1b2735; +} + +.counts dt, .counts dd { +    float: left; +    margin-left: 1em; +} + +a { +    color: white; +} + +.h-card { +    min-height: 48px; +    margin-bottom: 8px; +} + +header a, .h-card a { +    text-decoration: none; +} + +header a:hover, .h-card a:hover { +    text-decoration: underline; +} + +.display-name { +    padding-top: 4px; +    display: block; +    text-overflow: ellipsis; +    overflow: hidden; +    color: white; +} + +/* keep emoji from being hilariously huge */ +.display-name img { +    max-height: 1em; +} + +.display-name .nickname { +    padding-top: 4px; +    display: block; +} + +.nickname:hover { +    text-decoration: none; +} + +.pull-right { +    float: right; +} + +.collapse { +    margin: 0; +    width: auto; +} + +h1 { +    margin: 0; +} + +h2 { +    color: #9baec8; +    font-weight: normal; +    font-size: 20px; +    margin-bottom: 40px; +} + +form { +    width: 100%; +} + +input { +    box-sizing: border-box; +    width: 100%; +    padding: 10px; +    margin-top: 20px; +    background-color: rgba(0,0,0,.1); +    color: white; +    border: 0; +    border-bottom: 2px solid #9baec8; +    font-size: 14px; +} + +input:focus { +    border-bottom: 2px solid #4b8ed8; +} + +input[type="checkbox"] { +    width: auto; +} + +button { +    box-sizing: border-box; +    width: 100%; +    color: white; +    background-color: #419bdd; +    border-radius: 4px; +    border: none; +    padding: 10px; +    margin-top: 30px; +    text-transform: uppercase; +    font-weight: 500; +    font-size: 16px; +} + +.alert-danger { +    box-sizing: border-box; +    width: 100%; +    color: #D8000C; +    background-color: #FFD2D2; +    border-radius: 4px; +    border: none; +    padding: 10px; +    margin-top: 20px; +    font-weight: 500; +    font-size: 16px; +} + +.alert-info { +    box-sizing: border-box; +    width: 100%; +    color: #00529B; +    background-color: #BDE5F8; +    border-radius: 4px; +    border: none; +    padding: 10px; +    margin-top: 20px; +    font-weight: 500; +    font-size: 16px; +} diff --git a/test/config/holder_test.exs b/test/config/holder_test.exs index 2368d4856..15d48b5c7 100644 --- a/test/config/holder_test.exs +++ b/test/config/holder_test.exs @@ -7,8 +7,8 @@ defmodule Pleroma.Config.HolderTest do    alias Pleroma.Config.Holder -  test "config/0" do -    config = Holder.config() +  test "default_config/0" do +    config = Holder.default_config()      assert config[:pleroma][Pleroma.Uploaders.Local][:uploads] == "test/uploads"      assert config[:tesla][:adapter] == Tesla.Mock @@ -20,15 +20,15 @@ defmodule Pleroma.Config.HolderTest do      refute config[:phoenix][:serve_endpoints]    end -  test "config/1" do -    pleroma_config = Holder.config(:pleroma) +  test "default_config/1" do +    pleroma_config = Holder.default_config(:pleroma)      assert pleroma_config[Pleroma.Uploaders.Local][:uploads] == "test/uploads" -    tesla_config = Holder.config(:tesla) +    tesla_config = Holder.default_config(:tesla)      assert tesla_config[:adapter] == Tesla.Mock    end -  test "config/2" do -    assert Holder.config(:pleroma, Pleroma.Uploaders.Local) == [uploads: "test/uploads"] -    assert Holder.config(:tesla, :adapter) == Tesla.Mock +  test "default_config/2" do +    assert Holder.default_config(:pleroma, Pleroma.Uploaders.Local) == [uploads: "test/uploads"] +    assert Holder.default_config(:tesla, :adapter) == Tesla.Mock    end  end diff --git a/test/config/loader_test.exs b/test/config/loader_test.exs index 4c93e5d4d..607572f4e 100644 --- a/test/config/loader_test.exs +++ b/test/config/loader_test.exs @@ -7,28 +7,13 @@ defmodule Pleroma.Config.LoaderTest do    alias Pleroma.Config.Loader -  test "load/1" do -    config = Loader.load("test/fixtures/config/temp.secret.exs") +  test "read/1" do +    config = Loader.read("test/fixtures/config/temp.secret.exs")      assert config[:pleroma][:first_setting][:key] == "value"      assert config[:pleroma][:first_setting][:key2] == [Pleroma.Repo]      assert config[:quack][:level] == :info    end -  test "load_and_merge/0" do -    config = Loader.load_and_merge() - -    refute config[:pleroma][Pleroma.Repo] -    refute config[:pleroma][Pleroma.Web.Endpoint] -    refute config[:pleroma][:env] -    refute config[:pleroma][:configurable_from_database] -    refute config[:pleroma][:database] -    refute config[:phoenix][:serve_endpoints] - -    assert config[:pleroma][:ecto_repos] == [Pleroma.Repo] -    assert config[:pleroma][Pleroma.Uploaders.Local][:uploads] == "test/uploads" -    assert config[:tesla][:adapter] == Tesla.Mock -  end -    test "filter_group/2" do      assert Loader.filter_group(:pleroma,               pleroma: [ diff --git a/test/config/transfer_task_test.exs b/test/config/transfer_task_test.exs index ce31d1e87..01d04761d 100644 --- a/test/config/transfer_task_test.exs +++ b/test/config/transfer_task_test.exs @@ -70,7 +70,7 @@ defmodule Pleroma.Config.TransferTaskTest do      assert Application.get_env(:quack, :level) == :info      assert Application.get_env(:quack, :meta) == [:none] -    default = Pleroma.Config.Holder.config(:quack, :webhook_url) +    default = Pleroma.Config.Holder.default_config(:quack, :webhook_url)      assert Application.get_env(:quack, :webhook_url) == default      on_exit(fn -> diff --git a/test/fixtures/relay/accept-follow.json b/test/fixtures/relay/accept-follow.json new file mode 100644 index 000000000..1b166f2da --- /dev/null +++ b/test/fixtures/relay/accept-follow.json @@ -0,0 +1,15 @@ +{ +  "@context": "https://www.w3.org/ns/activitystreams", +  "actor": "https://relay.mastodon.host/actor", +  "id": "https://relay.mastodon.host/activities/ec477b69-db26-4019-923e-cf809de516ab", +  "object": { +    "actor": "{{ap_id}}", +    "id": "{{activity_id}}", +    "object": "https://relay.mastodon.host/actor", +    "type": "Follow" +  }, +  "to": [ +    "{{ap_id}}" +  ], +  "type": "Accept" +}
\ No newline at end of file diff --git a/test/fixtures/relay/relay.json b/test/fixtures/relay/relay.json new file mode 100644 index 000000000..77ae7f06c --- /dev/null +++ b/test/fixtures/relay/relay.json @@ -0,0 +1,20 @@ +{ +  "@context": "https://www.w3.org/ns/activitystreams", +  "endpoints": { +    "sharedInbox": "https://relay.mastodon.host/inbox" +  }, +  "followers": "https://relay.mastodon.host/followers", +  "following": "https://relay.mastodon.host/following", +  "inbox": "https://relay.mastodon.host/inbox", +  "name": "ActivityRelay", +  "type": "Application", +  "id": "https://relay.mastodon.host/actor", +  "publicKey": { +    "id": "https://relay.mastodon.host/actor#main-key", +    "owner": "https://relay.mastodon.host/actor", +    "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuNYHNYETdsZFsdcTTEQo\nlsTP9yz4ZjOGrQ1EjoBA7NkjBUxxUAPxZbBjWPT9F+L3IbCX1IwI2OrBM/KwDlug\nV41xnjNmxSCUNpxX5IMZtFaAz9/hWu6xkRTs9Bh6XWZxi+db905aOqszb9Mo3H2g\nQJiAYemXwTh2kBO7XlBDbsMhO11Tu8FxcWTMdR54vlGv4RoiVh8dJRa06yyiTs+m\njbj/OJwR06mHHwlKYTVT/587NUb+e9QtCK6t/dqpyZ1o7vKSK5PSldZVjwHt292E\nXVxFOQVXi7JazTwpdPww79ECSe8ThCykOYCNkm3RjsKuLuokp7Vzq1hXIoeBJ7z2\ndU8vbgg/JyazsOsTxkVs2nd2i9/QW2SH+sX9X3357+XLSCh/A8p8fv/GeoN7UCXe\n4DWHFJZDlItNFfymiPbQH+omuju8qrfW9ngk1gFeI2mahXFQVu7x0qsaZYioCIrZ\nwq0zPnUGl9u0tLUXQz+ZkInRrEz+JepDVauy5/3QdzMLG420zCj/ygDrFzpBQIrc\n62Z6URueUBJox0UK71K+usxqOrepgw8haFGMvg3STFo34pNYjoK4oKO+h5qZEDFD\nb1n57t6JWUaBocZbJns9RGASq5gih+iMk2+zPLWp1x64yvuLsYVLPLBHxjCxS6lA\ndWcopZHi7R/OsRz+vTT7420CAwEAAQ==\n-----END PUBLIC KEY-----" +  }, +  "summary": "ActivityRelay bot", +  "preferredUsername": "relay", +  "url": "https://relay.mastodon.host/actor" +}
\ No newline at end of file diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index f1300637e..8a09e089b 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -1287,6 +1287,10 @@ defmodule HttpRequestMock do      {:ok, %Tesla.Env{status: 404, body: ""}}    end +  def get("https://relay.mastodon.host/actor", _, _, _) do +    {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/relay/relay.json")}} +  end +    def get(url, query, body, headers) do      {:error,       "Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{ @@ -1299,6 +1303,10 @@ defmodule HttpRequestMock do    def post(url, query \\ [], body \\ [], headers \\ []) +  def post("https://relay.mastodon.host/inbox", _, _, _) do +    {:ok, %Tesla.Env{status: 200, body: ""}} +  end +    def post("http://example.org/needs_refresh", _, _, _) do      {:ok,       %Tesla.Env{ diff --git a/test/tasks/relay_test.exs b/test/tasks/relay_test.exs index 08855f245..d3d88467d 100644 --- a/test/tasks/relay_test.exs +++ b/test/tasks/relay_test.exs @@ -38,6 +38,9 @@ defmodule Mix.Tasks.Pleroma.RelayTest do        assert activity.data["type"] == "Follow"        assert activity.data["actor"] == local_user.ap_id        assert activity.data["object"] == target_user.ap_id + +      :ok = Mix.Tasks.Pleroma.Relay.run(["list"]) +      assert_receive {:mix_shell, :info, ["mastodon.example.org (no Accept received)"]}      end    end diff --git a/test/user_test.exs b/test/user_test.exs index 84d7f5727..b07fed42b 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -412,7 +412,11 @@ defmodule Pleroma.UserTest do        assert activity.actor == welcome_user.ap_id      end -    test "it requires an email, name, nickname and password, bio is optional" do +    clear_config([:instance, :account_activation_required]) + +    test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do +      Pleroma.Config.put([:instance, :account_activation_required], true) +        @full_user_data        |> Map.keys()        |> Enum.each(fn key -> @@ -423,6 +427,19 @@ defmodule Pleroma.UserTest do        end)      end +    test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do +      Pleroma.Config.put([:instance, :account_activation_required], false) + +      @full_user_data +      |> Map.keys() +      |> Enum.each(fn key -> +        params = Map.delete(@full_user_data, key) +        changeset = User.register_changeset(%User{}, params) + +        assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid? +      end) +    end +      test "it restricts certain nicknames" do        [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames]) diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index 9151034da..b2352538a 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -341,6 +341,44 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        assert "ok" == json_response(conn, 200)        assert Instances.reachable?(sender_url)      end + +    test "accept follow activity", %{conn: conn} do +      Pleroma.Config.put([:instance, :federating], true) +      relay = Relay.get_actor() + +      assert {:ok, %Activity{} = activity} = Relay.follow("https://relay.mastodon.host/actor") + +      followed_relay = Pleroma.User.get_by_ap_id("https://relay.mastodon.host/actor") +      relay = refresh_record(relay) + +      accept = +        File.read!("test/fixtures/relay/accept-follow.json") +        |> String.replace("{{ap_id}}", relay.ap_id) +        |> String.replace("{{activity_id}}", activity.data["id"]) + +      assert "ok" == +               conn +               |> assign(:valid_signature, true) +               |> put_req_header("content-type", "application/activity+json") +               |> post("/inbox", accept) +               |> json_response(200) + +      ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) + +      assert Pleroma.FollowingRelationship.following?( +               relay, +               followed_relay +             ) + +      Mix.shell(Mix.Shell.Process) + +      on_exit(fn -> +        Mix.shell(Mix.Shell.IO) +      end) + +      :ok = Mix.Tasks.Pleroma.Relay.run(["list"]) +      assert_receive {:mix_shell, :info, ["relay.mastodon.host"]} +    end    end    describe "/users/:nickname/inbox" do diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index 299d968db..b80523160 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -202,13 +202,15 @@ defmodule Pleroma.Web.CommonAPITest do                 CommonAPI.post(user, %{"status" => ""})      end -    test "it returns error when character limit is exceeded" do +    test "it validates character limits are correctly enforced" do        Pleroma.Config.put([:instance, :limit], 5)        user = insert(:user)        assert {:error, "The status is over the character limit"} =                 CommonAPI.post(user, %{"status" => "foobar"}) + +      assert {:ok, activity} = CommonAPI.post(user, %{"status" => "12345"})      end      test "it can handle activities that expire" do diff --git a/test/web/mastodon_api/controllers/account_controller_test.exs b/test/web/mastodon_api/controllers/account_controller_test.exs index 57d0f4416..7f7d8cea3 100644 --- a/test/web/mastodon_api/controllers/account_controller_test.exs +++ b/test/web/mastodon_api/controllers/account_controller_test.exs @@ -601,6 +601,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do        [valid_params: valid_params]      end +    clear_config([:instance, :account_activation_required]) +      test "Account registration via Application", %{conn: conn} do        conn =          post(conn, "/api/v1/apps", %{ @@ -685,7 +687,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do        assert json_response(res, 200)        [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}] -      |> Stream.zip(valid_params) +      |> Stream.zip(Map.delete(valid_params, :email))        |> Enum.each(fn {ip, {attr, _}} ->          res =            conn @@ -697,6 +699,54 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do        end)      end +    clear_config([:instance, :account_activation_required]) + +    test "returns bad_request if missing email params when :account_activation_required is enabled", +         %{conn: conn, valid_params: valid_params} do +      Pleroma.Config.put([:instance, :account_activation_required], true) + +      app_token = insert(:oauth_token, user: nil) +      conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token) + +      res = +        conn +        |> Map.put(:remote_ip, {127, 0, 0, 5}) +        |> post("/api/v1/accounts", Map.delete(valid_params, :email)) + +      assert json_response(res, 400) == %{"error" => "Missing parameters"} + +      res = +        conn +        |> Map.put(:remote_ip, {127, 0, 0, 6}) +        |> post("/api/v1/accounts", Map.put(valid_params, :email, "")) + +      assert json_response(res, 400) == %{"error" => "{\"email\":[\"can't be blank\"]}"} +    end + +    test "allow registration without an email", %{conn: conn, valid_params: valid_params} do +      app_token = insert(:oauth_token, user: nil) +      conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token) + +      res = +        conn +        |> Map.put(:remote_ip, {127, 0, 0, 7}) +        |> post("/api/v1/accounts", Map.delete(valid_params, :email)) + +      assert json_response(res, 200) +    end + +    test "allow registration with an empty email", %{conn: conn, valid_params: valid_params} do +      app_token = insert(:oauth_token, user: nil) +      conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token) + +      res = +        conn +        |> Map.put(:remote_ip, {127, 0, 0, 8}) +        |> post("/api/v1/accounts", Map.put(valid_params, :email, "")) + +      assert json_response(res, 200) +    end +      test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do        conn = put_req_header(conn, "authorization", "Bearer " <> "invalid-token")  | 
