diff --git a/CHANGELOG.md b/CHANGELOG.md index 59f7dfcdd..f1766a255 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,34 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [2.0.1] - 2020-03-15 +### Security +- Static-FE: Fix remote posts not being sanitized + +### Fixed +- Rate limiter crashes when there is no explicitly specified ip in the config +- 500 errors when no `Accept` header is present if Static-FE is enabled +- Instance panel not being updated immediately due to wrong `Cache-Control` headers +- Statuses posted with BBCode/Markdown having unncessary newlines in Pleroma-FE +- OTP: Fix some settings not being migrated to in-database config properly +- No `Cache-Control` headers on attachment/media proxy requests +- Character limit enforcement being off by 1 +- Mastodon Streaming API: hashtag timelines not working + +### Changed +- BBCode and Markdown formatters will no longer return any `\n` and only use `
` for newlines +- Mastodon API: Allow registration without email if email verification is not enabled + +### Upgrade notes +#### Nginx only +1. Remove `proxy_ignore_headers Cache-Control;` and `proxy_hide_header Cache-Control;` from your config. + +#### Everyone +1. Run database migrations (inside Pleroma directory): + - OTP: `./bin/pleroma_ctl migrate` + - From Source: `mix ecto.migrate` +2. Restart Pleroma + ## [2.0.0] - 2019-03-08 ### Security - Mastodon API: Fix being able to request enourmous amount of statuses in timelines leading to DoS. Now limited to 40 per request. @@ -38,6 +66,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.
diff --git a/config/config.exs b/config/config.exs index 2cd741213..3357e23e7 100644 --- a/config/config.exs +++ b/config/config.exs @@ -504,10 +504,6 @@ federator_outgoing: 5 ] -config :pleroma, :fetch_initial_posts, - enabled: false, - pages: 5 - config :auto_linker, opts: [ extra: true, diff --git a/config/description.exs b/config/description.exs index 9fdcfcd96..c0e403b2e 100644 --- a/config/description.exs +++ b/config/description.exs @@ -2007,25 +2007,6 @@ } ] }, - %{ - group: :pleroma, - key: :fetch_initial_posts, - type: :group, - description: "Fetching initial posts settings", - children: [ - %{ - key: :enabled, - type: :boolean, - description: "Fetch posts when a new user is federated with" - }, - %{ - key: :pages, - type: :integer, - description: "The amount of pages to fetch", - suggestions: [5] - } - ] - }, %{ group: :auto_linker, key: :opts, diff --git a/config/test.exs b/config/test.exs index a17886265..b8ea63c94 100644 --- a/config/test.exs +++ b/config/test.exs @@ -92,6 +92,8 @@ config :pleroma, Pleroma.Emails.NewUsersDigestEmail, enabled: true +config :pleroma, Pleroma.Plugs.RemoteIp, enabled: false + if File.exists?("./config/test.secret.exs") do import_config "test.secret.exs" else diff --git a/docs/API/pleroma_api.md b/docs/API/pleroma_api.md index 761d5c69c..12e63ef9f 100644 --- a/docs/API/pleroma_api.md +++ b/docs/API/pleroma_api.md @@ -288,10 +288,11 @@ Pleroma Conversations have the same general structure that Mastodon Conversation 2. Pleroma Conversations statuses can be requested by Conversation id. 3. Pleroma Conversations can be replied to. -Conversations have the additional field "recipients" under the "pleroma" key. This holds a list of all the accounts that will receive a message in this conversation. +Conversations have the additional field `recipients` under the `pleroma` key. This holds a list of all the accounts that will receive a message in this conversation. The status posting endpoint takes an additional parameter, `in_reply_to_conversation_id`, which, when set, will set the visiblity to direct and address only the people who are the recipients of that Conversation. +⚠ Conversation IDs can be found in direct messages with the `pleroma.direct_conversation_id` key, do not confuse it with `pleroma.conversation_id`. ## `GET /api/v1/pleroma/conversations/:id/statuses` ### Timeline for a given conversation 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 [] +./bin/pleroma_ctl database remove_embedded_objects [option ...] ``` ```sh tab="From Source" -mix pleroma.database remove_embedded_objects [] +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 [] +./bin/pleroma_ctl database prune_objects [option ...] ``` ```sh tab="From Source" -mix pleroma.database prune_objects [] +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 [] + ./bin/pleroma_ctl digest test [since_date] ``` ```sh tab="From Source" -mix pleroma.digest test [] +mix pleroma.digest test [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 [] +./bin/pleroma_ctl emoji ls-packs [option ...] ``` ```sh tab="From Source" -mix pleroma.emoji ls-packs [] +mix pleroma.emoji ls-packs [option ...] ``` @@ -19,11 +19,11 @@ mix pleroma.emoji ls-packs [] ## 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 [] +./bin/pleroma_ctl emoji get-packs [option ...] ``` ```sh tab="From Source" -mix pleroma.emoji get-packs [] +mix pleroma.emoji get-packs [option ...] ``` ### 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 [] + ./bin/pleroma_ctl instance gen [option ...] ``` ```sh tab="From Source" -mix pleroma.instance gen [] +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 [] + ./bin/pleroma_ctl uploads migrate_local [option ...] ``` ```sh tab="From Source" -mix pleroma.uploads migrate_local [] +mix pleroma.uploads migrate_local [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 [] +./bin/pleroma_ctl user new [option ...] ``` ```sh tab="From Source" -mix pleroma.user new [] +mix pleroma.user new [option ...] ``` @@ -33,11 +33,11 @@ mix pleroma.user list ## Generate an invite link ```sh tab="OTP" - ./bin/pleroma_ctl user invite [] + ./bin/pleroma_ctl user invite [option ...] ``` ```sh tab="From Source" -mix pleroma.user invite [] +mix pleroma.user invite [option ...] ``` @@ -137,11 +137,11 @@ mix pleroma.user reset_password ## Set the value of the given user's settings ```sh tab="OTP" - ./bin/pleroma_ctl user set [] + ./bin/pleroma_ctl user set [option ...] ``` ```sh tab="From Source" -mix pleroma.user set [] +mix pleroma.user set [option ...] ``` ### Options diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 05fd6ceb1..2629385da 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -151,14 +151,6 @@ config :pleroma, :mrf_user_allowlist, * `sign_object_fetches`: Sign object fetches with HTTP signatures * `authorized_fetch_mode`: Require HTTP signatures for AP fetches -### :fetch_initial_posts - -!!! warning - Be careful with this setting, fetching posts may lead to new users being discovered whose posts will then also be fetched. This can lead to serious load on your instance and database. - -* `enabled`: If enabled, when a new user is discovered by your instance, fetch some of their latest posts. -* `pages`: The amount of pages to fetch - ## Pleroma.ScheduledActivity * `daily_user_limit`: the number of scheduled activities a user is allowed to create in a single day (Default: `25`) 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/installation/pleroma.nginx b/installation/pleroma.nginx index 7f48b614b..688be3e71 100644 --- a/installation/pleroma.nginx +++ b/installation/pleroma.nginx @@ -90,8 +90,6 @@ server { proxy_ignore_client_abort on; proxy_buffering on; chunked_transfer_encoding on; - proxy_ignore_headers Cache-Control; - proxy_hide_header Cache-Control; proxy_pass http://127.0.0.1:4000; } } 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 @@ def run(_) 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 @@ def run(["unfollow", target]) 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 @@ def follow_requests_for_actor(%Pleroma.User{ap_id: ap_id}) 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/activity/ir/topics.ex b/lib/pleroma/activity/ir/topics.ex index 4acc1a3e0..9e65bedad 100644 --- a/lib/pleroma/activity/ir/topics.ex +++ b/lib/pleroma/activity/ir/topics.ex @@ -39,7 +39,7 @@ defp visibility_tags(object, activity) do end end - defp item_creation_tags(tags, %{data: %{"type" => "Create"}} = object, activity) do + defp item_creation_tags(tags, object, %{data: %{"type" => "Create"}} = activity) do tags ++ hashtags_to_topics(object) ++ attachment_topics(object, activity) end diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 18854b850..33f1705df 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -31,6 +31,7 @@ def user_agent 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() Pleroma.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() - all_paths - |> Enum.map(&load(&1)) - |> Enum.reduce([], &do_merge(&2, &1)) + @spec merge(keyword(), keyword()) :: keyword() + def merge(c1, c2), do: @reader.merge(c1, c2) + + @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 435fc7450..7c3449b5e 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -83,7 +83,7 @@ defp merge_and_update(setting) do key = ConfigDB.from_string(setting.key) group = ConfigDB.from_string(setting.group) - default = Pleroma.Config.Holder.config(group, key) + default = Pleroma.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 @@ def process(descriptions) 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/earmark_renderer.ex b/lib/pleroma/earmark_renderer.ex new file mode 100644 index 000000000..6211a3b4a --- /dev/null +++ b/lib/pleroma/earmark_renderer.ex @@ -0,0 +1,256 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only +# +# This file is derived from Earmark, under the following copyright: +# Copyright © 2014 Dave Thomas, The Pragmatic Programmers +# SPDX-License-Identifier: Apache-2.0 +# Upstream: https://github.com/pragdave/earmark/blob/master/lib/earmark/html_renderer.ex +defmodule Pleroma.EarmarkRenderer do + @moduledoc false + + alias Earmark.Block + alias Earmark.Context + alias Earmark.HtmlRenderer + alias Earmark.Options + + import Earmark.Inline, only: [convert: 3] + import Earmark.Helpers.HtmlHelpers + import Earmark.Message, only: [add_messages_from: 2, get_messages: 1, set_messages: 2] + import Earmark.Context, only: [append: 2, set_value: 2] + import Earmark.Options, only: [get_mapper: 1] + + @doc false + def render(blocks, %Context{options: %Options{}} = context) do + messages = get_messages(context) + + {contexts, html} = + get_mapper(context.options).( + blocks, + &render_block(&1, put_in(context.options.messages, [])) + ) + |> Enum.unzip() + + all_messages = + contexts + |> Enum.reduce(messages, fn ctx, messages1 -> messages1 ++ get_messages(ctx) end) + + {put_in(context.options.messages, all_messages), html |> IO.iodata_to_binary()} + end + + ############# + # Paragraph # + ############# + defp render_block(%Block.Para{lnb: lnb, lines: lines, attrs: attrs}, context) do + lines = convert(lines, lnb, context) + add_attrs(lines, "

#{lines.value}

", attrs, [], lnb) + end + + ######## + # Html # + ######## + defp render_block(%Block.Html{html: html}, context) do + {context, html} + end + + defp render_block(%Block.HtmlComment{lines: lines}, context) do + {context, lines} + end + + defp render_block(%Block.HtmlOneline{html: html}, context) do + {context, html} + end + + ######### + # Ruler # + ######### + defp render_block(%Block.Ruler{lnb: lnb, attrs: attrs}, context) do + add_attrs(context, "
", attrs, [], lnb) + end + + ########### + # Heading # + ########### + defp render_block( + %Block.Heading{lnb: lnb, level: level, content: content, attrs: attrs}, + context + ) do + converted = convert(content, lnb, context) + html = "#{converted.value}" + add_attrs(converted, html, attrs, [], lnb) + end + + ############## + # Blockquote # + ############## + + defp render_block(%Block.BlockQuote{lnb: lnb, blocks: blocks, attrs: attrs}, context) do + {context1, body} = render(blocks, context) + html = "
#{body}
" + add_attrs(context1, html, attrs, [], lnb) + end + + ######### + # Table # + ######### + + defp render_block( + %Block.Table{lnb: lnb, header: header, rows: rows, alignments: aligns, attrs: attrs}, + context + ) do + {context1, html} = add_attrs(context, "", attrs, [], lnb) + context2 = set_value(context1, html) + + context3 = + if header do + append(add_trs(append(context2, ""), [header], "th", aligns, lnb), "") + else + # Maybe an error, needed append(context, html) + context2 + end + + context4 = append(add_trs(append(context3, ""), rows, "td", aligns, lnb), "") + + {context4, [context4.value, "
"]} + end + + ######## + # Code # + ######## + + defp render_block( + %Block.Code{lnb: lnb, language: language, attrs: attrs} = block, + %Context{options: options} = context + ) do + class = + if language, do: ~s{ class="#{code_classes(language, options.code_class_prefix)}"}, else: "" + + tag = ~s[
]
+    lines = options.render_code.(block)
+    html = ~s[#{tag}#{lines}
] + add_attrs(context, html, attrs, [], lnb) + end + + ######### + # Lists # + ######### + + defp render_block( + %Block.List{lnb: lnb, type: type, blocks: items, attrs: attrs, start: start}, + context + ) do + {context1, content} = render(items, context) + html = "<#{type}#{start}>#{content}" + add_attrs(context1, html, attrs, [], lnb) + end + + # format a single paragraph list item, and remove the para tags + defp render_block( + %Block.ListItem{lnb: lnb, blocks: blocks, spaced: false, attrs: attrs}, + context + ) + when length(blocks) == 1 do + {context1, content} = render(blocks, context) + content = Regex.replace(~r{}, content, "") + html = "
  • #{content}
  • " + add_attrs(context1, html, attrs, [], lnb) + end + + # format a spaced list item + defp render_block(%Block.ListItem{lnb: lnb, blocks: blocks, attrs: attrs}, context) do + {context1, content} = render(blocks, context) + html = "
  • #{content}
  • " + add_attrs(context1, html, attrs, [], lnb) + end + + ################## + # Footnote Block # + ################## + + defp render_block(%Block.FnList{blocks: footnotes}, context) do + items = + Enum.map(footnotes, fn note -> + blocks = append_footnote_link(note) + %Block.ListItem{attrs: "#fn:#{note.number}", type: :ol, blocks: blocks} + end) + + {context1, html} = render_block(%Block.List{type: :ol, blocks: items}, context) + {context1, Enum.join([~s[
    ], "
    ", html, "
    "])} + end + + ####################################### + # Isolated IALs are rendered as paras # + ####################################### + + defp render_block(%Block.Ial{verbatim: verbatim}, context) do + {context, "

    {:#{verbatim}}

    "} + end + + #################### + # IDDef is ignored # + #################### + + defp render_block(%Block.IdDef{}, context), do: {context, ""} + + ##################################### + # And here are the inline renderers # + ##################################### + + defdelegate br, to: HtmlRenderer + defdelegate codespan(text), to: HtmlRenderer + defdelegate em(text), to: HtmlRenderer + defdelegate strong(text), to: HtmlRenderer + defdelegate strikethrough(text), to: HtmlRenderer + + defdelegate link(url, text), to: HtmlRenderer + defdelegate link(url, text, title), to: HtmlRenderer + + defdelegate image(path, alt, title), to: HtmlRenderer + + defdelegate footnote_link(ref, backref, number), to: HtmlRenderer + + # Table rows + defp add_trs(context, rows, tag, aligns, lnb) do + numbered_rows = + rows + |> Enum.zip(Stream.iterate(lnb, &(&1 + 1))) + + numbered_rows + |> Enum.reduce(context, fn {row, lnb}, ctx -> + append(add_tds(append(ctx, ""), row, tag, aligns, lnb), "") + end) + end + + defp add_tds(context, row, tag, aligns, lnb) do + Enum.reduce(1..length(row), context, add_td_fn(row, tag, aligns, lnb)) + end + + defp add_td_fn(row, tag, aligns, lnb) do + fn n, ctx -> + style = + case Enum.at(aligns, n - 1, :default) do + :default -> "" + align -> " style=\"text-align: #{align}\"" + end + + col = Enum.at(row, n - 1) + converted = convert(col, lnb, set_messages(ctx, [])) + append(add_messages_from(ctx, converted), "<#{tag}#{style}>#{converted.value}") + end + end + + ############################### + # Append Footnote Return Link # + ############################### + + defdelegate append_footnote_link(note), to: HtmlRenderer + defdelegate append_footnote_link(note, fnlink), to: HtmlRenderer + + defdelegate render_code(lines), to: HtmlRenderer + + defp code_classes(language, prefix) do + ["" | String.split(prefix || "")] + |> Enum.map(fn pfx -> "#{pfx}#{language}" end) + |> Enum.join(" ") + end +end diff --git a/lib/pleroma/plugs/rate_limiter/rate_limiter.ex b/lib/pleroma/plugs/rate_limiter/rate_limiter.ex index c3f6351c8..1529da717 100644 --- a/lib/pleroma/plugs/rate_limiter/rate_limiter.ex +++ b/lib/pleroma/plugs/rate_limiter/rate_limiter.ex @@ -78,7 +78,7 @@ def init(plug_opts) do end def call(conn, plug_opts) do - if disabled?() do + if disabled?(conn) do handle_disabled(conn) else action_settings = action_settings(plug_opts) @@ -87,9 +87,9 @@ def call(conn, plug_opts) do end defp handle_disabled(conn) do - if Config.get(:env) == :prod do - Logger.warn("Rate limiter is disabled for localhost/socket") - end + Logger.warn( + "Rate limiter disabled due to forwarded IP not being found. Please ensure your reverse proxy is providing the X-Forwarded-For header or disable the RemoteIP plug/rate limiter." + ) conn end @@ -109,16 +109,21 @@ defp handle(conn, action_settings) do end end - def disabled? do + def disabled?(conn) do localhost_or_socket = - Config.get([Pleroma.Web.Endpoint, :http, :ip]) - |> Tuple.to_list() - |> Enum.join(".") - |> String.match?(~r/^local|^127.0.0.1/) + case Config.get([Pleroma.Web.Endpoint, :http, :ip]) do + {127, 0, 0, 1} -> true + {0, 0, 0, 0, 0, 0, 0, 1} -> true + {:local, _} -> true + _ -> false + end - remote_ip_disabled = not Config.get([Pleroma.Plugs.RemoteIp, :enabled]) + remote_ip_not_found = + if Map.has_key?(conn.assigns, :remote_ip_found), + do: !conn.assigns.remote_ip_found, + else: false - localhost_or_socket and remote_ip_disabled + localhost_or_socket and remote_ip_not_found end @inspect_bucket_not_found {:error, :not_found} diff --git a/lib/pleroma/plugs/remote_ip.ex b/lib/pleroma/plugs/remote_ip.ex index 2eca4f8f6..0ac9050d0 100644 --- a/lib/pleroma/plugs/remote_ip.ex +++ b/lib/pleroma/plugs/remote_ip.ex @@ -7,6 +7,8 @@ defmodule Pleroma.Plugs.RemoteIp do This is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration. """ + import Plug.Conn + @behaviour Plug @headers ~w[ @@ -26,11 +28,12 @@ defmodule Pleroma.Plugs.RemoteIp do def init(_), do: nil - def call(conn, _) do + def call(%{remote_ip: original_remote_ip} = conn, _) do config = Pleroma.Config.get(__MODULE__, []) if Keyword.get(config, :enabled, false) do - RemoteIp.call(conn, remote_ip_opts(config)) + %{remote_ip: new_remote_ip} = conn = RemoteIp.call(conn, remote_ip_opts(config)) + assign(conn, :remote_ip_found, original_remote_ip != new_remote_ip) else conn end diff --git a/lib/pleroma/plugs/static_fe_plug.ex b/lib/pleroma/plugs/static_fe_plug.ex index deebe4879..156e6788e 100644 --- a/lib/pleroma/plugs/static_fe_plug.ex +++ b/lib/pleroma/plugs/static_fe_plug.ex @@ -21,6 +21,9 @@ def call(conn, _) do defp enabled?, do: Pleroma.Config.get([:static_fe, :enabled], false) defp accepts_html?(conn) do - conn |> get_req_header("accept") |> List.first() |> String.contains?("text/html") + case get_req_header(conn, "accept") do + [accept | _] -> String.contains?(accept, "text/html") + _ -> false + end end end diff --git a/lib/pleroma/plugs/uploaded_media.ex b/lib/pleroma/plugs/uploaded_media.ex index f372829a2..36ff024a7 100644 --- a/lib/pleroma/plugs/uploaded_media.ex +++ b/lib/pleroma/plugs/uploaded_media.ex @@ -14,9 +14,14 @@ defmodule Pleroma.Plugs.UploadedMedia do # no slashes @path "media" + @default_cache_control_header "public, max-age=1209600" + def init(_opts) do static_plug_opts = - [] + [ + headers: %{"cache-control" => @default_cache_control_header}, + cache_control_for_etags: @default_cache_control_header + ] |> Keyword.put(:from, "__unconfigured_media_plug") |> Keyword.put(:at, "/__unconfigured_media_plug") |> Plug.Static.init() diff --git a/lib/pleroma/reverse_proxy/reverse_proxy.ex b/lib/pleroma/reverse_proxy/reverse_proxy.ex index a281a00dc..8b713b8f4 100644 --- a/lib/pleroma/reverse_proxy/reverse_proxy.ex +++ b/lib/pleroma/reverse_proxy/reverse_proxy.ex @@ -7,7 +7,7 @@ defmodule Pleroma.ReverseProxy do @keep_req_headers ~w(accept user-agent accept-encoding cache-control if-modified-since) ++ ~w(if-unmodified-since if-none-match if-range range) - @resp_cache_headers ~w(etag date last-modified cache-control) + @resp_cache_headers ~w(etag date last-modified) @keep_resp_headers @resp_cache_headers ++ ~w(content-type content-disposition content-encoding content-range) ++ ~w(accept-ranges vary) @@ -34,9 +34,6 @@ defmodule Pleroma.ReverseProxy do * request: `#{inspect(@keep_req_headers)}` * response: `#{inspect(@keep_resp_headers)}` - If no caching headers (`#{inspect(@resp_cache_headers)}`) are returned by upstream, `cache-control` will be - set to `#{inspect(@default_cache_control_header)}`. - Options: * `redirect_on_failure` (default `false`). Redirects the client to the real remote URL if there's any HTTP @@ -297,16 +294,17 @@ defp build_resp_headers(headers, opts) do defp build_resp_cache_headers(headers, _opts) do has_cache? = Enum.any?(headers, fn {k, _} -> k in @resp_cache_headers end) - has_cache_control? = List.keymember?(headers, "cache-control", 0) cond do - has_cache? && has_cache_control? -> - headers - has_cache? -> - # There's caching header present but no cache-control -- we need to explicitely override it - # to public as Plug defaults to "max-age=0, private, must-revalidate" - List.keystore(headers, "cache-control", 0, {"cache-control", "public"}) + # There's caching header present but no cache-control -- we need to set our own + # as Plug defaults to "max-age=0, private, must-revalidate" + List.keystore( + headers, + "cache-control", + 0, + {"cache-control", @default_cache_control_header} + ) true -> List.keystore( diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 5fe79333e..911dde6e2 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -16,6 +16,7 @@ defmodule Pleroma.User do alias Pleroma.Conversation.Participation alias Pleroma.Delivery alias Pleroma.FollowingRelationship + alias Pleroma.HTML alias Pleroma.Keys alias Pleroma.Notification alias Pleroma.Object @@ -530,7 +531,14 @@ def register_changeset(struct, params \\ %{}, opts \\ []) 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)}) @@ -832,10 +840,6 @@ def get_or_fetch_by_nickname(nickname) do _e -> with [_nick, _domain] <- String.split(nickname, "@"), {:ok, user} <- fetch_by_nickname(nickname) do - if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do - fetch_initial_posts(user) - end - {:ok, user} else _e -> {:error, "not found " <> nickname} @@ -843,11 +847,6 @@ def get_or_fetch_by_nickname(nickname) do end end - @doc "Fetch some posts when the user has just been federated with" - def fetch_initial_posts(user) do - BackgroundWorker.enqueue("fetch_initial_posts", %{"user_id" => user.id}) - end - @spec get_followers_query(User.t(), pos_integer() | nil) :: Ecto.Query.t() def get_followers_query(%User{} = user, nil) do User.Query.build(%{followers: user, deactivated: false}) @@ -1313,16 +1312,6 @@ def perform(:delete, %User{} = user) do Repo.delete(user) end - def perform(:fetch_initial_posts, %User{} = user) do - pages = Pleroma.Config.get!([:fetch_initial_posts, :pages]) - - # Insert all the posts in reverse order, so they're in the right order on the timeline - user.source_data["outbox"] - |> Utils.fetch_ordered_collection(pages) - |> Enum.reverse() - |> Enum.each(&Pleroma.Web.Federator.incoming_ap_doc/1) - end - def perform(:deactivate_async, user, status), do: deactivate(user, status) @spec perform(atom(), User.t(), list()) :: list() | {:error, any()} @@ -1451,18 +1440,7 @@ def get_or_fetch_by_ap_id(ap_id) do if !is_nil(user) and !needs_update?(user) do {:ok, user} else - # Whether to fetch initial posts for the user (if it's a new user & the fetching is enabled) - should_fetch_initial = is_nil(user) and Pleroma.Config.get([:fetch_initial_posts, :enabled]) - - resp = fetch_by_ap_id(ap_id) - - if should_fetch_initial do - with {:ok, %User{} = user} <- resp do - fetch_initial_posts(user) - end - end - - resp + fetch_by_ap_id(ap_id) end end @@ -2055,4 +2033,27 @@ def set_invisible(user, invisible) do |> validate_required([:invisible]) |> update_and_set_cache() end + + def sanitize_html(%User{} = user) do + sanitize_html(user, nil) + end + + # User data that mastodon isn't filtering (treated as plaintext): + # - field name + # - display name + def sanitize_html(%User{} = user, filter) do + fields = + user + |> User.fields() + |> Enum.map(fn %{"name" => name, "value" => value} -> + %{ + "name" => name, + "value" => HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly) + } + end) + + user + |> Map.put(:bio, HTML.filter_tags(user.bio, filter)) + |> Map.put(:fields, fields) + end end 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 @@ def publish(%Activity{data: %{"type" => "Create"}} = activity) 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/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 2bc958670..15dd2ed45 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -784,45 +784,6 @@ defp build_flag_object(act) when is_map(act) or is_binary(act) do defp build_flag_object(_), do: [] - @doc """ - Fetches the OrderedCollection/OrderedCollectionPage from `from`, limiting the amount of pages fetched after - the first one to `pages_left` pages. - If the amount of pages is higher than the collection has, it returns whatever was there. - """ - def fetch_ordered_collection(from, pages_left, acc \\ []) do - with {:ok, response} <- Tesla.get(from), - {:ok, collection} <- Jason.decode(response.body) do - case collection["type"] do - "OrderedCollection" -> - # If we've encountered the OrderedCollection and not the page, - # just call the same function on the page address - fetch_ordered_collection(collection["first"], pages_left) - - "OrderedCollectionPage" -> - if pages_left > 0 do - # There are still more pages - if Map.has_key?(collection, "next") do - # There are still more pages, go deeper saving what we have into the accumulator - fetch_ordered_collection( - collection["next"], - pages_left - 1, - acc ++ collection["orderedItems"] - ) - else - # No more pages left, just return whatever we already have - acc ++ collection["orderedItems"] - end - else - # Got the amount of pages needed, add them all to the accumulator - acc ++ collection["orderedItems"] - end - - _ -> - {:error, "Not an OrderedCollection or OrderedCollectionPage"} - end - end - end - #### Report-related helpers def get_reports(params, page, page_size) do params = diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index c0358b678..bc21ac6c7 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -73,6 +73,7 @@ def render("user.json", %{user: user}) do {:ok, _, public_key} = Keys.keys_from_pem(user.keys) public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key) public_key = :public_key.pem_encode([public_key]) + user = User.sanitize_html(user) endpoints = render("endpoints.json", %{user: user}) @@ -81,12 +82,6 @@ def render("user.json", %{user: user}) do fields = user |> User.fields() - |> Enum.map(fn %{"name" => name, "value" => value} -> - %{ - "name" => Pleroma.HTML.strip_tags(name), - "value" => Pleroma.HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly) - } - end) |> Enum.map(&Map.put(&1, "type", "PropertyValue")) %{ 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 @@ def config_show(conn, _params) 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/admin_api/views/account_view.ex b/lib/pleroma/web/admin_api/views/account_view.ex index 619390ef4..1e03849de 100644 --- a/lib/pleroma/web/admin_api/views/account_view.ex +++ b/lib/pleroma/web/admin_api/views/account_view.ex @@ -5,7 +5,6 @@ defmodule Pleroma.Web.AdminAPI.AccountView do use Pleroma.Web, :view - alias Pleroma.HTML alias Pleroma.User alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.MediaProxy @@ -26,7 +25,8 @@ def render("index.json", %{users: users}) do def render("show.json", %{user: user}) do avatar = User.avatar_url(user) |> MediaProxy.url() - display_name = HTML.strip_tags(user.name || user.nickname) + display_name = Pleroma.HTML.strip_tags(user.name || user.nickname) + user = User.sanitize_html(user, FastSanitize.Sanitizer.StripTags) %{ "id" => user.id, diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 8746273c4..635e7cd38 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -331,7 +331,7 @@ def format_input(text, "text/html", options) do def format_input(text, "text/markdown", options) do text |> Formatter.mentions_escape(options) - |> Earmark.as_html!() + |> Earmark.as_html!(%Earmark.Options{renderer: Pleroma.EarmarkRenderer}) |> Formatter.linkify(options) |> Formatter.html_escape("text/html") end @@ -591,7 +591,7 @@ def validate_character_limit(full_payload, _attachments) 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/endpoint.ex b/lib/pleroma/web/endpoint.ex index 118c3ac6f..72cb3ee27 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -12,7 +12,7 @@ defmodule Pleroma.Web.Endpoint do plug(Pleroma.Plugs.HTTPSecurityPlug) plug(Pleroma.Plugs.UploadedMedia) - @static_cache_control "public max-age=86400 must-revalidate" + @static_cache_control "public, no-cache" # InstanceStatic needs to be before Plug.Static to be able to override shipped-static files # If you're adding new paths to `only:` you'll need to configure them in InstanceStatic as well 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 @@ def create( |> 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 @@ def create(conn, _) 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/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex index f165c9965..37b389382 100644 --- a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex @@ -86,6 +86,6 @@ defp local_mastodon_root_path(conn) do @spec get_or_make_app() :: {:ok, App.t()} | {:error, Ecto.Changeset.t()} defp get_or_make_app do %{client_name: @local_mastodon_name, redirect_uris: "."} - |> App.get_or_make(["read", "write", "follow", "push"]) + |> App.get_or_make(["read", "write", "follow", "push", "admin"]) end end diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 6dc191250..341dc2c91 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -5,7 +5,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do use Pleroma.Web, :view - alias Pleroma.HTML alias Pleroma.User alias Pleroma.Web.CommonAPI.Utils alias Pleroma.Web.MastodonAPI.AccountView @@ -67,6 +66,7 @@ def render("relationships.json", %{user: user, targets: targets}) do end defp do_render("show.json", %{user: user} = opts) do + user = User.sanitize_html(user, User.html_filter_policy(opts[:for])) display_name = user.name || user.nickname image = User.avatar_url(user) |> MediaProxy.url() @@ -100,17 +100,6 @@ defp do_render("show.json", %{user: user} = opts) do } end) - fields = - user - |> User.fields() - |> Enum.map(fn %{"name" => name, "value" => value} -> - %{ - "name" => name, - "value" => Pleroma.HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly) - } - end) - - bio = HTML.filter_tags(user.bio, User.html_filter_policy(opts[:for])) relationship = render("relationship.json", %{user: opts[:for], target: user}) %{ @@ -123,17 +112,17 @@ defp do_render("show.json", %{user: user} = opts) do followers_count: followers_count, following_count: following_count, statuses_count: user.note_count, - note: bio || "", + note: user.bio || "", url: User.profile_url(user), avatar: image, avatar_static: image, header: header, header_static: header, emojis: emojis, - fields: fields, + fields: user.fields, bot: bot, source: %{ - note: HTML.strip_tags((user.bio || "") |> String.replace("
    ", "\n")), + note: Pleroma.HTML.strip_tags((user.bio || "") |> String.replace("
    ", "\n")), sensitive: false, fields: user.raw_fields, pleroma: %{ diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex index 0e160bbfc..dae7f0f2f 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -101,6 +101,11 @@ def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) conn |> put_view(ConversationView) |> render("participation.json", %{participation: participation, for: user}) + else + _error -> + conn + |> put_status(404) + |> json(%{"error" => "Unknown conversation id"}) end end @@ -108,9 +113,9 @@ def conversation_statuses( %{assigns: %{user: user}} = conn, %{"id" => participation_id} = params ) do - participation = Participation.get(participation_id, preload: [:conversation]) - - if user.id == participation.user_id do + with %Participation{} = participation <- + Participation.get(participation_id, preload: [:conversation]), + true <- user.id == participation.user_id do params = params |> Map.put("blocking_user", user) @@ -126,6 +131,11 @@ def conversation_statuses( |> add_link_headers(activities) |> put_view(StatusView) |> render("index.json", %{activities: activities, for: user, as: :activity}) + else + _error -> + conn + |> put_status(404) + |> json(%{"error" => "Unknown conversation id"}) end end @@ -133,15 +143,22 @@ def update_conversation( %{assigns: %{user: user}} = conn, %{"id" => participation_id, "recipients" => recipients} ) do - participation = - participation_id - |> Participation.get() - - with true <- user.id == participation.user_id, + with %Participation{} = participation <- Participation.get(participation_id), + true <- user.id == participation.user_id, {:ok, participation} <- Participation.set_recipients(participation, recipients) do conn |> put_view(ConversationView) |> render("participation.json", %{participation: participation, for: user}) + else + {:error, message} -> + conn + |> put_status(:bad_request) + |> json(%{"error" => message}) + + _error -> + conn + |> put_status(404) + |> json(%{"error" => "Unknown conversation id"}) end end diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 5ac75f1c4..98977bc19 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -54,10 +54,17 @@ def represent(%Activity{object: %Object{data: data}} = activity, selected) do _ -> data["url"] || data["external_url"] || data["id"] end + content = + if data["content"] do + Pleroma.HTML.filter_tags(data["content"]) + else + nil + end + %{ - user: user, + user: User.sanitize_html(user), title: get_title(activity.object), - content: data["content"] || nil, + content: content, attachment: data["attachment"], link: link, published: data["published"], @@ -109,7 +116,7 @@ def show(%{assigns: %{username_or_id: username_or_id}} = conn, params) do next_page_id = List.last(timeline) && List.last(timeline).id render(conn, "profile.html", %{ - user: user, + user: User.sanitize_html(user), timeline: timeline, prev_page_id: prev_page_id, next_page_id: next_page_id, diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex index 598df6580..0f8ece2c4 100644 --- a/lib/pleroma/workers/background_worker.ex +++ b/lib/pleroma/workers/background_worker.ex @@ -10,10 +10,6 @@ defmodule Pleroma.Workers.BackgroundWorker do use Pleroma.Workers.WorkerHelper, queue: "background" @impl Oban.Worker - def perform(%{"op" => "fetch_initial_posts", "user_id" => user_id}, _job) do - user = User.get_cached_by_id(user_id) - User.perform(:fetch_initial_posts, user) - end def perform(%{"op" => "deactivate_user", "user_id" => user_id, "status" => status}, _job) do user = User.get_cached_by_id(user_id) diff --git a/mix.exs b/mix.exs index 89b56bc5d..b55a79a77 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do def project do [ app: :pleroma, - version: version("2.0.0"), + version: version("2.0.1"), elixir: "~> 1.8", elixirc_paths: elixirc_paths(Mix.env()), compilers: [:phoenix, :gettext] ++ Mix.compilers(), @@ -126,7 +126,7 @@ defp deps do {:ex_aws_s3, "~> 2.0"}, {:sweet_xml, "~> 0.6.6"}, {:earmark, "~> 1.3"}, - {:bbcode, "~> 0.1.1"}, + {:bbcode_pleroma, "~> 0.2.0"}, {:ex_machina, "~> 2.3", only: :test}, {:credo, "~> 1.1.0", only: [:dev, :test], runtime: false}, {:mock, "~> 0.3.3", only: :test}, diff --git a/mix.lock b/mix.lock index c8b30a6f9..62e14924a 100644 --- a/mix.lock +++ b/mix.lock @@ -3,7 +3,8 @@ "auto_linker": {:git, "https://git.pleroma.social/pleroma/auto_linker.git", "95e8188490e97505c56636c1379ffdf036c1fdde", [ref: "95e8188490e97505c56636c1379ffdf036c1fdde"]}, "base62": {:hex, :base62, "1.2.1", "4866763e08555a7b3917064e9eef9194c41667276c51b59de2bc42c6ea65f806", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm", "3b29948de2013d3f93aa898c884a9dff847e7aec75d9d6d8c1dc4c61c2716c42"}, "base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"}, - "bbcode": {:hex, :bbcode, "0.1.1", "0023e2c7814119b2e620b7add67182e3f6019f92bfec9a22da7e99821aceba70", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5a981b98ac7d366a9b6bf40eac389aaf4d6e623c631e6b6f8a6b571efaafd338"}, + "bbcode": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/bbcode.git", "f2d267675e9a7e1ad1ea9beb4cc23382762b66c2", [ref: "v0.2.0"]}, + "bbcode_pleroma": {:hex, :bbcode_pleroma, "0.2.0", "d36f5bca6e2f62261c45be30fa9b92725c0655ad45c99025cb1c3e28e25803ef", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "19851074419a5fedb4ef49e1f01b30df504bb5dbb6d6adfc135238063bebd1c3"}, "benchee": {:hex, :benchee, "1.0.1", "66b211f9bfd84bd97e6d1beaddf8fc2312aaabe192f776e8931cb0c16f53a521", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}], "hexpm", "3ad58ae787e9c7c94dd7ceda3b587ec2c64604563e049b2a0e8baafae832addb"}, "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, "cachex": {:hex, :cachex, "3.2.0", "a596476c781b0646e6cb5cd9751af2e2974c3e0d5498a8cab71807618b74fe2f", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "aef93694067a43697ae0531727e097754a9e992a1e7946296f5969d6dd9ac986"}, @@ -110,4 +111,3 @@ "web_push_encryption": {:hex, :web_push_encryption, "0.2.3", "a0ceab85a805a30852f143d22d71c434046fbdbafbc7292e7887cec500826a80", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:poison, "~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm", "9315c8f37c108835cf3f8e9157d7a9b8f420a34f402d1b1620a31aed5b93ecdf"}, "websocket_client": {:git, "https://github.com/jeremyong/websocket_client.git", "9a6f65d05ebf2725d62fb19262b21f1805a59fbf", []}, } - diff --git a/priv/repo/migrations/20200314123607_config_remove_fetch_initial_posts.exs b/priv/repo/migrations/20200314123607_config_remove_fetch_initial_posts.exs new file mode 100644 index 000000000..392f531e8 --- /dev/null +++ b/priv/repo/migrations/20200314123607_config_remove_fetch_initial_posts.exs @@ -0,0 +1,10 @@ +defmodule Pleroma.Repo.Migrations.ConfigRemoveFetchInitialPosts do + use Ecto.Migration + + def change do + execute( + "delete from config where config.key = ':fetch_initial_posts' and config.group = ':pleroma';", + "" + ) + end +end diff --git a/priv/repo/migrations/20200315125756_delete_fetch_initial_posts_jobs.exs b/priv/repo/migrations/20200315125756_delete_fetch_initial_posts_jobs.exs new file mode 100644 index 000000000..5b8e3ab91 --- /dev/null +++ b/priv/repo/migrations/20200315125756_delete_fetch_initial_posts_jobs.exs @@ -0,0 +1,10 @@ +defmodule Pleroma.Repo.Migrations.DeleteFetchInitialPostsJobs do + use Ecto.Migration + + def change do + execute( + "delete from oban_jobs where worker = 'Pleroma.Workers.BackgroundWorker' and args->>'op' = 'fetch_initial_posts';", + "" + ) + end +end diff --git a/priv/static/adminfe/chunk-17a5.edcdbe30.css b/priv/static/adminfe/chunk-0d8f.650c8e81.css similarity index 100% rename from priv/static/adminfe/chunk-17a5.edcdbe30.css rename to priv/static/adminfe/chunk-0d8f.650c8e81.css diff --git a/priv/static/adminfe/chunk-2b8b.0f1ee211.css b/priv/static/adminfe/chunk-136a.3936457d.css similarity index 100% rename from priv/static/adminfe/chunk-2b8b.0f1ee211.css rename to priv/static/adminfe/chunk-136a.3936457d.css diff --git a/priv/static/adminfe/chunk-15fa.dc3643e6.css b/priv/static/adminfe/chunk-15fa.5a5f973d.css similarity index 100% rename from priv/static/adminfe/chunk-15fa.dc3643e6.css rename to priv/static/adminfe/chunk-15fa.5a5f973d.css diff --git a/priv/static/adminfe/chunk-46cf.6dd5bbb7.css b/priv/static/adminfe/chunk-46cf.a43e9415.css similarity index 100% rename from priv/static/adminfe/chunk-46cf.6dd5bbb7.css rename to priv/static/adminfe/chunk-46cf.a43e9415.css diff --git a/priv/static/adminfe/chunk-453a.bbab87da.css b/priv/static/adminfe/chunk-46ef.d45db7be.css similarity index 100% rename from priv/static/adminfe/chunk-453a.bbab87da.css rename to priv/static/adminfe/chunk-46ef.d45db7be.css diff --git a/priv/static/adminfe/chunk-293a.a8b5ee5b.css b/priv/static/adminfe/chunk-4e7d.7aace723.css similarity index 57% rename from priv/static/adminfe/chunk-293a.a8b5ee5b.css rename to priv/static/adminfe/chunk-4e7d.7aace723.css index 924633a80..9a35b64a0 100644 Binary files a/priv/static/adminfe/chunk-293a.a8b5ee5b.css and b/priv/static/adminfe/chunk-4e7d.7aace723.css differ diff --git a/priv/static/adminfe/chunk-4e46.ad5e9ff3.css b/priv/static/adminfe/chunk-4ffb.dd09fe2e.css similarity index 100% rename from priv/static/adminfe/chunk-4e46.ad5e9ff3.css rename to priv/static/adminfe/chunk-4ffb.dd09fe2e.css diff --git a/priv/static/adminfe/chunk-6dd6.85f319f7.css b/priv/static/adminfe/chunk-876c.90dffac4.css similarity index 100% rename from priv/static/adminfe/chunk-6dd6.85f319f7.css rename to priv/static/adminfe/chunk-876c.90dffac4.css diff --git a/priv/static/adminfe/chunk-03b0.49362218.css b/priv/static/adminfe/chunk-87b3.2affd602.css similarity index 57% rename from priv/static/adminfe/chunk-03b0.49362218.css rename to priv/static/adminfe/chunk-87b3.2affd602.css index e43c776aa..c4fa46d3e 100644 Binary files a/priv/static/adminfe/chunk-03b0.49362218.css and b/priv/static/adminfe/chunk-87b3.2affd602.css differ diff --git a/priv/static/adminfe/chunk-cf58.80435fa1.css b/priv/static/adminfe/chunk-cf57.4d39576f.css similarity index 75% rename from priv/static/adminfe/chunk-cf58.80435fa1.css rename to priv/static/adminfe/chunk-cf57.4d39576f.css index 8b0f21153..1190aca24 100644 Binary files a/priv/static/adminfe/chunk-cf58.80435fa1.css and b/priv/static/adminfe/chunk-cf57.4d39576f.css differ diff --git a/priv/static/adminfe/chunk-560d.802cfba1.css b/priv/static/adminfe/chunk-e5cf.cba3ae06.css similarity index 100% rename from priv/static/adminfe/chunk-560d.802cfba1.css rename to priv/static/adminfe/chunk-e5cf.cba3ae06.css diff --git a/priv/static/adminfe/index.html b/priv/static/adminfe/index.html index e2db408c3..717b0f32d 100644 --- a/priv/static/adminfe/index.html +++ b/priv/static/adminfe/index.html @@ -1 +1 @@ -Admin FE
    \ No newline at end of file +Admin FE
    \ No newline at end of file diff --git a/priv/static/adminfe/static/js/app.55df3157.js b/priv/static/adminfe/static/js/app.55df3157.js deleted file mode 100644 index d1a37af1c..000000000 Binary files a/priv/static/adminfe/static/js/app.55df3157.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/app.55df3157.js.map b/priv/static/adminfe/static/js/app.55df3157.js.map deleted file mode 100644 index 740783b80..000000000 Binary files a/priv/static/adminfe/static/js/app.55df3157.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/app.d2c3c6b3.js b/priv/static/adminfe/static/js/app.d2c3c6b3.js new file mode 100644 index 000000000..c527207dd Binary files /dev/null and b/priv/static/adminfe/static/js/app.d2c3c6b3.js differ diff --git a/priv/static/adminfe/static/js/app.d2c3c6b3.js.map b/priv/static/adminfe/static/js/app.d2c3c6b3.js.map new file mode 100644 index 000000000..7b2d4dc05 Binary files /dev/null and b/priv/static/adminfe/static/js/app.d2c3c6b3.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-03b0.7a203856.js b/priv/static/adminfe/static/js/chunk-03b0.7a203856.js deleted file mode 100644 index 43ca0e4e6..000000000 Binary files a/priv/static/adminfe/static/js/chunk-03b0.7a203856.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-03b0.7a203856.js.map b/priv/static/adminfe/static/js/chunk-03b0.7a203856.js.map deleted file mode 100644 index 697a106ac..000000000 Binary files a/priv/static/adminfe/static/js/chunk-03b0.7a203856.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-17a5.13b13757.js b/priv/static/adminfe/static/js/chunk-0d8f.a85e3222.js similarity index 99% rename from priv/static/adminfe/static/js/chunk-17a5.13b13757.js rename to priv/static/adminfe/static/js/chunk-0d8f.a85e3222.js index 80e7a8ac7..e3b0ae986 100644 Binary files a/priv/static/adminfe/static/js/chunk-17a5.13b13757.js and b/priv/static/adminfe/static/js/chunk-0d8f.a85e3222.js differ diff --git a/priv/static/adminfe/static/js/chunk-17a5.13b13757.js.map b/priv/static/adminfe/static/js/chunk-0d8f.a85e3222.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-17a5.13b13757.js.map rename to priv/static/adminfe/static/js/chunk-0d8f.a85e3222.js.map index 7da1a0077..cf75f3243 100644 Binary files a/priv/static/adminfe/static/js/chunk-17a5.13b13757.js.map and b/priv/static/adminfe/static/js/chunk-0d8f.a85e3222.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-2b8b.e3daf966.js b/priv/static/adminfe/static/js/chunk-136a.142aa42a.js similarity index 99% rename from priv/static/adminfe/static/js/chunk-2b8b.e3daf966.js rename to priv/static/adminfe/static/js/chunk-136a.142aa42a.js index 4b100db60..812089b5f 100644 Binary files a/priv/static/adminfe/static/js/chunk-2b8b.e3daf966.js and b/priv/static/adminfe/static/js/chunk-136a.142aa42a.js differ diff --git a/priv/static/adminfe/static/js/chunk-2b8b.e3daf966.js.map b/priv/static/adminfe/static/js/chunk-136a.142aa42a.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-2b8b.e3daf966.js.map rename to priv/static/adminfe/static/js/chunk-136a.142aa42a.js.map index a7282eaf4..f6b4c84aa 100644 Binary files a/priv/static/adminfe/static/js/chunk-2b8b.e3daf966.js.map and b/priv/static/adminfe/static/js/chunk-136a.142aa42a.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-15fa.15303f3a.js b/priv/static/adminfe/static/js/chunk-15fa.34070731.js similarity index 99% rename from priv/static/adminfe/static/js/chunk-15fa.15303f3a.js rename to priv/static/adminfe/static/js/chunk-15fa.34070731.js index 7d3e0c56e..937908d00 100644 Binary files a/priv/static/adminfe/static/js/chunk-15fa.15303f3a.js and b/priv/static/adminfe/static/js/chunk-15fa.34070731.js differ diff --git a/priv/static/adminfe/static/js/chunk-15fa.15303f3a.js.map b/priv/static/adminfe/static/js/chunk-15fa.34070731.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-15fa.15303f3a.js.map rename to priv/static/adminfe/static/js/chunk-15fa.34070731.js.map index f08d1dbf9..d3830be7c 100644 Binary files a/priv/static/adminfe/static/js/chunk-15fa.15303f3a.js.map and b/priv/static/adminfe/static/js/chunk-15fa.34070731.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-293a.a728de01.js b/priv/static/adminfe/static/js/chunk-293a.a728de01.js deleted file mode 100644 index c856e21eb..000000000 Binary files a/priv/static/adminfe/static/js/chunk-293a.a728de01.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-293a.a728de01.js.map b/priv/static/adminfe/static/js/chunk-293a.a728de01.js.map deleted file mode 100644 index 03f61abcb..000000000 Binary files a/priv/static/adminfe/static/js/chunk-293a.a728de01.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-46cf.104380a9.js b/priv/static/adminfe/static/js/chunk-46cf.3bd3567a.js similarity index 99% rename from priv/static/adminfe/static/js/chunk-46cf.104380a9.js rename to priv/static/adminfe/static/js/chunk-46cf.3bd3567a.js index 9e1e1520b..0795a46b6 100644 Binary files a/priv/static/adminfe/static/js/chunk-46cf.104380a9.js and b/priv/static/adminfe/static/js/chunk-46cf.3bd3567a.js differ diff --git a/priv/static/adminfe/static/js/chunk-46cf.104380a9.js.map b/priv/static/adminfe/static/js/chunk-46cf.3bd3567a.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-46cf.104380a9.js.map rename to priv/static/adminfe/static/js/chunk-46cf.3bd3567a.js.map index b9357ca8f..9993be4aa 100644 Binary files a/priv/static/adminfe/static/js/chunk-46cf.104380a9.js.map and b/priv/static/adminfe/static/js/chunk-46cf.3bd3567a.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-453a.2fcd7192.js b/priv/static/adminfe/static/js/chunk-46ef.215af110.js similarity index 98% rename from priv/static/adminfe/static/js/chunk-453a.2fcd7192.js rename to priv/static/adminfe/static/js/chunk-46ef.215af110.js index b0ee1b6b0..db11c7488 100644 Binary files a/priv/static/adminfe/static/js/chunk-453a.2fcd7192.js and b/priv/static/adminfe/static/js/chunk-46ef.215af110.js differ diff --git a/priv/static/adminfe/static/js/chunk-453a.2fcd7192.js.map b/priv/static/adminfe/static/js/chunk-46ef.215af110.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-453a.2fcd7192.js.map rename to priv/static/adminfe/static/js/chunk-46ef.215af110.js.map index b43d2f571..2da3dbec6 100644 Binary files a/priv/static/adminfe/static/js/chunk-453a.2fcd7192.js.map and b/priv/static/adminfe/static/js/chunk-46ef.215af110.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-4e7d.a40ad735.js b/priv/static/adminfe/static/js/chunk-4e7d.a40ad735.js new file mode 100644 index 000000000..ef2379ed9 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-4e7d.a40ad735.js differ diff --git a/priv/static/adminfe/static/js/chunk-4e7d.a40ad735.js.map b/priv/static/adminfe/static/js/chunk-4e7d.a40ad735.js.map new file mode 100644 index 000000000..b349f12eb Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-4e7d.a40ad735.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-4e46.d257e435.js b/priv/static/adminfe/static/js/chunk-4ffb.0e8f3772.js similarity index 85% rename from priv/static/adminfe/static/js/chunk-4e46.d257e435.js rename to priv/static/adminfe/static/js/chunk-4ffb.0e8f3772.js index 39c5dcc4e..5a7aa9f59 100644 Binary files a/priv/static/adminfe/static/js/chunk-4e46.d257e435.js and b/priv/static/adminfe/static/js/chunk-4ffb.0e8f3772.js differ diff --git a/priv/static/adminfe/static/js/chunk-4e46.d257e435.js.map b/priv/static/adminfe/static/js/chunk-4ffb.0e8f3772.js.map similarity index 98% rename from priv/static/adminfe/static/js/chunk-4e46.d257e435.js.map rename to priv/static/adminfe/static/js/chunk-4ffb.0e8f3772.js.map index 75d3554ac..7c020768c 100644 Binary files a/priv/static/adminfe/static/js/chunk-4e46.d257e435.js.map and b/priv/static/adminfe/static/js/chunk-4ffb.0e8f3772.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-6dd6.6c139a9c.js b/priv/static/adminfe/static/js/chunk-876c.e4ceccca.js similarity index 97% rename from priv/static/adminfe/static/js/chunk-6dd6.6c139a9c.js rename to priv/static/adminfe/static/js/chunk-876c.e4ceccca.js index 670016168..841ceb9dc 100644 Binary files a/priv/static/adminfe/static/js/chunk-6dd6.6c139a9c.js and b/priv/static/adminfe/static/js/chunk-876c.e4ceccca.js differ diff --git a/priv/static/adminfe/static/js/chunk-6dd6.6c139a9c.js.map b/priv/static/adminfe/static/js/chunk-876c.e4ceccca.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-6dd6.6c139a9c.js.map rename to priv/static/adminfe/static/js/chunk-876c.e4ceccca.js.map index b1438722c..88976a4fe 100644 Binary files a/priv/static/adminfe/static/js/chunk-6dd6.6c139a9c.js.map and b/priv/static/adminfe/static/js/chunk-876c.e4ceccca.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-87b3.4704cadf.js b/priv/static/adminfe/static/js/chunk-87b3.4704cadf.js new file mode 100644 index 000000000..9766fd7d2 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-87b3.4704cadf.js differ diff --git a/priv/static/adminfe/static/js/chunk-87b3.4704cadf.js.map b/priv/static/adminfe/static/js/chunk-87b3.4704cadf.js.map new file mode 100644 index 000000000..7472fcd92 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-87b3.4704cadf.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-cf57.42b96339.js b/priv/static/adminfe/static/js/chunk-cf57.42b96339.js new file mode 100644 index 000000000..81122f992 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-cf57.42b96339.js differ diff --git a/priv/static/adminfe/static/js/chunk-cf57.42b96339.js.map b/priv/static/adminfe/static/js/chunk-cf57.42b96339.js.map new file mode 100644 index 000000000..7471835b9 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-cf57.42b96339.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-cf58.e52693b3.js b/priv/static/adminfe/static/js/chunk-cf58.e52693b3.js deleted file mode 100644 index b74c20373..000000000 Binary files a/priv/static/adminfe/static/js/chunk-cf58.e52693b3.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-cf58.e52693b3.js.map b/priv/static/adminfe/static/js/chunk-cf58.e52693b3.js.map deleted file mode 100644 index 0f3f15299..000000000 Binary files a/priv/static/adminfe/static/js/chunk-cf58.e52693b3.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-560d.a8bb8682.js b/priv/static/adminfe/static/js/chunk-e5cf.501d7902.js similarity index 99% rename from priv/static/adminfe/static/js/chunk-560d.a8bb8682.js rename to priv/static/adminfe/static/js/chunk-e5cf.501d7902.js index 0b03305e9..fe5552943 100644 Binary files a/priv/static/adminfe/static/js/chunk-560d.a8bb8682.js and b/priv/static/adminfe/static/js/chunk-e5cf.501d7902.js differ diff --git a/priv/static/adminfe/static/js/chunk-560d.a8bb8682.js.map b/priv/static/adminfe/static/js/chunk-e5cf.501d7902.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-560d.a8bb8682.js.map rename to priv/static/adminfe/static/js/chunk-e5cf.501d7902.js.map index bfab1ade9..60676bfe7 100644 Binary files a/priv/static/adminfe/static/js/chunk-560d.a8bb8682.js.map and b/priv/static/adminfe/static/js/chunk-e5cf.501d7902.js.map differ diff --git a/priv/static/adminfe/static/js/runtime.ae93ea9f.js b/priv/static/adminfe/static/js/runtime.ae93ea9f.js deleted file mode 100644 index ebda2acde..000000000 Binary files a/priv/static/adminfe/static/js/runtime.ae93ea9f.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/runtime.fa19e5d1.js b/priv/static/adminfe/static/js/runtime.fa19e5d1.js new file mode 100644 index 000000000..b905e42e1 Binary files /dev/null and b/priv/static/adminfe/static/js/runtime.fa19e5d1.js differ diff --git a/priv/static/adminfe/static/js/runtime.ae93ea9f.js.map b/priv/static/adminfe/static/js/runtime.fa19e5d1.js.map similarity index 91% rename from priv/static/adminfe/static/js/runtime.ae93ea9f.js.map rename to priv/static/adminfe/static/js/runtime.fa19e5d1.js.map index 6392c981a..6a2565556 100644 Binary files a/priv/static/adminfe/static/js/runtime.ae93ea9f.js.map and b/priv/static/adminfe/static/js/runtime.fa19e5d1.js.map differ diff --git a/priv/static/static/static-fe.css b/priv/static/static/static-fe.css new file mode 100644 index 000000000..19c56387b Binary files /dev/null and b/priv/static/static/static-fe.css differ diff --git a/test/activity/ir/topics_test.exs b/test/activity/ir/topics_test.exs index e75f83586..44aec1e19 100644 --- a/test/activity/ir/topics_test.exs +++ b/test/activity/ir/topics_test.exs @@ -59,8 +59,8 @@ test "non-local action does not produce public:local topic", %{activity: activit describe "public visibility create events" do setup do activity = %Activity{ - object: %Object{data: %{"type" => "Create", "attachment" => []}}, - data: %{"to" => [Pleroma.Constants.as_public()]} + object: %Object{data: %{"attachment" => []}}, + data: %{"type" => "Create", "to" => [Pleroma.Constants.as_public()]} } {:ok, activity: activity} @@ -98,8 +98,8 @@ test "only converts strinngs to hash tags", %{ describe "public visibility create events with attachments" do setup do activity = %Activity{ - object: %Object{data: %{"type" => "Create", "attachment" => ["foo"]}}, - data: %{"to" => [Pleroma.Constants.as_public()]} + object: %Object{data: %{"attachment" => ["foo"]}}, + data: %{"type" => "Create", "to" => [Pleroma.Constants.as_public()]} } {:ok, activity: activity} 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 @@ test "config/0" 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 @@ test "transfer config values for 1 group and some keys" 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/earmark_renderer_test.ex b/test/earmark_renderer_test.ex new file mode 100644 index 000000000..220d97d16 --- /dev/null +++ b/test/earmark_renderer_test.ex @@ -0,0 +1,79 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only +defmodule Pleroma.EarmarkRendererTest do + use ExUnit.Case + + test "Paragraph" do + code = ~s[Hello\n\nWorld!] + result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) + assert result == "

    Hello

    World!

    " + end + + test "raw HTML" do + code = ~s[OwO] + result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) + assert result == "

    #{code}

    " + end + + test "rulers" do + code = ~s[before\n\n-----\n\nafter] + result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) + assert result == "

    before


    after

    " + end + + test "headings" do + code = ~s[# h1\n## h2\n### h3\n] + result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) + assert result == ~s[

    h1

    h2

    h3

    ] + end + + test "blockquote" do + code = ~s[> whoms't are you quoting?] + result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) + assert result == "

    whoms’t are you quoting?

    " + end + + test "code" do + code = ~s[`mix`] + result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) + assert result == ~s[

    mix

    ] + + code = ~s[``mix``] + result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) + assert result == ~s[

    mix

    ] + + code = ~s[```\nputs "Hello World"\n```] + result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) + assert result == ~s[
    puts "Hello World"
    ] + end + + test "lists" do + code = ~s[- one\n- two\n- three\n- four] + result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) + assert result == "
    • one
    • two
    • three
    • four
    " + + code = ~s[1. one\n2. two\n3. three\n4. four\n] + result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) + assert result == "
    1. one
    2. two
    3. three
    4. four
    " + end + + test "delegated renderers" do + code = ~s[a
    b] + result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) + assert result == "

    #{code}

    " + + code = ~s[*aaaa~*] + result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) + assert result == ~s[

    aaaa~

    ] + + code = ~s[**aaaa~**] + result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) + assert result == ~s[

    aaaa~

    ] + + # strikethrought + code = ~s[aaaa~] + result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) + assert result == ~s[

    aaaa~

    ] + end +end 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/plugs/cache_control_test.exs b/test/plugs/cache_control_test.exs index 005912ffb..6b567e81d 100644 --- a/test/plugs/cache_control_test.exs +++ b/test/plugs/cache_control_test.exs @@ -9,7 +9,7 @@ defmodule Pleroma.Web.CacheControlTest do test "Verify Cache-Control header on static assets", %{conn: conn} do conn = get(conn, "/index.html") - assert Conn.get_resp_header(conn, "cache-control") == ["public max-age=86400 must-revalidate"] + assert Conn.get_resp_header(conn, "cache-control") == ["public, no-cache"] end test "Verify Cache-Control header on the API", %{conn: conn} do diff --git a/test/plugs/rate_limiter_test.exs b/test/plugs/rate_limiter_test.exs index 8023271e4..81e2009c8 100644 --- a/test/plugs/rate_limiter_test.exs +++ b/test/plugs/rate_limiter_test.exs @@ -3,8 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Plugs.RateLimiterTest do - use ExUnit.Case, async: true - use Plug.Test + use Pleroma.Web.ConnCase alias Pleroma.Config alias Pleroma.Plugs.RateLimiter @@ -36,63 +35,44 @@ test "config is required for plug to work" do |> RateLimiter.init() |> RateLimiter.action_settings() end + end - test "it is disabled for localhost" do - Config.put([:rate_limit, @limiter_name], {1, 1}) - Config.put([Pleroma.Web.Endpoint, :http, :ip], {127, 0, 0, 1}) - Config.put([Pleroma.Plugs.RemoteIp, :enabled], false) + test "it is disabled if it remote ip plug is enabled but no remote ip is found" do + Config.put([Pleroma.Web.Endpoint, :http, :ip], {127, 0, 0, 1}) + assert RateLimiter.disabled?(Plug.Conn.assign(build_conn(), :remote_ip_found, false)) + end - assert RateLimiter.disabled?() == true - end + test "it restricts based on config values" do + limiter_name = :test_plug_opts + scale = 80 + limit = 5 - test "it is disabled for socket" do - Config.put([:rate_limit, @limiter_name], {1, 1}) - Config.put([Pleroma.Web.Endpoint, :http, :ip], {:local, "/path/to/pleroma.sock"}) - Config.put([Pleroma.Plugs.RemoteIp, :enabled], false) + Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) + Config.put([:rate_limit, limiter_name], {scale, limit}) - assert RateLimiter.disabled?() == true - end - - test "it is enabled for socket when remote ip is enabled" do - Config.put([:rate_limit, @limiter_name], {1, 1}) - Config.put([Pleroma.Web.Endpoint, :http, :ip], {:local, "/path/to/pleroma.sock"}) - Config.put([Pleroma.Plugs.RemoteIp, :enabled], true) - - assert RateLimiter.disabled?() == false - end - - test "it restricts based on config values" do - limiter_name = :test_plug_opts - scale = 80 - limit = 5 - - Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) - Config.put([:rate_limit, limiter_name], {scale, limit}) - - plug_opts = RateLimiter.init(name: limiter_name) - conn = conn(:get, "/") - - for i <- 1..5 do - conn = RateLimiter.call(conn, plug_opts) - assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts) - Process.sleep(10) - end + plug_opts = RateLimiter.init(name: limiter_name) + conn = conn(:get, "/") + for i <- 1..5 do conn = RateLimiter.call(conn, plug_opts) - assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) - assert conn.halted - - Process.sleep(50) - - conn = conn(:get, "/") - - conn = RateLimiter.call(conn, plug_opts) - assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts) - - refute conn.status == Plug.Conn.Status.code(:too_many_requests) - refute conn.resp_body - refute conn.halted + assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts) + Process.sleep(10) end + + conn = RateLimiter.call(conn, plug_opts) + assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) + assert conn.halted + + Process.sleep(50) + + conn = conn(:get, "/") + + conn = RateLimiter.call(conn, plug_opts) + assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts) + + refute conn.status == Plug.Conn.Status.code(:too_many_requests) + refute conn.resp_body + refute conn.halted end describe "options" do diff --git a/test/reverse_proxy_test.exs b/test/reverse_proxy_test.exs index 18d70862c..87c6aca4e 100644 --- a/test/reverse_proxy_test.exs +++ b/test/reverse_proxy_test.exs @@ -275,17 +275,6 @@ test "returns 400 on non GET, HEAD requests", %{conn: conn} do end describe "cache resp headers" do - test "returns headers", %{conn: conn} do - ClientMock - |> expect(:request, fn :get, "/cache/" <> ttl, _, _, _ -> - {:ok, 200, [{"cache-control", "public, max-age=" <> ttl}], %{}} - end) - |> expect(:stream_body, fn _ -> :done end) - - conn = ReverseProxy.call(conn, "/cache/10") - assert {"cache-control", "public, max-age=10"} in conn.resp_headers - end - test "add cache-control", %{conn: conn} do ClientMock |> expect(:request, fn :get, "/cache", _, _, _ -> @@ -294,7 +283,7 @@ test "add cache-control", %{conn: conn} do |> expect(:stream_body, fn _ -> :done end) conn = ReverseProxy.call(conn, "/cache") - assert {"cache-control", "public"} in conn.resp_headers + assert {"cache-control", "public, max-age=1209600"} in conn.resp_headers end end diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index d46887865..e72638814 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -1277,6 +1277,10 @@ def get("http://example.com/rel_me/error", _, _, _) 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)}, #{ @@ -1289,6 +1293,10 @@ def get(url, query, body, headers) 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 @@ test "relay is followed" 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 @@ test "it sends a welcome message if it is set" 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 @@ test "it requires an email, name, nickname and password, bio is optional" 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 @@ test "it clears `unreachable` federation status of the sender", %{conn: conn} 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/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs index e5ab54dd4..e913a5148 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/web/activity_pub/utils_test.exs @@ -177,71 +177,6 @@ test "does not adress actor's follower address if the activity is not public", % end end - describe "fetch_ordered_collection" do - import Tesla.Mock - - test "fetches the first OrderedCollectionPage when an OrderedCollection is encountered" do - mock(fn - %{method: :get, url: "http://mastodon.com/outbox"} -> - json(%{"type" => "OrderedCollection", "first" => "http://mastodon.com/outbox?page=true"}) - - %{method: :get, url: "http://mastodon.com/outbox?page=true"} -> - json(%{"type" => "OrderedCollectionPage", "orderedItems" => ["ok"]}) - end) - - assert Utils.fetch_ordered_collection("http://mastodon.com/outbox", 1) == ["ok"] - end - - test "fetches several pages in the right order one after another, but only the specified amount" do - mock(fn - %{method: :get, url: "http://example.com/outbox"} -> - json(%{ - "type" => "OrderedCollectionPage", - "orderedItems" => [0], - "next" => "http://example.com/outbox?page=1" - }) - - %{method: :get, url: "http://example.com/outbox?page=1"} -> - json(%{ - "type" => "OrderedCollectionPage", - "orderedItems" => [1], - "next" => "http://example.com/outbox?page=2" - }) - - %{method: :get, url: "http://example.com/outbox?page=2"} -> - json(%{"type" => "OrderedCollectionPage", "orderedItems" => [2]}) - end) - - assert Utils.fetch_ordered_collection("http://example.com/outbox", 0) == [0] - assert Utils.fetch_ordered_collection("http://example.com/outbox", 1) == [0, 1] - end - - test "returns an error if the url doesn't have an OrderedCollection/Page" do - mock(fn - %{method: :get, url: "http://example.com/not-an-outbox"} -> - json(%{"type" => "NotAnOutbox"}) - end) - - assert {:error, _} = Utils.fetch_ordered_collection("http://example.com/not-an-outbox", 1) - end - - test "returns the what was collected if there are less pages than specified" do - mock(fn - %{method: :get, url: "http://example.com/outbox"} -> - json(%{ - "type" => "OrderedCollectionPage", - "orderedItems" => [0], - "next" => "http://example.com/outbox?page=1" - }) - - %{method: :get, url: "http://example.com/outbox?page=1"} -> - json(%{"type" => "OrderedCollectionPage", "orderedItems" => [1]}) - end) - - assert Utils.fetch_ordered_collection("http://example.com/outbox", 5) == [0, 1] - end - end - test "make_json_ld_header/0" do assert Utils.make_json_ld_header() == %{ "@context" => [ 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 @@ test "it returns error when status is empty and no attachments" 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/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs index b380d10d8..45fc94522 100644 --- a/test/web/common_api/common_api_utils_test.exs +++ b/test/web/common_api/common_api_utils_test.exs @@ -89,8 +89,8 @@ test "works for bare text/html" do assert output == expected - text = "

    hello world!

    \n\n

    second paragraph

    " - expected = "

    hello world!

    \n\n

    second paragraph

    " + text = "

    hello world!


    \n

    second paragraph

    " + expected = "

    hello world!


    \n

    second paragraph

    " {output, [], []} = Utils.format_input(text, "text/html") @@ -99,14 +99,14 @@ test "works for bare text/html" do test "works for bare text/markdown" do text = "**hello world**" - expected = "

    hello world

    \n" + expected = "

    hello world

    " {output, [], []} = Utils.format_input(text, "text/markdown") assert output == expected text = "**hello world**\n\n*another paragraph*" - expected = "

    hello world

    \n

    another paragraph

    \n" + expected = "

    hello world

    another paragraph

    " {output, [], []} = Utils.format_input(text, "text/markdown") @@ -118,7 +118,7 @@ test "works for bare text/markdown" do by someone """ - expected = "

    cool quote

    \n
    \n

    by someone

    \n" + expected = "

    cool quote

    by someone

    " {output, [], []} = Utils.format_input(text, "text/markdown") @@ -134,7 +134,7 @@ test "works for bare text/bbcode" do assert output == expected text = "[b]hello world![/b]\n\nsecond paragraph!" - expected = "hello world!
    \n
    \nsecond paragraph!" + expected = "hello world!

    second paragraph!" {output, [], []} = Utils.format_input(text, "text/bbcode") @@ -143,7 +143,7 @@ test "works for bare text/bbcode" do text = "[b]hello world![/b]\n\nsecond paragraph!" expected = - "hello world!
    \n
    \n<strong>second paragraph!</strong>" + "hello world!

    <strong>second paragraph!</strong>" {output, [], []} = Utils.format_input(text, "text/bbcode") @@ -156,16 +156,14 @@ test "works for text/markdown with mentions" do text = "**hello world**\n\n*another @user__test and @user__test google.com paragraph*" - expected = - ~s(

    hello world

    \n

    another @user__test and @user__test google.com paragraph

    \n) - {output, _, _} = Utils.format_input(text, "text/markdown") - assert output == expected + assert output == + ~s(

    hello world

    another @user__test and @user__test google.com paragraph

    ) end end diff --git a/test/web/mastodon_api/controllers/account_controller_test.exs b/test/web/mastodon_api/controllers/account_controller_test.exs index 57d0f4416..7efccd9c4 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 @@ test "blocking / unblocking a user" 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 @@ test "returns bad_request if missing required params", %{ 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 @@ test "returns bad_request if missing required params", %{ 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") @@ -706,10 +756,6 @@ test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_ end describe "create account by app / rate limit" do - clear_config([Pleroma.Plugs.RemoteIp, :enabled]) do - Pleroma.Config.put([Pleroma.Plugs.RemoteIp, :enabled], true) - end - clear_config([:rate_limit, :app_account_creation]) do Pleroma.Config.put([:rate_limit, :app_account_creation], {10_000, 2}) end diff --git a/test/web/static_fe/static_fe_controller_test.exs b/test/web/static_fe/static_fe_controller_test.exs index 2ce8f9fa3..2c999295a 100644 --- a/test/web/static_fe/static_fe_controller_test.exs +++ b/test/web/static_fe/static_fe_controller_test.exs @@ -110,6 +110,19 @@ test "single notice page", %{conn: conn} do assert html =~ "testing a thing!" end + test "filters HTML tags", %{conn: conn} do + user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{"status" => ""}) + + conn = + conn + |> put_req_header("accept", "text/html") + |> get("/notice/#{activity.id}") + + html = html_response(conn, 200) + assert html =~ ~s[<script>alert('xss')</script>] + end + test "shows the whole thread", %{conn: conn} do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{"status" => "space: the final frontier"})