build:
stage: build
+ only:
+ changes:
+ - "**/*.ex"
+ - "**/*.exs"
+ - "mix.lock"
script:
- mix compile --force
spec-build:
stage: test
+ only:
+ changes:
+ - "lib/pleroma/web/api_spec/**/*.ex"
+ - "lib/pleroma/web/api_spec.ex"
artifacts:
paths:
- spec.json
unit-testing:
stage: test
+ only:
+ changes:
+ - "**/*.ex"
+ - "**/*.exs"
+ - "mix.lock"
retry: 2
cache: &testing_cache_policy
<<: *global_cache_policy
unit-testing-rum:
stage: test
+ only:
+ changes:
+ - "**/*.ex"
+ - "**/*.exs"
+ - "mix.lock"
retry: 2
cache: *testing_cache_policy
services:
lint:
stage: test
+ only:
+ changes:
+ - "**/*.ex"
+ - "**/*.exs"
+ - "mix.lock"
cache: *testing_cache_policy
script:
- mix format --check-formatted
analysis:
stage: test
+ only:
+ changes:
+ - "**/*.ex"
+ - "**/*.exs"
+ - "mix.lock"
cache: *testing_cache_policy
script:
- mix credo --strict --only=warnings,todo,fixme,consistency,readability
### Changed
+- **Breaking:** Configuration: `:chat, enabled` moved to `:shout, enabled` and `:instance, chat_limit` moved to `:shout, limit`
+- Support for Erlang/OTP 24
- The `application` metadata returned with statuses is no longer hardcoded. Apps that want to display these details will now have valid data for new posts after this change.
- HTTPSecurityPlug now sends a response header to opt out of Google's FLoC (Federated Learning of Cohorts) targeted advertising.
- Email address is now returned if requesting user is the owner of the user account so it can be exposed in client and FE user settings UIs.
### Fixed
- Don't crash so hard when email settings are invalid.
- Checking activated Upload Filters for required commands.
+- Mix task `pleroma.database prune_objects`
+
+### Removed
+- **Breaking**: Remove deprecated `/api/qvitter/statuses/notifications/read` (replaced by `/api/v1/pleroma/notifications/read`)
## Unreleased (Patch)
- Latest Git revision: <https://docs-develop.pleroma.social>
## Community Channels
-* IRC: **#pleroma** and **#pleroma-dev** on freenode, webchat is available at <https://irc.pleroma.social>
-* Matrix: <https://matrix.to/#/#freenode_#pleroma:matrix.org> and <https://matrix.to/#/#freenode_#pleroma-dev:matrix.org>
+* IRC: **#pleroma** and **#pleroma-dev** on libera.chat, webchat is available at <https://irc.pleroma.social>
+* Matrix: [#pleroma:libera.chat](https://matrix.to/#/#pleroma:libera.chat) and [#pleroma-dev:libera.chat](https://matrix.to/#/#pleroma-dev:libera.chat)
"url" => [
%{
"href" =>
- "#{Pleroma.Web.base_url()}/media/b1b873552422a07bf53af01f3c231c841db4dfc42c35efde681abaf0f2a4eab7.jpg",
+ "#{Pleroma.Web.Endpoint.url()}/media/b1b873552422a07bf53af01f3c231c841db4dfc42c35efde681abaf0f2a4eab7.jpg",
"mediaType" => "image/jpeg",
"type" => "Link"
}
instance_thumbnail: "/instance/thumbnail.jpeg",
limit: 5_000,
description_limit: 5_000,
- chat_limit: 5_000,
remote_limit: 100_000,
upload_limit: 16_000_000,
avatar_upload_limit: 2_000_000,
image_quality: 85,
min_content_length: 100 * 1024
-config :pleroma, :chat, enabled: true
+config :pleroma, :shout,
+ enabled: true,
+ limit: 5_000
config :phoenix, :format_encoders, json: Jason
5_000
]
},
- %{
- key: :chat_limit,
- type: :integer,
- description: "Character limit of the instance chat messages",
- suggestions: [
- 5_000
- ]
- },
%{
key: :remote_limit,
type: :integer,
%{
key: :allow_relay,
type: :boolean,
- description: "Enable Pleroma's Relay, which makes it possible to follow a whole instance"
+ description:
+ "Permits remote instances to subscribe to all public posts of your instance. (Important!) This may increase the visibility of your instance."
},
%{
key: :public,
alwaysShowSubjectInput: true,
background: "/static/aurora_borealis.jpg",
collapseMessageWithSubject: false,
- disableChat: false,
greentext: false,
hideFilteredStatuses: false,
hideMutedPosts: false,
description:
"When a message has a subject (aka Content Warning), collapse it by default"
},
- %{
- key: :disableChat,
- label: "PleromaFE Chat",
- type: :boolean,
- description: "Disables PleromaFE Chat component"
- },
%{
key: :greentext,
label: "Greentext",
},
%{
group: :pleroma,
- key: :chat,
+ key: :shout,
type: :group,
- description: "Pleroma chat settings",
+ description: "Pleroma shout settings",
children: [
%{
key: :enabled,
- type: :boolean
+ type: :boolean,
+ description: "Enables the backend Shoutbox chat feature."
+ },
+ %{
+ key: :limit,
+ type: :integer,
+ description: "Shout message character limit.",
+ suggestions: [
+ 5_000
+ ]
}
]
},
To add configuration to your config file, you can copy it from the base config. The latest version of it can be viewed [here](https://git.pleroma.social/pleroma/pleroma/blob/develop/config/config.exs). You can also use this file if you don't know how an option is supposed to be formatted.
-## :chat
+## :shout
-* `enabled` - Enables the backend chat. Defaults to `true`.
+* `enabled` - Enables the backend Shoutbox chat feature. Defaults to `true`.
+* `limit` - Shout character limit. Defaults to `5_000`
## :instance
* `name`: The instance’s name.
* `description`: The instance’s description, can be seen in nodeinfo and ``/api/v1/instance``.
* `limit`: Posts character limit (CW/Subject included in the counter).
* `description_limit`: The character limit for image descriptions.
-* `chat_limit`: Character limit of the instance chat messages.
* `remote_limit`: Hard character limit beyond which remote posts will be dropped.
* `upload_limit`: File size limit of uploads (except for avatar, background, banner).
* `avatar_upload_limit`: File size limit of user’s profile avatars.
* `federating`: Enable federation with other instances.
* `federation_incoming_replies_max_depth`: Max. depth of reply-to activities fetching on incoming federation, to prevent out-of-memory situations while fetching very long threads. If set to `nil`, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes.
* `federation_reachability_timeout_days`: Timeout (in days) of each external federation target being unreachable prior to pausing federating to it.
-* `allow_relay`: Enable Pleroma’s Relay, which makes it possible to follow a whole instance.
+* `allow_relay`: Permits remote instances to subscribe to all public posts of your instance. This may increase the visibility of your instance.
* `public`: Makes the client API in authenticated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. Note that there is a dependent setting restricting or allowing unauthenticated access to specific resources, see `restrict_unauthenticated` for more details.
* `quarantined_instances`: List of ActivityPub instances where private (DMs, followers-only) activities will not be send.
* `allowed_post_formats`: MIME-type list of formats allowed to be posted (transformed into HTML).
```elixir
defmodule Pleroma.Web.ActivityPub.MRF.RewritePolicy do
@moduledoc "MRF policy which rewrites all Notes to have 'new message content'."
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
# Catch messages which contain Note objects with actual data to filter.
# Capture the object as `object`, the message content as `content` and the
* Note: Behaves exactly the same as `POST /api/v1/upload`.
Can only accept images - any attempt to upload non-image files will be met with `HTTP 415 Unsupported Media Type`.
-## `/api/v1/pleroma/notification_settings`
+## `/api/pleroma/notification_settings`
### Updates user notification settings
* Method `PUT`
* Authentication: required
## Questions
-Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**.
+Questions about the installation or didn’t it work as it should be, ask in [#pleroma:libera.chat](https://matrix.to/#/#pleroma:libera.chat) via Matrix or **#pleroma** on **libera.chat** via IRC.
## Questions
-Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**.
+Questions about the installation or didn’t it work as it should be, ask in [#pleroma:libera.chat](https://matrix.to/#/#pleroma:libera.chat) via Matrix or **#pleroma** on **libera.chat** via IRC.
## Questions
-Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**.
+Questions about the installation or didn’t it work as it should be, ask in [#pleroma:libera.chat](https://matrix.to/#/#pleroma:libera.chat) via Matrix or **#pleroma** on **libera.chat** via IRC.
インストールについて質問がある、もしくは、うまくいかないときは、以下のところで質問できます。
-* [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org)
-* **Freenode** の **#pleroma** IRCチャンネル
+* [#pleroma:libera.chat](https://matrix.to/#/#pleroma:libera.chat)
+* **libera.chat** の **#pleroma** IRCチャンネル
## Questions
-Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**.
+Questions about the installation or didn’t it work as it should be, ask in [#pleroma:libera.chat](https://matrix.to/#/#pleroma:libera.chat) via Matrix or **#pleroma** on **libera.chat** via IRC.
## Questions
-Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**.
+Questions about the installation or didn’t it work as it should be, ask in [#pleroma:libera.chat](https://matrix.to/#/#pleroma:libera.chat) via Matrix or **#pleroma** on **libera.chat** via IRC.
Restart nginx with `# /etc/rc.d/nginx restart` and you should be up and running.
-If you need further help, contact niaa on freenode.
-
Make sure your time is in sync, or other instances will receive your posts with
incorrect timestamps. You should have ntpd running.
## Questions
-Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**.
+Questions about the installation or didn’t it work as it should be, ask in [#pleroma:libera.chat](https://matrix.to/#/#pleroma:libera.chat) via Matrix or **#pleroma** on **libera.chat** via IRC.
## Questions
-Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**.
+Questions about the installation or didn’t it work as it should be, ask in [#pleroma:libera.chat](https://matrix.to/#/#pleroma:libera.chat) via Matrix or **#pleroma** on **libera.chat** via IRC.
Tästä eteenpäin oletuksena on, että domain "esimerkki.com" osoittaa
serverin IP-osoitteeseen.
-Jos asennuksen kanssa on ongelmia, IRC-kanava #pleroma Freenodessa tai
-Matrix-kanava #freenode_#pleroma:matrix.org ovat hyviä paikkoja löytää apua
+Jos asennuksen kanssa on ongelmia, IRC-kanava #pleroma Libera.chat tai
+Matrix-kanava #pleroma:libera.chat ovat hyviä paikkoja löytää apua
(englanniksi), `/msg eal kukkuu` jos haluat välttämättä puhua härmää.
Asenna tarvittava ohjelmisto:
If everything worked, you should see Pleroma-FE when visiting your domain. If that didn't happen, try reviewing the installation steps, starting Pleroma in the foreground and seeing if there are any errrors.
-Still doesn't work? Feel free to contact us on [#pleroma on freenode](https://irc.pleroma.social) or via matrix at <https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org>, you can also [file an issue on our Gitlab](https://git.pleroma.social/pleroma/pleroma-support/issues/new)
+Questions about the installation or didn’t it work as it should be, ask in [#pleroma:libera.chat](https://matrix.to/#/#pleroma:libera.chat) via Matrix or **#pleroma** on **libera.chat** via IRC, you can also [file an issue on our Gitlab](https://git.pleroma.social/pleroma/pleroma-support/issues/new).
## Post installation
## Questions
-Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**.
+Questions about the installation or didn’t it work as it should be, ask in [#pleroma:libera.chat](https://matrix.to/#/#pleroma:libera.chat) via Matrix or **#pleroma** on **libera.chat** via IRC, you can also [file an issue on our Gitlab](https://git.pleroma.social/pleroma/pleroma-support/issues/new).
)
|> Repo.delete_all(timeout: :infinity)
+ prune_hashtags_query = """
+ DELETE FROM hashtags AS ht
+ WHERE NOT EXISTS (
+ SELECT 1 FROM hashtags_objects hto
+ WHERE ht.id = hto.hashtag_id)
+ """
+
+ Repo.query(prune_hashtags_query)
+
if Keyword.get(options, :vacuum) do
Maintenance.vacuum("full")
end
if Process.whereis(Pleroma.Web.Endpoint) do
case Config.get([:http, :user_agent], :default) do
:default ->
- info = "#{Pleroma.Web.base_url()} <#{Config.get([:instance, :email], "")}>"
+ info = "#{Pleroma.Web.Endpoint.url()} <#{Config.get([:instance, :email], "")}>"
named_version() <> "; " <> info
custom ->
] ++
task_children(@mix_env) ++
dont_run_in_test(@mix_env) ++
- chat_child(chat_enabled?()) ++
+ shout_child(shout_enabled?()) ++
[Pleroma.Gopher.Server]
# See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
type: :worker
}
- defp chat_enabled?, do: Config.get([:chat, :enabled])
+ defp shout_enabled?, do: Config.get([:shout, :enabled])
defp dont_run_in_test(env) when env in [:test, :benchmark], do: []
]
end
- defp chat_child(true) do
+ defp shout_child(true) do
[
- Pleroma.Web.ChatChannel.ChatChannelState,
+ Pleroma.Web.ShoutChannel.ShoutChannelState,
{Phoenix.PubSub, [name: Pleroma.PubSub, adapter: Phoenix.PubSub.PG2]}
]
end
- defp chat_child(_), do: []
+ defp shout_child(_), do: []
defp task_children(:test) do
[
:ok <- check_gun_pool_options(),
:ok <- check_activity_expiration_config(),
:ok <- check_remote_ip_plug_name(),
- :ok <- check_uploders_s3_public_endpoint() do
+ :ok <- check_uploders_s3_public_endpoint(),
+ :ok <- check_old_chat_shoutbox() do
:ok
else
_ ->
:ok
end
end
+
+ @spec check_old_chat_shoutbox() :: :ok | nil
+ def check_old_chat_shoutbox do
+ instance_config = Pleroma.Config.get([:instance])
+ chat_config = Pleroma.Config.get([:chat]) || []
+
+ use_old_config =
+ Keyword.has_key?(instance_config, :chat_limit) or
+ Keyword.has_key?(chat_config, :enabled)
+
+ if use_old_config do
+ Logger.error("""
+ !!!DEPRECATION WARNING!!!
+ Your config is using the old namespace for the Shoutbox configuration. You need to convert to the new namespace. e.g.,
+ \n* `config :pleroma, :chat, enabled` and `config :pleroma, :instance, chat_limit` are now equal to:
+ \n* `config :pleroma, :shout, enabled` and `config :pleroma, :shout, limit`
+ """)
+
+ :error
+ else
+ :ok
+ end
+ end
end
defp reboot_time_keys,
do: [
{:pleroma, :hackney_pools},
- {:pleroma, :chat},
+ {:pleroma, :shout},
{:pleroma, Oban},
{:pleroma, :rate_limit},
{:pleroma, :markup},
do:
~w(index.html robots.txt static static-fe finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc embed.js embed.css)
)
-
- def as_local_public, do: Pleroma.Web.base_url() <> "/#Public"
end
cast([object])
end
+ def cast(object) when is_map(object) do
+ case ObjectID.cast(object) do
+ {:ok, data} -> {:ok, [data]}
+ _ -> :error
+ end
+ end
+
def cast(data) when is_list(data) do
- data
- |> Enum.reduce_while({:ok, []}, fn element, {:ok, list} ->
- case ObjectID.cast(element) do
- {:ok, id} ->
- {:cont, {:ok, [id | list]}}
-
- _ ->
- {:halt, :error}
- end
- end)
+ data =
+ data
+ |> Enum.reduce_while([], fn element, list ->
+ case ObjectID.cast(element) do
+ {:ok, id} ->
+ {:cont, [id | list]}
+
+ _ ->
+ {:cont, list}
+ end
+ end)
+ |> Enum.sort()
+ |> Enum.uniq()
+
+ {:ok, data}
end
- def cast(_) do
- :error
+ def cast(data) do
+ {:error, data}
end
def dump(data) do
#{comment_html}
#{statuses_html}
<p>
- <a href="#{Pleroma.Web.base_url()}/pleroma/admin/#/reports/index">View Reports in AdminFE</a>
+ <a href="#{Pleroma.Web.Endpoint.url()}/pleroma/admin/#/reports/index">View Reports in AdminFE</a>
"""
new()
html_body = """
<p>New account for review: <a href="#{account.ap_id}">@#{account.nickname}</a></p>
<blockquote>#{HTML.strip_tags(account.registration_reason)}</blockquote>
- <a href="#{Pleroma.Web.base_url()}/pleroma/admin/#/users/#{account.id}/">Visit AdminFE</a>
+ <a href="#{Pleroma.Web.Endpoint.url()}/pleroma/admin/#/users/#{account.id}/">Visit AdminFE</a>
"""
new()
defmodule Pleroma.Emails.UserEmail do
@moduledoc "User emails"
- use Phoenix.Swoosh, view: Pleroma.Web.EmailView, layout: {Pleroma.Web.LayoutView, :email}
-
alias Pleroma.Config
alias Pleroma.User
alias Pleroma.Web.Endpoint
alias Pleroma.Web.Router
+ import Swoosh.Email
+ import Phoenix.Swoosh, except: [render_body: 3]
import Pleroma.Config.Helpers, only: [instance_name: 0, sender: 0]
+ def render_body(email, template, assigns \\ %{}) do
+ email
+ |> put_new_layout({Pleroma.Web.LayoutView, :email})
+ |> put_new_view(Pleroma.Web.EmailView)
+ |> Phoenix.Swoosh.render_body(template, assigns)
+ end
+
defp recipient(email, nil), do: email
defp recipient(email, name), do: {name, email}
defp recipient(%User{} = user), do: recipient(user.email, user.name)
defmodule Pleroma.Emoji.Formatter do
alias Pleroma.Emoji
alias Pleroma.HTML
- alias Pleroma.Web
+ alias Pleroma.Web.Endpoint
alias Pleroma.Web.MediaProxy
def emojify(text) do
Emoji.get_all()
|> Enum.filter(fn {emoji, %Emoji{}} -> String.contains?(text, ":#{emoji}:") end)
|> Enum.reduce(%{}, fn {name, %Emoji{file: file}}, acc ->
- Map.put(acc, name, to_string(URI.merge(Web.base_url(), file)))
+ Map.put(acc, name, to_string(URI.merge(Endpoint.url(), file)))
end)
end
def hashtag_handler("#" <> tag = tag_text, _buffer, _opts, acc) do
tag = String.downcase(tag)
- url = "#{Pleroma.Web.base_url()}/tag/#{tag}"
+ url = "#{Pleroma.Web.Endpoint.url()}/tag/#{tag}"
link =
Phoenix.HTML.Tag.content_tag(:a, tag_text,
defmodule Pleroma.HTTP.WebPush do
@moduledoc false
- def post(url, payload, headers) do
+ def post(url, payload, headers, options \\ []) do
list_headers = Map.to_list(headers)
- Pleroma.HTTP.post(url, payload, list_headers)
+ Pleroma.HTTP.post(url, payload, list_headers, options)
end
end
_ -> map
end
end
+
+ def safe_put_in(data, keys, value) when is_map(data) and is_list(keys) do
+ Kernel.put_in(data, keys, value)
+ rescue
+ _ -> data
+ end
end
end
def local?(%Object{data: %{"id" => id}}) do
- String.starts_with?(id, Pleroma.Web.base_url() <> "/")
+ String.starts_with?(id, Pleroma.Web.Endpoint.url() <> "/")
end
def replies(object, opts \\ []) do
defmodule Pleroma.Object.Fetcher do
alias Pleroma.HTTP
+ alias Pleroma.Maps
alias Pleroma.Object
alias Pleroma.Object.Containment
alias Pleroma.Repo
{:transmogrifier, {:error, {:reject, e}}} ->
{:reject, e}
+ {:transmogrifier, {:reject, e}} ->
+ {:reject, e}
+
{:transmogrifier, _} = e ->
{:error, e}
defp prepare_activity_params(data) do
%{
"type" => "Create",
- "to" => data["to"] || [],
- "cc" => data["cc"] || [],
# Should we seriously keep this attributedTo thing?
"actor" => data["actor"] || data["attributedTo"],
"object" => data
}
+ |> Maps.put_if_present("to", data["to"])
+ |> Maps.put_if_present("cc", data["cc"])
+ |> Maps.put_if_present("bto", data["bto"])
+ |> Maps.put_if_present("bcc", data["bcc"])
end
def fetch_object_from_id!(id, options \\ []) do
{:ok, :no_duration_limit, :no_duration_limit}
end
- defp client, do: Pleroma.ReverseProxy.Client
+ defp client, do: Pleroma.ReverseProxy.Client.Wrapper
defp track_failed_url(url, error, opts) do
ttl =
@callback stream_body(map()) :: {:ok, binary(), map()} | :done | {:error, atom() | String.t()}
@callback close(reference() | pid() | map()) :: :ok
-
- def request(method, url, headers, body \\ "", opts \\ []) do
- client().request(method, url, headers, body, opts)
- end
-
- def stream_body(ref), do: client().stream_body(ref)
-
- def close(ref), do: client().close(ref)
-
- defp client do
- :tesla
- |> Application.get_env(:adapter)
- |> client()
- end
-
- defp client(Tesla.Adapter.Hackney), do: Pleroma.ReverseProxy.Client.Hackney
- defp client(Tesla.Adapter.Gun), do: Pleroma.ReverseProxy.Client.Tesla
- defp client(_), do: Pleroma.Config.get!(Pleroma.ReverseProxy.Client)
end
--- /dev/null
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.ReverseProxy.Client.Wrapper do
+ @moduledoc "Meta-client that calls the appropriate client from the config."
+ @behaviour Pleroma.ReverseProxy.Client
+
+ @impl true
+ def request(method, url, headers, body \\ "", opts \\ []) do
+ client().request(method, url, headers, body, opts)
+ end
+
+ @impl true
+ def stream_body(ref), do: client().stream_body(ref)
+
+ @impl true
+ def close(ref), do: client().close(ref)
+
+ defp client do
+ :tesla
+ |> Application.get_env(:adapter)
+ |> client()
+ end
+
+ defp client(Tesla.Adapter.Hackney), do: Pleroma.ReverseProxy.Client.Hackney
+ defp client(Tesla.Adapter.Gun), do: Pleroma.ReverseProxy.Client.Tesla
+ defp client(_), do: Pleroma.Config.get!(Pleroma.ReverseProxy.Client)
+end
case uploader do
Pleroma.Uploaders.Local ->
- upload_base_url || Pleroma.Web.base_url() <> "/media/"
+ upload_base_url || Pleroma.Web.Endpoint.url() <> "/media/"
Pleroma.Uploaders.S3 ->
bucket = Config.get([Pleroma.Uploaders.S3, :bucket])
end
_ ->
- public_endpoint || upload_base_url || Pleroma.Web.base_url() <> "/media/"
+ public_endpoint || upload_base_url || Pleroma.Web.Endpoint.url() <> "/media/"
end
end
end
"""
@type file_spec :: {:file | :url, String.t()}
- @callback put_file(Pleroma.Upload.t()) ::
+ @callback put_file(upload :: struct()) ::
:ok | {:ok, file_spec()} | {:error, String.t()} | :wait_callback
@callback delete_file(file :: String.t()) :: :ok | {:error, String.t()}
| {:error, Plug.Conn.t(), String.t()}
@optional_callbacks http_callback: 2
- @spec put_file(module(), Pleroma.Upload.t()) :: {:ok, file_spec()} | {:error, String.t()}
+ @spec put_file(module(), upload :: struct()) :: {:ok, file_spec()} | {:error, String.t()}
def put_file(uploader, upload) do
case uploader.put_file(upload) do
:ok -> {:ok, {:file, upload.path}}
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.UserRelationship
- alias Pleroma.Web
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.Pipeline
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.CommonAPI.Utils, as: CommonUtils
+ alias Pleroma.Web.Endpoint
alias Pleroma.Web.OAuth
alias Pleroma.Web.RelMe
alias Pleroma.Workers.BackgroundWorker
_ ->
unless options[:no_default] do
- Config.get([:assets, :default_user_avatar], "#{Web.base_url()}/images/avi.png")
+ Config.get([:assets, :default_user_avatar], "#{Endpoint.url()}/images/avi.png")
end
end
end
def banner_url(user, options \\ []) do
case user.banner do
%{"url" => [%{"href" => href} | _]} -> href
- _ -> !options[:no_default] && "#{Web.base_url()}/images/banner.png"
+ _ -> !options[:no_default] && "#{Endpoint.url()}/images/banner.png"
end
end
# Should probably be renamed or removed
@spec ap_id(User.t()) :: String.t()
- def ap_id(%User{nickname: nickname}), do: "#{Web.base_url()}/users/#{nickname}"
+ def ap_id(%User{nickname: nickname}), do: "#{Endpoint.url()}/users/#{nickname}"
@spec ap_followers(User.t()) :: String.t()
def ap_followers(%User{follower_address: fa}) when is_binary(fa), do: fa
- e.g. Pleroma.User.Query.build(%{ap_id: ["http://ap_id1", "http://ap_id2"]})
"""
import Ecto.Query
- import Pleroma.Web.AdminAPI.Search, only: [not_empty_string: 1]
+ import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1]
alias Pleroma.FollowingRelationship
alias Pleroma.User
defmacro __using__(which) when is_atom(which) do
apply(__MODULE__, which, [])
end
-
- def base_url do
- Pleroma.Web.Endpoint.url()
- end
end
defp increase_replies_count_if_reply(_create_data), do: :noop
- @object_types ~w[ChatMessage Question Answer Audio Video Event Article]
+ @object_types ~w[ChatMessage Question Answer Audio Video Event Article Note]
@impl true
def persist(%{"type" => type} = object, meta) when type in @object_types do
with {:ok, object} <- Object.create(object) do
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ActivityPub.Persisting do
- @callback persist(map(), keyword()) :: {:ok, Activity.t() | Object.t()}
+ @callback persist(map(), keyword()) :: {:ok, struct()}
end
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ActivityPub.Streaming do
- alias Pleroma.Activity
- alias Pleroma.Object
- alias Pleroma.User
-
- @callback stream_out(Activity.t()) :: any()
- @callback stream_out_participations(Object.t(), User.t()) :: any()
+ @callback stream_out(struct()) :: any()
+ @callback stream_out_participations(struct(), struct()) :: any()
end
[actor.follower_address]
public? and Visibility.is_local_public?(object) ->
- [actor.follower_address, object.data["actor"], Pleroma.Constants.as_local_public()]
+ [actor.follower_address, object.data["actor"], Utils.as_local_public()]
public? ->
[actor.follower_address, object.data["actor"], Pleroma.Constants.as_public()]
@required_description_keys [:key, :related_policy]
- @callback filter(Map.t()) :: {:ok | :reject, Map.t()}
- @callback describe() :: {:ok | :error, Map.t()}
- @callback config_description() :: %{
- optional(:children) => [map()],
- key: atom(),
- related_policy: String.t(),
- label: String.t(),
- description: String.t()
- }
- @optional_callbacks config_description: 0
-
def filter(policies, %{} = message) do
policies
|> Enum.reduce({:ok, message}, fn
def describe, do: get_policies() |> describe()
def config_descriptions do
- Pleroma.Web.ActivityPub.MRF
+ Pleroma.Web.ActivityPub.MRF.Policy
|> Pleroma.Docs.Generator.list_behaviour_implementations()
|> config_descriptions()
end
defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy do
@moduledoc "Adds expiration to all local Create activities"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
@impl true
def filter(activity) do
@moduledoc "Prevent followbots from following with a bit of heuristic"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
# XXX: this should become User.normalize_by_ap_id() or similar, really.
defp normalize_by_ap_id(%{"id" => id}), do: User.get_cached_by_ap_id(id)
defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do
alias Pleroma.User
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
require Logger
defmodule Pleroma.Web.ActivityPub.MRF.DropPolicy do
require Logger
@moduledoc "Drop and log everything received"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
@impl true
def filter(object) do
alias Pleroma.Object
@moduledoc "Ensure a re: is prepended on replies to a post with a Subject"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
@reply_prefix Regex.compile!("^re:[[:space:]]*", [:caseless])
defmodule Pleroma.Web.ActivityPub.MRF.FollowBotPolicy do
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
alias Pleroma.Config
alias Pleroma.User
alias Pleroma.Web.CommonAPI
defmodule Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicy do
alias Pleroma.User
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
@moduledoc "Remove bot posts from federated timeline"
require Pleroma.Constants
Note: This MRF Policy is always enabled, if you want to disable it you have to set empty lists.
"""
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
defp check_reject(message, hashtags) do
if Enum.any?(Config.get([:mrf_hashtag, :reject]), fn match -> match in hashtags end) do
@moduledoc "Block messages with too much mentions (configurable)"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
defp delist_message(message, threshold) when threshold > 0 do
follower_collection = User.get_cached_by_ap_id(message["actor"]).follower_address
@moduledoc "Reject or Word-Replace messages with a keyword or regex"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
defp string_matches?(string, _) when not is_binary(string) do
false
end
defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do
@moduledoc "Preloads any attachments in the MediaProxy cache by prefetching them"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
alias Pleroma.HTTP
alias Pleroma.Web.MediaProxy
defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicy do
@moduledoc "Block messages which mention a user"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
@impl true
def filter(%{"type" => "Create"} = message) do
defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do
@moduledoc "Filter local activities which have no content"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
- alias Pleroma.Web
+ alias Pleroma.Web.Endpoint
@impl true
def filter(%{"actor" => actor} = object) do
def filter(object), do: {:ok, object}
defp is_local?(actor) do
- if actor |> String.starts_with?("#{Web.base_url()}") do
+ if actor |> String.starts_with?("#{Endpoint.url()}") do
true
else
false
defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do
@moduledoc "Does nothing (lets the messages go through unmodified)"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
@impl true
def filter(object) do
defmodule Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy do
@moduledoc "Ensure no content placeholder is present (such as the dot from mastodon)"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
@impl true
def filter(
@moduledoc "Scrub configured hypertext markup"
alias Pleroma.HTML
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
@impl true
def filter(%{"type" => "Create", "object" => child_object} = object) do
require Pleroma.Constants
@moduledoc "Filter activities depending on their age"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
defp check_date(%{"object" => %{"published" => published}} = message) do
with %DateTime{} = now <- DateTime.utc_now(),
--- /dev/null
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.Policy do
+ @callback filter(Map.t()) :: {:ok | :reject, Map.t()}
+ @callback describe() :: {:ok | :error, Map.t()}
+ @callback config_description() :: %{
+ optional(:children) => [map()],
+ key: atom(),
+ related_policy: String.t(),
+ label: String.t(),
+ description: String.t()
+ }
+ @optional_callbacks config_description: 0
+end
alias Pleroma.Config
alias Pleroma.User
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
require Pleroma.Constants
defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
@moduledoc "Filter activities depending on their origin instance"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
alias Pleroma.Config
alias Pleroma.FollowingRelationship
alias Pleroma.Config
@moduledoc "Detect new emojis by their shortcode and steals them"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
defp accept_host?(host), do: host in Config.get([:mrf_steal_emoji, :hosts], [])
require Logger
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
defp lookup_subchain(actor) do
with matches <- Config.get([:mrf_subchain, :match_actor]),
defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
alias Pleroma.User
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
@moduledoc """
Apply policies based on user tags
alias Pleroma.Config
@moduledoc "Accept-list of users from specified instances"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
defp filter_by_list(object, []), do: {:ok, object}
defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do
@moduledoc "Filter messages which belong to certain activity vocabularies"
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
@impl true
def filter(%{"type" => "Undo", "object" => child_message} = message) do
%{"type" => "Create", "object" => %{"type" => objtype} = object} = create_activity,
meta
)
- when objtype in ~w[Question Answer Audio Video Event Article] do
+ when objtype in ~w[Question Answer Audio Video Event Article Note] do
with {:ok, object_data} <- cast_and_apply(object),
meta = Keyword.put(meta, :object_data, object_data |> stringify_keys),
{:ok, create_activity} <-
end
def validate(%{"type" => type} = object, meta)
- when type in ~w[Event Question Audio Video Article] do
+ when type in ~w[Event Question Audio Video Article Note] do
validator =
case type do
"Event" -> EventValidator
"Audio" -> AudioVideoValidator
"Video" -> AudioVideoValidator
"Article" -> ArticleNoteValidator
+ "Note" -> ArticleNoteValidator
end
with {:ok, object} <-
EventValidator.cast_and_apply(object)
end
- def cast_and_apply(%{"type" => "Article"} = object) do
+ def cast_and_apply(%{"type" => type} = object) when type in ~w[Article Note] do
ArticleNoteValidator.cast_and_apply(object)
end
false <- Visibility.is_public?(object) do
same_actor = object.data["actor"] == actor.ap_id
recipients = get_field(cng, :to) ++ get_field(cng, :cc)
- local_public = Pleroma.Constants.as_local_public()
+ local_public = Utils.as_local_public()
is_public =
Enum.member?(recipients, Pleroma.Constants.as_public()) or
use Ecto.Schema
alias Pleroma.EctoType.ActivityPub.ObjectValidators
+ alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
import Ecto.Changeset
field(:name, :string)
field(:inReplyTo, ObjectValidators.ObjectID)
field(:attributedTo, ObjectValidators.ObjectID)
+ field(:context, :string)
# TODO: Remove actor on objects
field(:actor, ObjectValidators.ObjectID)
end
def changeset(struct, data) do
+ data =
+ data
+ |> CommonFixes.fix_actor()
+ |> CommonFixes.fix_object_defaults()
+
struct
|> cast(data, __schema__(:fields))
end
field(:likes, {:array, ObjectValidators.ObjectID}, default: [])
field(:announcements, {:array, ObjectValidators.ObjectID}, default: [])
+
+ field(:replies, {:array, ObjectValidators.ObjectID}, default: [])
end
def cast_and_apply(data) do
end
def cast_data(data) do
- data = fix(data)
-
%__MODULE__{}
|> changeset(data)
end
- defp fix_url(%{"url" => url} = data) when is_map(url) do
- Map.put(data, "url", url["href"])
- end
-
+ defp fix_url(%{"url" => url} = data) when is_bitstring(url), do: data
+ defp fix_url(%{"url" => url} = data) when is_map(url), do: Map.put(data, "url", url["href"])
defp fix_url(data), do: data
+ defp fix_tag(%{"tag" => tag} = data) when is_list(tag), do: data
+ defp fix_tag(%{"tag" => tag} = data) when is_map(tag), do: Map.put(data, "tag", [tag])
+ defp fix_tag(data), do: Map.drop(data, ["tag"])
+
+ defp fix_replies(%{"replies" => %{"first" => %{"items" => replies}}} = data)
+ when is_list(replies),
+ do: Map.put(data, "replies", replies)
+
+ defp fix_replies(%{"replies" => %{"items" => replies}} = data) when is_list(replies),
+ do: Map.put(data, "replies", replies)
+
+ defp fix_replies(%{"replies" => replies} = data) when is_bitstring(replies),
+ do: Map.drop(data, ["replies"])
+
+ defp fix_replies(data), do: data
+
defp fix(data) do
data
- |> CommonFixes.fix_defaults()
- |> CommonFixes.fix_attribution()
|> CommonFixes.fix_actor()
+ |> CommonFixes.fix_object_defaults()
|> fix_url()
+ |> fix_tag()
+ |> fix_replies()
|> Transmogrifier.fix_emoji()
+ |> Transmogrifier.fix_content_map()
end
def changeset(struct, data) do
def fix_media_type(data) do
data = Map.put_new(data, "mediaType", data["mimeType"])
- if MIME.valid?(data["mediaType"]) do
+ if is_bitstring(data["mediaType"]) && MIME.extensions(data["mediaType"]) != [] do
data
else
Map.put(data, "mediaType", "application/octet-stream")
defp fix(data) do
data
- |> CommonFixes.fix_defaults()
- |> CommonFixes.fix_attribution()
|> CommonFixes.fix_actor()
+ |> CommonFixes.fix_object_defaults()
|> Transmogrifier.fix_emoji()
|> fix_url()
|> fix_content()
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
+ alias Pleroma.EctoType.ActivityPub.ObjectValidators
alias Pleroma.Object.Containment
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
- # based on Pleroma.Web.ActivityPub.Utils.lazy_put_objects_defaults
- def fix_defaults(data) do
+ def cast_and_filter_recipients(message, field, follower_collection, field_fallback \\ []) do
+ {:ok, data} = ObjectValidators.Recipients.cast(message[field] || field_fallback)
+
+ data =
+ Enum.reject(data, fn x ->
+ String.ends_with?(x, "/followers") and x != follower_collection
+ end)
+
+ Map.put(message, field, data)
+ end
+
+ def fix_object_defaults(data) do
%{data: %{"id" => context}, id: context_id} =
Utils.create_context(data["context"] || data["conversation"])
+ %User{follower_address: follower_collection} = User.get_cached_by_ap_id(data["attributedTo"])
+
data
|> Map.put("context", context)
|> Map.put("context_id", context_id)
+ |> cast_and_filter_recipients("to", follower_collection)
+ |> cast_and_filter_recipients("cc", follower_collection)
+ |> cast_and_filter_recipients("bto", follower_collection)
+ |> cast_and_filter_recipients("bcc", follower_collection)
+ |> Transmogrifier.fix_implicit_addressing(follower_collection)
end
- def fix_attribution(data) do
- data
- |> Map.put_new("actor", data["attributedTo"])
+ def fix_activity_addressing(activity, _meta) do
+ %User{follower_address: follower_collection} = User.get_cached_by_ap_id(activity["actor"])
+
+ activity
+ |> cast_and_filter_recipients("to", follower_collection)
+ |> cast_and_filter_recipients("cc", follower_collection)
+ |> cast_and_filter_recipients("bto", follower_collection)
+ |> cast_and_filter_recipients("bcc", follower_collection)
+ |> Transmogrifier.fix_implicit_addressing(follower_collection)
end
def fix_actor(data) do
- actor = Containment.get_actor(data)
+ actor =
+ data
+ |> Map.put_new("actor", data["attributedTo"])
+ |> Containment.get_actor()
data
|> Map.put("actor", actor)
fields
|> Enum.map(fn field -> get_field(cng, field) end)
|> Enum.any?(fn
+ nil -> false
[] -> false
_ -> true
end)
alias Pleroma.EctoType.ActivityPub.ObjectValidators
alias Pleroma.Object
+ alias Pleroma.User
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
+ alias Pleroma.Web.ActivityPub.Transmogrifier
import Ecto.Changeset
field(:type, :string)
field(:to, ObjectValidators.Recipients, default: [])
field(:cc, ObjectValidators.Recipients, default: [])
+ field(:bto, ObjectValidators.Recipients, default: [])
+ field(:bcc, ObjectValidators.Recipients, default: [])
field(:object, ObjectValidators.ObjectID)
field(:expires_at, ObjectValidators.DateTime)
|> cast(data, __schema__(:fields))
end
- defp fix_context(data, meta) do
- if object = meta[:object_data] do
- Map.put_new(data, "context", object["context"])
- else
- data
- end
- end
+ # CommonFixes.fix_activity_addressing adapted for Create specific behavior
+ defp fix_addressing(data, object) do
+ %User{follower_address: follower_collection} = User.get_cached_by_ap_id(data["actor"])
- defp fix_addressing(data, meta) do
- if object = meta[:object_data] do
- data
- |> Map.put_new("to", object["to"] || [])
- |> Map.put_new("cc", object["cc"] || [])
- else
- data
- end
+ data
+ |> CommonFixes.cast_and_filter_recipients("to", follower_collection, object["to"])
+ |> CommonFixes.cast_and_filter_recipients("cc", follower_collection, object["cc"])
+ |> CommonFixes.cast_and_filter_recipients("bto", follower_collection, object["bto"])
+ |> CommonFixes.cast_and_filter_recipients("bcc", follower_collection, object["bcc"])
+ |> Transmogrifier.fix_implicit_addressing(follower_collection)
end
- defp fix(data, meta) do
+ def fix(data, meta) do
+ object = meta[:object_data]
+
data
- |> fix_context(meta)
- |> fix_addressing(meta)
|> CommonFixes.fix_actor()
+ |> Map.put_new("context", object["context"])
+ |> fix_addressing(object)
end
defp validate_data(cng, meta) do
+ object = meta[:object_data]
+
cng
- |> validate_required([:actor, :type, :object])
+ |> validate_required([:actor, :type, :object, :to, :cc])
|> validate_inclusion(:type, ["Create"])
|> CommonValidations.validate_actor_presence()
- |> CommonValidations.validate_any_presence([:to, :cc])
- |> validate_actors_match(meta)
- |> validate_context_match(meta)
+ |> validate_actors_match(object)
+ |> validate_context_match(object)
+ |> validate_addressing_match(object)
|> validate_object_nonexistence()
|> validate_object_containment()
end
end)
end
- def validate_actors_match(cng, meta) do
- attributed_to = meta[:object_data]["attributedTo"] || meta[:object_data]["actor"]
+ def validate_actors_match(cng, object) do
+ attributed_to = object["attributedTo"] || object["actor"]
cng
|> validate_change(:actor, fn :actor, actor ->
end)
end
- def validate_context_match(cng, %{object_data: %{"context" => object_context}}) do
+ def validate_context_match(cng, %{"context" => object_context}) do
cng
|> validate_change(:context, fn :context, context ->
if context == object_context do
end)
end
- def validate_context_match(cng, _), do: cng
+ def validate_addressing_match(cng, object) do
+ [:to, :cc, :bcc, :bto]
+ |> Enum.reduce(cng, fn field, cng ->
+ object_data = object[to_string(field)]
+
+ validate_change(cng, field, fn field, data ->
+ if data == object_data do
+ []
+ else
+ [{field, "field doesn't match with object (#{inspect(object_data)})"}]
+ end
+ end)
+ end)
+ end
end
+++ /dev/null
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateNoteValidator do
- use Ecto.Schema
-
- alias Pleroma.EctoType.ActivityPub.ObjectValidators
- alias Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator
-
- import Ecto.Changeset
-
- @primary_key false
-
- embedded_schema do
- field(:id, ObjectValidators.ObjectID, primary_key: true)
- field(:actor, ObjectValidators.ObjectID)
- field(:type, :string)
- field(:to, ObjectValidators.Recipients, default: [])
- field(:cc, ObjectValidators.Recipients, default: [])
- field(:bto, ObjectValidators.Recipients, default: [])
- field(:bcc, ObjectValidators.Recipients, default: [])
- embeds_one(:object, NoteValidator)
- end
-
- def cast_data(data) do
- cast(%__MODULE__{}, data, __schema__(:fields))
- end
-end
defp fix(data) do
data
- |> CommonFixes.fix_defaults()
- |> CommonFixes.fix_attribution()
+ |> CommonFixes.fix_actor()
+ |> CommonFixes.fix_object_defaults()
|> Transmogrifier.fix_emoji()
end
defp fix(data) do
data
- |> CommonFixes.fix_defaults()
- |> CommonFixes.fix_attribution()
+ |> CommonFixes.fix_actor()
+ |> CommonFixes.fix_object_defaults()
|> Transmogrifier.fix_emoji()
|> fix_closed()
end
},
%{
"rel" => "http://ostatus.org/schema/1.0/subscribe",
- "template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}"
+ "template" => "#{Pleroma.Web.Endpoint.url()}/ostatus_subscribe?acct={uri}"
}
]
end
Object.increase_replies_count(in_reply_to)
end
+ reply_depth = (meta[:depth] || 0) + 1
+
+ # FIXME: Force inReplyTo to replies
+ if Pleroma.Web.Federator.allowed_thread_distance?(reply_depth) and
+ object.data["replies"] != nil do
+ for reply_id <- object.data["replies"] do
+ Pleroma.Workers.RemoteFetcherWorker.enqueue("fetch_remote", %{
+ "id" => reply_id,
+ "depth" => reply_depth
+ })
+ end
+ end
+
ConcurrentLimiter.limit(Pleroma.Web.RichMedia.Helpers, fn ->
Task.start(fn -> Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) end)
end)
end
def handle_object_creation(%{"type" => objtype} = object, meta)
- when objtype in ~w[Audio Video Question Event Article] do
+ when objtype in ~w[Audio Video Question Event Article Note] do
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
{:ok, object, meta}
end
|> fix_content_map()
|> fix_addressing()
|> fix_summary()
- |> fix_type(options)
end
def fix_summary(%{"summary" => nil} = object) do
end
end
- def fix_explicit_addressing(
- %{"to" => to, "cc" => cc} = object,
- explicit_mentions,
- follower_collection
- ) do
- explicit_to = Enum.filter(to, fn x -> x in explicit_mentions end)
+ # if directMessage flag is set to true, leave the addressing alone
+ def fix_explicit_addressing(%{"directMessage" => true} = object, _follower_collection),
+ do: object
+
+ def fix_explicit_addressing(%{"to" => to, "cc" => cc} = object, follower_collection) do
+ explicit_mentions =
+ Utils.determine_explicit_mentions(object) ++
+ [Pleroma.Constants.as_public(), follower_collection]
+ explicit_to = Enum.filter(to, fn x -> x in explicit_mentions end)
explicit_cc = Enum.filter(to, fn x -> x not in explicit_mentions end)
final_cc =
(cc ++ explicit_cc)
+ |> Enum.filter(& &1)
|> Enum.reject(fn x -> String.ends_with?(x, "/followers") and x != follower_collection end)
|> Enum.uniq()
|> Map.put("cc", final_cc)
end
- def fix_explicit_addressing(object, _explicit_mentions, _followers_collection), do: object
-
- # if directMessage flag is set to true, leave the addressing alone
- def fix_explicit_addressing(%{"directMessage" => true} = object), do: object
-
- def fix_explicit_addressing(object) do
- explicit_mentions = Utils.determine_explicit_mentions(object)
-
- %User{follower_address: follower_collection} =
- object
- |> Containment.get_actor()
- |> User.get_cached_by_ap_id()
-
- explicit_mentions =
- explicit_mentions ++
- [
- Pleroma.Constants.as_public(),
- follower_collection
- ]
-
- fix_explicit_addressing(object, explicit_mentions, follower_collection)
- end
-
# if as:Public is addressed, then make sure the followers collection is also addressed
# so that the activities will be delivered to local users.
def fix_implicit_addressing(%{"to" => to, "cc" => cc} = object, followers_collection) do
end
end
- def fix_implicit_addressing(object, _), do: object
-
def fix_addressing(object) do
- {:ok, %User{} = user} = User.get_or_fetch_by_ap_id(object["actor"])
- followers_collection = User.ap_followers(user)
+ {:ok, %User{follower_address: follower_collection}} =
+ object
+ |> Containment.get_actor()
+ |> User.get_or_fetch_by_ap_id()
object
|> fix_addressing_list("to")
|> fix_addressing_list("cc")
|> fix_addressing_list("bto")
|> fix_addressing_list("bcc")
- |> fix_explicit_addressing()
- |> fix_implicit_addressing(followers_collection)
+ |> fix_explicit_addressing(follower_collection)
+ |> fix_implicit_addressing(follower_collection)
end
def fix_actor(%{"attributedTo" => actor} = object) do
media_type =
cond do
- is_map(url) && MIME.valid?(url["mediaType"]) -> url["mediaType"]
- MIME.valid?(data["mediaType"]) -> data["mediaType"]
- MIME.valid?(data["mimeType"]) -> data["mimeType"]
- true -> nil
+ is_map(url) && MIME.extensions(url["mediaType"]) != [] ->
+ url["mediaType"]
+
+ is_bitstring(data["mediaType"]) && MIME.extensions(data["mediaType"]) != [] ->
+ data["mediaType"]
+
+ is_bitstring(data["mimeType"]) && MIME.extensions(data["mimeType"]) != [] ->
+ data["mimeType"]
+
+ true ->
+ nil
end
href =
def fix_content_map(object), do: object
- def fix_type(object, options \\ [])
+ defp fix_type(%{"type" => "Note", "inReplyTo" => reply_id, "name" => _} = object, options)
+ when is_binary(reply_id) do
+ options = Keyword.put(options, :fetch, true)
- def fix_type(%{"inReplyTo" => reply_id, "name" => _} = object, options)
- when is_binary(reply_id) do
- with true <- Federator.allowed_thread_distance?(options[:depth]),
- {:ok, %{data: %{"type" => "Question"} = _} = _} <- get_obj_helper(reply_id, options) do
+ with %Object{data: %{"type" => "Question"}} <- Object.normalize(reply_id, options) do
Map.put(object, "type", "Answer")
else
_ -> object
end
end
- def fix_type(object, _), do: object
+ defp fix_type(object, _options), do: object
# Reduce the object list to find the reported user.
defp get_reported(objects) do
# - tags
# - emoji
def handle_incoming(
- %{"type" => "Create", "object" => %{"type" => objtype} = object} = data,
+ %{"type" => "Create", "object" => %{"type" => "Page"} = object} = data,
options
- )
- when objtype in ~w{Note Page} do
+ ) do
actor = Containment.get_actor(data)
with nil <- Activity.get_create_by_object_ap_id(object["id"]),
def handle_incoming(
%{"type" => "Create", "object" => %{"type" => objtype, "id" => obj_id}} = data,
- _options
+ options
)
- when objtype in ~w{Question Answer ChatMessage Audio Video Event Article} do
- data = Map.put(data, "object", strip_internal_fields(data["object"]))
+ when objtype in ~w{Question Answer ChatMessage Audio Video Event Article Note} do
+ fetch_options = Keyword.put(options, :depth, (options[:depth] || 0) + 1)
+
+ object =
+ data["object"]
+ |> strip_internal_fields()
+ |> fix_type(fetch_options)
+ |> fix_in_reply_to(fetch_options)
+
+ data = Map.put(data, "object", object)
+ options = Keyword.put(options, :local, false)
with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
nil <- Activity.get_create_by_object_ap_id(obj_id),
- {:ok, activity, _} <- Pipeline.common_pipeline(data, local: false) do
+ {:ok, activity, _} <- Pipeline.common_pipeline(data, options) do
{:ok, activity}
else
%Activity{} = activity -> {:ok, activity}
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
- alias Pleroma.Web
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.AdminAPI.AccountView
@supported_report_states ~w(open closed resolved)
@valid_visibilities ~w(public unlisted private direct)
+ def as_local_public, do: Endpoint.url() <> "/#Public"
+
# Some implementations send the actor URI as the actor field, others send the entire actor object,
# so figure out what the actor's URI is based on what we have.
def get_ap_id(%{"id" => id} = _), do: id
!label_in_collection?(ap_id, params["cc"])
if need_splice? do
- cc_list = extract_list(params["cc"])
- Map.put(params, "cc", [ap_id | cc_list])
+ cc = [ap_id | extract_list(params["cc"])]
+
+ params
+ |> Map.put("cc", cc)
+ |> Maps.safe_put_in(["object", "cc"], cc)
else
params
end
%{
"@context" => [
"https://www.w3.org/ns/activitystreams",
- "#{Web.base_url()}/schemas/litepub-0.1.jsonld",
+ "#{Endpoint.url()}/schemas/litepub-0.1.jsonld",
%{
"@language" => "und"
}
end
def generate_id(type) do
- "#{Web.base_url()}/#{type}/#{UUID.generate()}"
+ "#{Endpoint.url()}/#{type}/#{UUID.generate()}"
end
def get_notified_from_object(%{"type" => type} = object) when type in @supported_object_types do
def is_public?(data) do
Utils.label_in_message?(Pleroma.Constants.as_public(), data) or
- Utils.label_in_message?(Pleroma.Constants.as_local_public(), data)
+ Utils.label_in_message?(Utils.as_local_public(), data)
end
def is_local_public?(%Object{data: data}), do: is_local_public?(data)
def is_local_public?(%Activity{data: data}), do: is_local_public?(data)
def is_local_public?(data) do
- Utils.label_in_message?(Pleroma.Constants.as_local_public(), data) and
+ Utils.label_in_message?(Utils.as_local_public(), data) and
not Utils.label_in_message?(Pleroma.Constants.as_public(), data)
end
Pleroma.Constants.as_public() in cc ->
"unlisted"
- Pleroma.Constants.as_local_public() in to ->
+ Utils.as_local_public() in to ->
"local"
# this should use the sql for the object's activity
@page_size 50
- defmacro not_empty_string(string) do
- quote do
- is_binary(unquote(string)) and unquote(string) != ""
- end
- end
-
@spec user(map()) :: {:ok, [User.t()], pos_integer()}
def user(params \\ %{}) do
query =
responses: %{
200 => Operation.response("Media", "application/json", Attachment),
401 => Operation.response("Media", "application/json", ApiError),
+ 403 => Operation.response("Media", "application/json", ApiError),
422 => Operation.response("Media", "application/json", ApiError)
}
}
],
operationId: "TimelineController.hashtag",
responses: %{
- 200 => Operation.response("Array of Status", "application/json", array_of_statuses())
+ 200 => Operation.response("Array of Status", "application/json", array_of_statuses()),
+ 401 => Operation.response("Error", "application/json", ApiError)
}
}
end
--- /dev/null
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Schemas.ApiError
+ alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def emoji_operation do
+ %Operation{
+ tags: ["Emojis"],
+ summary: "List all custom emojis",
+ operationId: "UtilController.emoji",
+ parameters: [],
+ responses: %{
+ 200 =>
+ Operation.response("List", "application/json", %Schema{
+ type: :object,
+ additionalProperties: %Schema{
+ type: :object,
+ properties: %{
+ image_url: %Schema{type: :string},
+ tags: %Schema{type: :array, items: %Schema{type: :string}}
+ }
+ },
+ example: %{
+ "firefox" => %{
+ "image_url" => "/emoji/firefox.png",
+ "tag" => ["Fun"]
+ }
+ }
+ })
+ }
+ }
+ end
+
+ def frontend_configurations_operation do
+ %Operation{
+ tags: ["Configuration"],
+ summary: "Dump frontend configurations",
+ operationId: "UtilController.frontend_configurations",
+ parameters: [],
+ responses: %{
+ 200 =>
+ Operation.response("List", "application/json", %Schema{
+ type: :object,
+ additionalProperties: %Schema{type: :object}
+ })
+ }
+ }
+ end
+
+ def change_password_operation do
+ %Operation{
+ tags: ["Account credentials"],
+ summary: "Change account password",
+ security: [%{"oAuth" => ["write:accounts"]}],
+ operationId: "UtilController.change_password",
+ parameters: [
+ Operation.parameter(:password, :query, :string, "Current password", required: true),
+ Operation.parameter(:new_password, :query, :string, "New password", required: true),
+ Operation.parameter(
+ :new_password_confirmation,
+ :query,
+ :string,
+ "New password, confirmation",
+ required: true
+ )
+ ],
+ responses: %{
+ 200 =>
+ Operation.response("Success", "application/json", %Schema{
+ type: :object,
+ properties: %{status: %Schema{type: :string, example: "success"}}
+ }),
+ 400 => Operation.response("Error", "application/json", ApiError),
+ 403 => Operation.response("Error", "application/json", ApiError)
+ }
+ }
+ end
+
+ def change_email_operation do
+ %Operation{
+ tags: ["Account credentials"],
+ summary: "Change account email",
+ security: [%{"oAuth" => ["write:accounts"]}],
+ operationId: "UtilController.change_email",
+ parameters: [
+ Operation.parameter(:password, :query, :string, "Current password", required: true),
+ Operation.parameter(:email, :query, :string, "New email", required: true)
+ ],
+ requestBody: nil,
+ responses: %{
+ 200 =>
+ Operation.response("Success", "application/json", %Schema{
+ type: :object,
+ properties: %{status: %Schema{type: :string, example: "success"}}
+ }),
+ 400 => Operation.response("Error", "application/json", ApiError),
+ 403 => Operation.response("Error", "application/json", ApiError)
+ }
+ }
+ end
+
+ def update_notificaton_settings_operation do
+ %Operation{
+ tags: ["Accounts"],
+ summary: "Update Notification Settings",
+ security: [%{"oAuth" => ["write:accounts"]}],
+ operationId: "UtilController.update_notificaton_settings",
+ parameters: [
+ Operation.parameter(
+ :block_from_strangers,
+ :query,
+ BooleanLike,
+ "blocks notifications from accounts you do not follow"
+ ),
+ Operation.parameter(
+ :hide_notification_contents,
+ :query,
+ BooleanLike,
+ "removes the contents of a message from the push notification"
+ )
+ ],
+ requestBody: nil,
+ responses: %{
+ 200 =>
+ Operation.response("Success", "application/json", %Schema{
+ type: :object,
+ properties: %{status: %Schema{type: :string, example: "success"}}
+ }),
+ 400 => Operation.response("Error", "application/json", ApiError)
+ }
+ }
+ end
+
+ def disable_account_operation do
+ %Operation{
+ tags: ["Account credentials"],
+ summary: "Disable Account",
+ security: [%{"oAuth" => ["write:accounts"]}],
+ operationId: "UtilController.disable_account",
+ parameters: [
+ Operation.parameter(:password, :query, :string, "Password")
+ ],
+ responses: %{
+ 200 =>
+ Operation.response("Success", "application/json", %Schema{
+ type: :object,
+ properties: %{status: %Schema{type: :string, example: "success"}}
+ }),
+ 403 => Operation.response("Error", "application/json", ApiError)
+ }
+ }
+ end
+
+ def delete_account_operation do
+ %Operation{
+ tags: ["Account credentials"],
+ summary: "Delete Account",
+ security: [%{"oAuth" => ["write:accounts"]}],
+ operationId: "UtilController.delete_account",
+ parameters: [
+ Operation.parameter(:password, :query, :string, "Password")
+ ],
+ responses: %{
+ 200 =>
+ Operation.response("Success", "application/json", %Schema{
+ type: :object,
+ properties: %{status: %Schema{type: :string, example: "success"}}
+ }),
+ 403 => Operation.response("Error", "application/json", ApiError)
+ }
+ }
+ end
+
+ def captcha_operation do
+ %Operation{
+ summary: "Get a captcha",
+ operationId: "UtilController.captcha",
+ parameters: [],
+ responses: %{
+ 200 => Operation.response("Success", "application/json", %Schema{type: :object})
+ }
+ }
+ end
+
+ def healthcheck_operation do
+ %Operation{
+ tags: ["Accounts"],
+ summary: "Quick status check on the instance",
+ security: [%{"oAuth" => ["write:accounts"]}],
+ operationId: "UtilController.healthcheck",
+ parameters: [],
+ responses: %{
+ 200 => Operation.response("Healthy", "application/json", %Schema{type: :object}),
+ 503 =>
+ Operation.response("Disabled or Unhealthy", "application/json", %Schema{type: :object})
+ }
+ }
+ end
+
+ def remote_subscribe_operation do
+ %Operation{
+ tags: ["Accounts"],
+ summary: "Remote Subscribe",
+ operationId: "UtilController.remote_subscribe",
+ parameters: [],
+ responses: %{200 => Operation.response("Web Page", "test/html", %Schema{type: :string})}
+ }
+ end
+end
requestBody: request_body("Parameters", import_request(), required: true),
responses: %{
200 => ok_response(),
+ 403 => Operation.response("Error", "application/json", ApiError),
500 => Operation.response("Error", "application/json", ApiError)
},
security: [%{"oAuth" => ["write:follow"]}]
## Channels
# channel "room:*", Pleroma.Web.RoomChannel
- channel("chat:*", Pleroma.Web.ChatChannel)
+ channel("chat:*", Pleroma.Web.ShoutChannel)
# Socket params are passed from the client and can
# be used to verify and authenticate a user. After
# See `Phoenix.Token` documentation for examples in
# performing token verification on connect.
def connect(%{"token" => token}, socket) do
- with true <- Pleroma.Config.get([:chat, :enabled]),
+ with true <- Pleroma.Config.get([:shout, :enabled]),
{:ok, user_id} <- Phoenix.Token.verify(socket, "user socket", token, max_age: 84_600),
%User{} = user <- Pleroma.User.get_cached_by_id(user_id) do
{:ok, assign(socket, :user_name, user.nickname)}
to =
case visibility do
"public" -> [Pleroma.Constants.as_public() | draft.mentions]
- "local" -> [Pleroma.Constants.as_local_public() | draft.mentions]
+ "local" -> [Utils.as_local_public() | draft.mentions]
end
cc = [draft.user.follower_address]
plug(Plug.Parsers,
parsers: [
:urlencoded,
- {:multipart, length: {Config, :get, [[:instance, :upload_limit]]}},
+ {:multipart, length: Config.get([:instance, :upload_limit])},
:json
],
pass: ["*/*"],
Logger.debug("Unhandled actor #{actor}, #{inspect(e)}")
{:error, e}
+ {:error, {:validate_object, _}} = e ->
+ Logger.error("Incoming AP doc validation error: #{inspect(e)}")
+ Logger.debug(Jason.encode!(params, pretty: true))
+ e
+
e ->
# Just drop those for now
Logger.debug(fn -> "Unhandled activity\n" <> Jason.encode!(params, pretty: true) end)
def feed_logo do
case Pleroma.Config.get([:feed, :logo]) do
nil ->
- "#{Pleroma.Web.base_url()}/static/logo.svg"
+ "#{Pleroma.Web.Endpoint.url()}/static/logo.svg"
logo ->
- "#{Pleroma.Web.base_url()}#{logo}"
+ "#{Pleroma.Web.Endpoint.url()}#{logo}"
end
|> MediaProxy.url()
end
alias Pleroma.Activity
alias Pleroma.Repo
alias Pleroma.User
- alias Pleroma.Web
alias Pleroma.Web.ControllerHelper
+ alias Pleroma.Web.Endpoint
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.Plugs.OAuthScopesPlug
end
defp resource_search(:v2, "hashtags", query, options) do
- tags_path = Web.base_url() <> "/tag/"
+ tags_path = Endpoint.url() <> "/tag/"
query
|> prepare_tags(options)
use Pleroma.Web, :view
alias Pleroma.Emoji
- alias Pleroma.Web
+ alias Pleroma.Web.Endpoint
def render("index.json", %{custom_emojis: custom_emojis}) do
render_many(custom_emojis, __MODULE__, "show.json")
end
def render("show.json", %{custom_emoji: {shortcode, %Emoji{file: relative_url, tags: tags}}}) do
- url = Web.base_url() |> URI.merge(relative_url) |> to_string()
+ url = Endpoint.url() |> URI.merge(relative_url) |> to_string()
%{
"shortcode" => shortcode,
instance = Config.get(:instance)
%{
- uri: Pleroma.Web.base_url(),
+ uri: Pleroma.Web.Endpoint.url(),
title: Keyword.get(instance, :name),
description: Keyword.get(instance, :description),
version: "#{@mastodon_api_level} (compatible; #{Pleroma.Application.named_version()})",
},
stats: Pleroma.Stats.get_stats(),
thumbnail:
- URI.merge(Pleroma.Web.base_url(), Keyword.get(instance, :instance_thumbnail)) |> to_string,
+ URI.merge(Pleroma.Web.Endpoint.url(), Keyword.get(instance, :instance_thumbnail))
+ |> to_string,
languages: ["en"],
registrations: Keyword.get(instance, :registrations_open),
approval_required: Keyword.get(instance, :account_approval_required),
avatar_upload_limit: Keyword.get(instance, :avatar_upload_limit),
background_upload_limit: Keyword.get(instance, :background_upload_limit),
banner_upload_limit: Keyword.get(instance, :banner_upload_limit),
- background_image: Pleroma.Web.base_url() <> Keyword.get(instance, :background_image),
- chat_limit: Keyword.get(instance, :chat_limit),
+ background_image: Pleroma.Web.Endpoint.url() <> Keyword.get(instance, :background_image),
+ shout_limit: Config.get([:shout, :limit]),
description_limit: Keyword.get(instance, :description_limit),
pleroma: %{
metadata: %{
if Config.get([:gopher, :enabled]) do
"gopher"
end,
- if Config.get([:chat, :enabled]) do
+ # backwards compat
+ if Config.get([:shout, :enabled]) do
"chat"
end,
+ if Config.get([:shout, :enabled]) do
+ "shout"
+ end,
if Config.get([:instance, :allow_relay]) do
"relay"
end,
def build_tags(object_tags) when is_list(object_tags) do
object_tags
|> Enum.filter(&is_binary/1)
- |> Enum.map(&%{name: &1, url: "#{Pleroma.Web.base_url()}/tag/#{URI.encode(&1)}"})
+ |> Enum.map(&%{name: &1, url: "#{Pleroma.Web.Endpoint.url()}/tag/#{URI.encode(&1)}"})
end
def build_tags(_), do: []
alias Pleroma.Config
alias Pleroma.Helpers.UriHelper
alias Pleroma.Upload
- alias Pleroma.Web
+ alias Pleroma.Web.Endpoint
alias Pleroma.Web.MediaProxy.Invalidation
@base64_opts [padding: false]
# non-local non-whitelisted URLs through it and be sure that body size constraint is preserved.
def preview_enabled?, do: enabled?() and !!Config.get([:media_preview_proxy, :enabled])
- def local?(url), do: String.starts_with?(url, Web.base_url())
+ def local?(url), do: String.starts_with?(url, Endpoint.url())
def whitelisted?(url) do
%{host: domain} = URI.parse(url)
end
defp signed_url(url) do
- :crypto.hmac(:sha, Config.get([Web.Endpoint, :secret_key_base]), url)
+ :crypto.mac(:hmac, :sha, Config.get([Endpoint, :secret_key_base]), url)
end
def filename(url_or_path) do
end
def base_url do
- Config.get([:media_proxy, :base_url], Web.base_url())
+ Config.get([:media_proxy, :base_url], Endpoint.url())
end
defp proxy_url(path, sig_base64, url_base64, filename) do
defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
use Pleroma.Web, :controller
- alias Pleroma.Web
+ alias Pleroma.Web.Endpoint
alias Pleroma.Web.Nodeinfo.Nodeinfo
def schemas(conn, _params) do
links: [
%{
rel: "http://nodeinfo.diaspora.software/ns/schema/2.0",
- href: Web.base_url() <> "/nodeinfo/2.0.json"
+ href: Endpoint.url() <> "/nodeinfo/2.0.json"
},
%{
rel: "http://nodeinfo.diaspora.software/ns/schema/2.1",
- href: Web.base_url() <> "/nodeinfo/2.1.json"
+ href: Endpoint.url() <> "/nodeinfo/2.1.json"
}
]
}
"""
@behaviour Plug
- @api_routes Pleroma.Web.Router.get_api_routes()
-
def file_path(path, frontend_type \\ :primary) do
if configuration = Pleroma.Config.get([:frontends, frontend_type]) do
instance_static_path = Pleroma.Config.get([:instance, :static_dir], "instance/static")
defp invalid_path?([h | t], match), do: String.contains?(h, match) or invalid_path?(t)
defp invalid_path?([], _match), do: false
- defp api_route?([h | _]) when h in @api_routes, do: true
- defp api_route?([_ | t]), do: api_route?(t)
defp api_route?([]), do: false
+ defp api_route?([h | t]) do
+ api_routes = Pleroma.Web.Router.get_api_routes()
+ if h in api_routes, do: true, else: api_route?(t)
+ end
+
defp call_static(conn, opts, from) do
opts = Map.put(opts, :from, from)
Plug.Static.call(conn, opts)
get("/oauth_tokens", TwitterAPI.Controller, :oauth_tokens)
delete("/oauth_tokens/:id", TwitterAPI.Controller, :revoke_token)
-
- post(
- "/qvitter/statuses/notifications/read",
- TwitterAPI.Controller,
- :mark_notifications_as_read
- )
end
scope "/", Pleroma.Web do
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.ChatChannel do
+defmodule Pleroma.Web.ShoutChannel do
use Phoenix.Channel
alias Pleroma.User
- alias Pleroma.Web.ChatChannel.ChatChannelState
alias Pleroma.Web.MastodonAPI.AccountView
+ alias Pleroma.Web.ShoutChannel.ShoutChannelState
def join("chat:public", _message, socket) do
send(self(), :after_join)
end
def handle_info(:after_join, socket) do
- push(socket, "messages", %{messages: ChatChannelState.messages()})
+ push(socket, "messages", %{messages: ShoutChannelState.messages()})
{:noreply, socket}
end
def handle_in("new_msg", %{"text" => text}, %{assigns: %{user_name: user_name}} = socket) do
text = String.trim(text)
- if String.length(text) in 1..Pleroma.Config.get([:instance, :chat_limit]) do
+ if String.length(text) in 1..Pleroma.Config.get([:shout, :limit]) do
author = User.get_cached_by_nickname(user_name)
author_json = AccountView.render("show.json", user: author, skip_visibility_check: true)
- message = ChatChannelState.add_message(%{text: text, author: author_json})
+ message = ShoutChannelState.add_message(%{text: text, author: author_json})
broadcast!(socket, "new_msg", message)
end
end
end
-defmodule Pleroma.Web.ChatChannel.ChatChannelState do
+defmodule Pleroma.Web.ShoutChannel.ShoutChannelState do
use Agent
@max_messages 20
<%= if id == Pleroma.Constants.as_public() do %>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<% else %>
- <%= unless Regex.match?(~r/^#{Pleroma.Web.base_url()}.+followers$/, id) do %>
+ <%= unless Regex.match?(~r/^#{Pleroma.Web.Endpoint.url()}.+followers$/, id) do %>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="<%= id %>"/>
<% end %>
<% end %>
<%= if id == Pleroma.Constants.as_public() do %>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection">http://activityschema.org/collection/public</link>
<% else %>
- <%= unless Regex.match?(~r/^#{Pleroma.Web.base_url()}.+followers$/, id) do %>
+ <%= unless Regex.match?(~r/^#{Pleroma.Web.Endpoint.url()}.+followers$/, id) do %>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person"><%= id %></link>
<% end %>
<% end %>
ostatus:object-type="http://activitystrea.ms/schema/1.0/collection"
href="http://activityschema.org/collection/public"/>
<% else %>
- <%= unless Regex.match?(~r/^#{Pleroma.Web.base_url()}.+followers$/, id) do %>
+ <%= unless Regex.match?(~r/^#{Pleroma.Web.Endpoint.url()}.+followers$/, id) do %>
<link rel="mentioned"
ostatus:object-type="http://activitystrea.ms/schema/1.0/person"
href="<%= id %>" />
<h2>Password reset failed</h2>
-<h3><a href="<%= Pleroma.Web.base_url() %>">Homepage</a></h3>
+<h3><a href="<%= Pleroma.Web.Endpoint.url() %>">Homepage</a></h3>
<h2>Password changed!</h2>
-<h3><a href="<%= Pleroma.Web.base_url() %>">Homepage</a></h3>
+<h3><a href="<%= Pleroma.Web.Endpoint.url() %>">Homepage</a></h3>
defmodule Pleroma.Web.TwitterAPI.Controller do
use Pleroma.Web, :controller
- alias Pleroma.Notification
alias Pleroma.User
alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug
require Logger
- plug(
- OAuthScopesPlug,
- %{scopes: ["write:notifications"]} when action == :mark_notifications_as_read
- )
-
plug(
:skip_plug,
[OAuthScopesPlug, EnsurePublicOrAuthenticatedPlug] when action == :confirm_email
|> put_resp_content_type("application/json")
|> send_resp(status, json)
end
-
- def mark_notifications_as_read(
- %{assigns: %{user: user}} = conn,
- %{"latest_id" => latest_id} = params
- ) do
- Notification.set_read_up_to(user, latest_id)
-
- notifications = Notification.for_user(user, params)
-
- conn
- # XXX: This is a hack because pleroma-fe still uses that API.
- |> put_view(Pleroma.Web.MastodonAPI.NotificationView)
- |> render("index.json", %{notifications: notifications, for: user})
- end
-
- def mark_notifications_as_read(%{assigns: %{user: _user}} = conn, _) do
- bad_request_reply(conn, "You need to specify latest_id")
- end
-
- defp bad_request_reply(conn, error_message) do
- json = error_json(conn, error_message)
- json_reply(conn, 400, json)
- end
-
- defp error_json(conn, error_message) do
- %{"error" => error_message, "request" => conn.request_path} |> Jason.encode!()
- end
end
alias Pleroma.Config
alias Pleroma.Emoji
alias Pleroma.Healthcheck
- alias Pleroma.Notification
alias Pleroma.User
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Plugs.OAuthScopesPlug
alias Pleroma.Web.WebFinger
+ plug(Pleroma.Web.ApiSpec.CastAndValidate when action != :remote_subscribe)
plug(Pleroma.Web.Plugs.FederatingPlug when action == :remote_subscribe)
plug(
]
)
- plug(OAuthScopesPlug, %{scopes: ["write:notifications"]} when action == :notifications_read)
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TwitterUtilOperation
def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
with %User{} = user <- User.get_cached_by_nickname(nick),
end
end
- def notifications_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
- with {:ok, _} <- Notification.read_one(user, notification_id) do
- json(conn, %{status: "success"})
- else
- {:error, message} ->
- conn
- |> put_resp_content_type("application/json")
- |> send_resp(403, Jason.encode!(%{"error" => message}))
- end
- end
-
def frontend_configurations(conn, _params) do
render(conn, "frontend_configurations.json")
end
end
end
- def change_password(%{assigns: %{user: user}} = conn, params) do
- case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
+ def change_password(%{assigns: %{user: user}} = conn, %{
+ password: password,
+ new_password: new_password,
+ new_password_confirmation: new_password_confirmation
+ }) do
+ case CommonAPI.Utils.confirm_current_password(user, password) do
{:ok, user} ->
with {:ok, _user} <-
User.reset_password(user, %{
- password: params["new_password"],
- password_confirmation: params["new_password_confirmation"]
+ password: new_password,
+ password_confirmation: new_password_confirmation
}) do
json(conn, %{status: "success"})
else
end
end
- def change_email(%{assigns: %{user: user}} = conn, params) do
- case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
+ def change_email(%{assigns: %{user: user}} = conn, %{password: password, email: email}) do
+ case CommonAPI.Utils.confirm_current_password(user, password) do
{:ok, user} ->
- with {:ok, _user} <- User.change_email(user, params["email"]) do
+ with {:ok, _user} <- User.change_email(user, email) do
json(conn, %{status: "success"})
else
{:error, changeset} ->
end
def delete_account(%{assigns: %{user: user}} = conn, params) do
- password = params["password"] || ""
+ password = params[:password] || ""
case CommonAPI.Utils.confirm_current_password(user, password) do
{:ok, user} ->
end
def disable_account(%{assigns: %{user: user}} = conn, params) do
- case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
+ case CommonAPI.Utils.confirm_current_password(user, params[:password]) do
{:ok, user} ->
User.set_activation_async(user, false)
json(conn, %{status: "success"})
use Pleroma.Web, :view
import Phoenix.HTML.Form
alias Pleroma.Config
- alias Pleroma.Web
+ alias Pleroma.Web.Endpoint
def status_net_config(instance) do
"""
<config>
<site>
<name>#{Keyword.get(instance, :name)}</name>
- <site>#{Web.base_url()}</site>
+ <site>#{Endpoint.url()}</site>
<textlimit>#{Keyword.get(instance, :limit)}</textlimit>
<closed>#{!Keyword.get(instance, :registrations_open)}</closed>
</site>
--- /dev/null
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Utils.Guards do
+ @moduledoc """
+ Project-wide custom guards.
+ See: https://hexdocs.pm/elixir/master/patterns-and-guards.html#custom-patterns-and-guards-expressions
+ """
+
+ @doc "Checks for non-empty string"
+ defguard not_empty_string(string) when is_binary(string) and string != ""
+end
theme_color: Config.get([:manifest, :theme_color]),
background_color: Config.get([:manifest, :background_color]),
display: "standalone",
- scope: Pleroma.Web.base_url(),
+ scope: Pleroma.Web.Endpoint.url(),
start_url: Routes.masto_fe_path(Pleroma.Web.Endpoint, :index, ["getting-started"]),
categories: [
"social"
defmodule Pleroma.Web.WebFinger do
alias Pleroma.HTTP
alias Pleroma.User
- alias Pleroma.Web
+ alias Pleroma.Web.Endpoint
alias Pleroma.Web.Federator.Publisher
alias Pleroma.Web.XML
alias Pleroma.XmlBuilder
require Logger
def host_meta do
- base_url = Web.base_url()
+ base_url = Endpoint.url()
{
:XRD,
{:tesla, "~> 1.4.0", override: true},
{:castore, "~> 0.1"},
{:cowlib, "~> 2.9", override: true},
- {:gun,
- github: "ninenines/gun", ref: "921c47146b2d9567eac7e9a4d2ccc60fffd4f327", override: true},
+ {:gun, "~> 2.0.0-rc.1", override: true},
{:jason, "~> 1.2"},
{:mogrify, "~> 0.7.4"},
{:ex_aws, "~> 2.1.6"},
git: "https://git.pleroma.social/pleroma/elixir-libraries/crypt.git",
ref: "cf2aa3f11632e8b0634810a15b3e612c7526f6a3"},
{:cors_plug, "~> 2.0"},
- {:web_push_encryption, "~> 0.3"},
+ {:web_push_encryption,
+ git: "https://github.com/lanodan/elixir-web-push-encryption.git", branch: "bugfix/otp-24"},
{:swoosh, "~> 1.0"},
{:phoenix_swoosh, "~> 0.3"},
{:gen_smtp, "~> 0.13"},
{:quack, "~> 0.1.1"},
{:joken, "~> 2.0"},
{:benchee, "~> 1.0"},
- {:pot, "~> 0.11"},
+ {:pot, "~> 1.0"},
{:esshd, "~> 0.1.0", runtime: Application.get_env(:esshd, :enabled, false)},
{:ex_const, "~> 0.2"},
{:plug_static_index_html, "~> 1.0.0"},
{:mock, "~> 0.3.5", only: :test},
# temporary downgrade for excoveralls, hackney until hackney max_connections bug will be fixed
{:excoveralls, "0.12.3", only: :test},
- {:hackney,
- git: "https://git.pleroma.social/pleroma/elixir-libraries/hackney.git",
- ref: "7d7119f0651515d6d7669c78393fd90950a3ec6e",
- override: true},
+ {:hackney, "~> 1.17.0", override: true},
{:mox, "~> 1.0", only: :test},
{:websocket_client, git: "https://github.com/jeremyong/websocket_client.git", only: :test}
] ++ oauth_deps()
%{
"accept": {:hex, :accept, "0.3.5", "b33b127abca7cc948bbe6caa4c263369abf1347cfa9d8e699c6d214660f10cd1", [:rebar3], [], "hexpm", "11b18c220bcc2eab63b5470c038ef10eb6783bcb1fcdb11aa4137defa5ac1bb8"},
- "base62": {:hex, :base62, "1.2.1", "4866763e08555a7b3917064e9eef9194c41667276c51b59de2bc42c6ea65f806", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm", "3b29948de2013d3f93aa898c884a9dff847e7aec75d9d6d8c1dc4c61c2716c42"},
+ "base62": {:hex, :base62, "1.2.2", "85c6627eb609317b70f555294045895ffaaeb1758666ab9ef9ca38865b11e629", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm", "d41336bda8eaa5be197f1e4592400513ee60518e5b9f4dcf38f4b4dae6f377bb"},
"base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"},
"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"},
- "bcrypt_elixir": {:hex, :bcrypt_elixir, "2.2.0", "3df902b81ce7fa8867a2ae30d20a1da6877a2c056bfb116fd0bc8a5f0190cea4", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "762be3fcb779f08207531bc6612cca480a338e4b4357abb49f5ce00240a77d1e"},
+ "bcrypt_elixir": {:hex, :bcrypt_elixir, "2.3.0", "6cb662d5c1b0a8858801cf20997bd006e7016aa8c52959c9ef80e0f34fb60b7a", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2c81d61d4f6ed0e5cf7bf27a9109b791ff216a1034b3d541327484f46dd43769"},
"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"},
+ "cachex": {:hex, :cachex, "3.3.0", "6f2ebb8f27491fe39121bd207c78badc499214d76c695658b19d6079beeca5c2", [: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", "d90e5ee1dde14cef33f6b187af4335b88748b72b30c038969176cd4e6ccc31a1"},
"calendar": {:hex, :calendar, "1.0.0", "f52073a708528482ec33d0a171954ca610fe2bd28f1e871f247dc7f1565fa807", [:mix], [{:tzdata, "~> 0.5.20 or ~> 0.1.201603 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "990e9581920c82912a5ee50e62ff5ef96da6b15949a2ee4734f935fdef0f0a6f"},
"captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "e0f16822d578866e186a0974d65ad58cddc1e2ab", [ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"]},
- "castore": {:hex, :castore, "0.1.7", "1ca19eee705cde48c9e809e37fdd0730510752cc397745e550f6065a56a701e9", [:mix], [], "hexpm", "a2ae2c13d40e9c308387f1aceb14786dca019ebc2a11484fb2a9f797ea0aa0d8"},
- "certifi": {:git, "https://github.com/certifi/erlang-certifi", "e08b12e8993502240c25b78563993776f87ecd2a", [tag: "2.5.1"]},
+ "castore": {:hex, :castore, "0.1.10", "b01a007416a0ae4188e70b3b306236021b16c11474038ead7aff79dd75538c23", [:mix], [], "hexpm", "a48314e0cb45682db2ea27b8ebfa11bd6fa0a6e21a65e5772ad83ca136ff2665"},
+ "certifi": {:hex, :certifi, "2.6.1", "dbab8e5e155a0763eea978c913ca280a6b544bfa115633fa20249c3d396d9493", [:rebar3], [], "hexpm", "524c97b4991b3849dd5c17a631223896272c6b0af446778ba4675a1dff53bb7e"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
- "comeonin": {:hex, :comeonin, "5.3.1", "7fe612b739c78c9c1a75186ef2d322ce4d25032d119823269d0aa1e2f1e20025", [:mix], [], "hexpm", "d6222483060c17f0977fad1b7401ef0c5863c985a64352755f366aee3799c245"},
+ "comeonin": {:hex, :comeonin, "5.3.2", "5c2f893d05c56ae3f5e24c1b983c2d5dfb88c6d979c9287a76a7feb1e1d8d646", [:mix], [], "hexpm", "d0993402844c49539aeadb3fe46a3c9bd190f1ecf86b6f9ebd71957534c95f04"},
"concurrent_limiter": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/concurrent_limiter.git", "d81be41024569330f296fc472e24198d7499ba78", [ref: "d81be41024569330f296fc472e24198d7499ba78"]},
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
- "cors_plug": {:hex, :cors_plug, "2.0.2", "2b46083af45e4bc79632bd951550509395935d3e7973275b2b743bd63cc942ce", [:mix], [{:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f0d0e13f71c51fd4ef8b2c7e051388e4dfb267522a83a22392c856de7e46465f"},
- "cowboy": {:hex, :cowboy, "2.8.0", "f3dc62e35797ecd9ac1b50db74611193c29815401e53bac9a5c0577bd7bc667d", [:rebar3], [{:cowlib, "~> 2.9.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "4643e4fba74ac96d4d152c75803de6fad0b3fa5df354c71afdd6cbeeb15fac8a"},
- "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.0", "69fdb5cf92df6373e15675eb4018cf629f5d8e35e74841bb637d6596cb797bbc", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "42868c229d9a2900a1501c5d0355bfd46e24c862c322b0b4f5a6f14fe0216753"},
- "cowlib": {:hex, :cowlib, "2.9.1", "61a6c7c50cf07fdd24b2f45b89500bb93b6686579b069a89f88cb211e1125c78", [:rebar3], [], "hexpm", "e4175dc240a70d996156160891e1c62238ede1729e45740bdd38064dad476170"},
- "credo": {:hex, :credo, "1.4.1", "16392f1edd2cdb1de9fe4004f5ab0ae612c92e230433968eab00aafd976282fc", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "155f8a2989ad77504de5d8291fa0d41320fdcaa6a1030472e9967f285f8c7692"},
+ "cors_plug": {:hex, :cors_plug, "2.0.3", "316f806d10316e6d10f09473f19052d20ba0a0ce2a1d910ddf57d663dac402ae", [:mix], [{:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ee4ae1418e6ce117fc42c2ba3e6cbdca4e95ecd2fe59a05ec6884ca16d469aea"},
+ "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
+ "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"},
+ "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
+ "credo": {:hex, :credo, "1.5.5", "e8f422026f553bc3bebb81c8e8bf1932f498ca03339856c7fec63d3faac8424b", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "dd8623ab7091956a855dc9f3062486add9c52d310dfd62748779c4315d8247de"},
"crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
"crypt": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/crypt.git", "cf2aa3f11632e8b0634810a15b3e612c7526f6a3", [ref: "cf2aa3f11632e8b0634810a15b3e612c7526f6a3"]},
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
- "db_connection": {:hex, :db_connection, "2.3.1", "4c9f3ed1ef37471cbdd2762d6655be11e38193904d9c5c1c9389f1b891a3088e", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "abaab61780dde30301d840417890bd9f74131041afd02174cf4e10635b3a63f5"},
+ "db_connection": {:hex, :db_connection, "2.4.0", "d04b1b73795dae60cead94189f1b8a51cc9e1f911c234cc23074017c43c031e5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad416c21ad9f61b3103d254a71b63696ecadb6a917b36f563921e0de00d7d7c8"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
"earmark": {:hex, :earmark, "1.4.15", "2c7f924bf495ec1f65bd144b355d0949a05a254d0ec561740308a54946a67888", [:mix], [{:earmark_parser, ">= 1.4.13", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "3b1209b85bc9f3586f370f7c363f6533788fb4e51db23aa79565875e7f9999ee"},
"eimp": {:hex, :eimp, "1.0.14", "fc297f0c7e2700457a95a60c7010a5f1dcb768a083b6d53f49cd94ab95a28f22", [:rebar3], [{:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "501133f3112079b92d9e22da8b88bf4f0e13d4d67ae9c15c42c30bd25ceb83b6"},
"elixir_make": {:hex, :elixir_make, "0.6.2", "7dffacd77dec4c37b39af867cedaabb0b59f6a871f89722c25b28fcd4bd70530", [:mix], [], "hexpm", "03e49eadda22526a7e5279d53321d1cced6552f344ba4e03e619063de75348d9"},
"esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"},
- "eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm", "b14f1dc204321429479c569cfbe8fb287541184ed040956c8862cb7a677b8406"},
+ "eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"},
"ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"},
- "ex_aws": {:hex, :ex_aws, "2.1.6", "41ab8b4caa48035c96d07faa035d2d9de6df480e7e084c054e662ac888dcd4d4", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "a541bd042c1ee26412bb1e749ddf2a1c327e4fb7e382b1cd227e1b00eed3d469"},
- "ex_aws_s3": {:hex, :ex_aws_s3, "2.0.2", "c0258bbdfea55de4f98f0b2f0ca61fe402cc696f573815134beb1866e778f47b", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "0569f5b211b1a3b12b705fe2a9d0e237eb1360b9d76298028df2346cad13097a"},
+ "ex_aws": {:hex, :ex_aws, "2.1.9", "dc4865ecc20a05190a34a0ac5213e3e5e2b0a75a0c2835e923ae7bfeac5e3c31", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "3e6c776703c9076001fbe1f7c049535f042cb2afa0d2cbd3b47cbc4e92ac0d10"},
+ "ex_aws_s3": {:hex, :ex_aws_s3, "2.2.0", "07a09de557070320e264893c0acc8a1d2e7ddf80155736e0aed966486d1988e6", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "15175c613371e29e1f88b78ec8a4327389ca1ec5b34489744b175727496b21bd"},
"ex_const": {:hex, :ex_const, "0.2.4", "d06e540c9d834865b012a17407761455efa71d0ce91e5831e86881b9c9d82448", [:mix], [], "hexpm", "96fd346610cc992b8f896ed26a98be82ac4efb065a0578f334a32d60a3ba9767"},
- "ex_doc": {:hex, :ex_doc, "0.22.2", "03a2a58bdd2ba0d83d004507c4ee113b9c521956938298eba16e55cc4aba4a6c", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "cf60e1b3e2efe317095b6bb79651f83a2c1b3edcb4d319c421d7fcda8b3aff26"},
- "ex_machina": {:hex, :ex_machina, "2.4.0", "09a34c5d371bfb5f78399029194a8ff67aff340ebe8ba19040181af35315eabb", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "a20bc9ddc721b33ea913b93666c5d0bdca5cbad7a67540784ae277228832d72c"},
+ "ex_doc": {:hex, :ex_doc, "0.24.2", "e4c26603830c1a2286dae45f4412a4d1980e1e89dc779fcd0181ed1d5a05c8d9", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "e134e1d9e821b8d9e4244687fb2ace58d479b67b282de5158333b0d57c6fb7da"},
+ "ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"},
"ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"},
"excoveralls": {:hex, :excoveralls, "0.12.3", "2142be7cb978a3ae78385487edda6d1aff0e482ffc6123877bb7270a8ffbcfe0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "568a3e616c264283f5dea5b020783ae40eef3f7ee2163f7a67cbd7b35bcadada"},
"fast_html": {:hex, :fast_html, "2.0.4", "4910ee49f2f6b19692e3bf30bf97f1b6b7dac489cd6b0f34cd0fe3042c56ba30", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "3bb49d541dfc02ad5e425904f53376d758c09f89e521afc7d2b174b3227761ea"},
"fast_sanitize": {:hex, :fast_sanitize, "0.2.2", "3cbbaebaea6043865dfb5b4ecb0f1af066ad410a51470e353714b10c42007b81", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "69f204db9250afa94a0d559d9110139850f57de2b081719fbafa1e9a89e94466"},
+ "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"},
- "floki": {:hex, :floki, "0.27.0", "6b29a14283f1e2e8fad824bc930eaa9477c462022075df6bea8f0ad811c13599", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "583b8c13697c37179f1f82443bcc7ad2f76fbc0bf4c186606eebd658f7f2631b"},
+ "floki": {:hex, :floki, "0.30.1", "75d35526d3a1459920b6e87fdbc2e0b8a3670f965dd0903708d2b267e0904c55", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "e9c03524447d1c4cbfccd672d739b8c18453eee377846b119d4fd71b1a176bb8"},
"gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"},
"gen_stage": {:hex, :gen_stage, "0.14.3", "d0c66f1c87faa301c1a85a809a3ee9097a4264b2edf7644bf5c123237ef732bf", [:mix], [], "hexpm"},
"gen_state_machine": {:hex, :gen_state_machine, "2.0.5", "9ac15ec6e66acac994cc442dcc2c6f9796cf380ec4b08267223014be1c728a95", [:mix], [], "hexpm"},
"gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"},
- "gun": {:git, "https://github.com/ninenines/gun.git", "921c47146b2d9567eac7e9a4d2ccc60fffd4f327", [ref: "921c47146b2d9567eac7e9a4d2ccc60fffd4f327"]},
- "hackney": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/hackney.git", "7d7119f0651515d6d7669c78393fd90950a3ec6e", [ref: "7d7119f0651515d6d7669c78393fd90950a3ec6e"]},
- "html_entities": {:hex, :html_entities, "0.5.1", "1c9715058b42c35a2ab65edc5b36d0ea66dd083767bef6e3edb57870ef556549", [:mix], [], "hexpm", "30efab070904eb897ff05cd52fa61c1025d7f8ef3a9ca250bc4e6513d16c32de"},
+ "gun": {:hex, :gun, "2.0.0-rc.2", "7c489a32dedccb77b6e82d1f3c5a7dadfbfa004ec14e322cdb5e579c438632d2", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "6b9d1eae146410d727140dbf8b404b9631302ecc2066d1d12f22097ad7d254fc"},
+ "hackney": {:hex, :hackney, "1.17.4", "99da4674592504d3fb0cfef0db84c3ba02b4508bae2dff8c0108baa0d6e0977c", [:rebar3], [{:certifi, "~>2.6.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "de16ff4996556c8548d512f4dbe22dd58a587bf3332e7fd362430a7ef3986b16"},
+ "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
"html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
"http_signatures": {:hex, :http_signatures, "0.1.0", "4e4b501a936dbf4cb5222597038a89ea10781776770d2e185849fa829686b34c", [:mix], [], "hexpm", "f8a7b3731e3fd17d38fa6e343fcad7b03d6874a3b0a108c8568a71ed9c2cf824"},
- "httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "aa2c74bd271af34239a3948779612f87df2422c2fdcfdbcec28d9c105f0773fe"},
- "idna": {:git, "https://github.com/benoitc/erlang-idna", "6cff72747821110169ecfac871b0c69e5064afff", [tag: "6.0.0"]},
+ "httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"},
+ "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"},
"jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"},
- "joken": {:hex, :joken, "2.2.0", "2daa1b12be05184aff7b5ace1d43ca1f81345962285fff3f88db74927c954d3a", [:mix], [{:jose, "~> 1.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "b4f92e30388206f869dd25d1af628a1d99d7586e5cf0672f64d4df84c4d2f5e9"},
- "jose": {:hex, :jose, "1.10.1", "16d8e460dae7203c6d1efa3f277e25b5af8b659febfc2f2eb4bacf87f128b80a", [:mix, :rebar3], [], "hexpm", "3c7ddc8a9394b92891db7c2771da94bf819834a1a4c92e30857b7d582e2f8257"},
+ "joken": {:hex, :joken, "2.3.0", "62a979c46f2c81dcb8ddc9150453b60d3757d1ac393c72bb20fc50a7b0827dc6", [:mix], [{:jose, "~> 1.10", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "57b263a79c0ec5d536ac02d569c01e6b4de91bd1cb825625fe90eab4feb7bc1e"},
+ "jose": {:hex, :jose, "1.11.1", "59da64010c69aad6cde2f5b9248b896b84472e99bd18f246085b7b9fe435dcdb", [:mix, :rebar3], [], "hexpm", "078f6c9fb3cd2f4cfafc972c814261a7d1e8d2b3685c0a76eb87e158efff1ac5"},
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},
"libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"},
"linkify": {:hex, :linkify, "0.5.0", "e0ea8de73ff44742d6a889721221f4c4eccaad5284957ee9832ffeb347602d54", [:mix], [], "hexpm", "4ccd958350aee7c51c89e21f05b15d30596ebbba707e051d21766be1809df2d7"},
"majic": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/majic.git", "289cda1b6d0d70ccb2ba508a2b0bd24638db2880", [ref: "289cda1b6d0d70ccb2ba508a2b0bd24638db2880"]},
- "makeup": {:hex, :makeup, "1.0.3", "e339e2f766d12e7260e6672dd4047405963c5ec99661abdc432e6ec67d29ef95", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "2e9b4996d11832947731f7608fed7ad2f9443011b3b479ae288011265cdd3dad"},
+ "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
"makeup_elixir": {:hex, :makeup_elixir, "0.14.1", "4f0e96847c63c17841d42c08107405a005a2680eb9c7ccadfd757bd31dabccfb", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f2438b1a80eaec9ede832b5c41cd4f373b38fd7aa33e3b22d9db79e640cbde11"},
- "meck": {:hex, :meck, "0.8.13", "ffedb39f99b0b99703b8601c6f17c7f76313ee12de6b646e671e3188401f7866", [:rebar3], [], "hexpm", "d34f013c156db51ad57cc556891b9720e6a1c1df5fe2e15af999c84d6cebeb1a"},
- "metrics": {:git, "https://github.com/benoitc/erlang-metrics", "c6eb4dcf29f9e907539915e2ab996f40c2ec7e8e", [tag: "1.0.1"]},
- "mime": {:hex, :mime, "1.4.0", "5066f14944b470286146047d2f73518cf5cca82f8e4815cf35d196b58cf07c47", [:mix], [], "hexpm", "75fa42c4228ea9a23f70f123c74ba7cece6a03b1fd474fe13f6a7a85c6ea4ff6"},
- "mimerl": {:git, "https://github.com/benoitc/mimerl", "5a1b22a8fada5b3b40438da00a6923cb87a42bbc", [tag: "1.2.0"]},
+ "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
+ "meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"},
+ "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
+ "mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"},
+ "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"},
- "mock": {:hex, :mock, "0.3.5", "feb81f52b8dcf0a0d65001d2fec459f6b6a8c22562d94a965862f6cc066b5431", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "6fae404799408300f863550392635d8f7e3da6b71abdd5c393faf41b131c8728"},
+ "mock": {:hex, :mock, "0.3.7", "75b3bbf1466d7e486ea2052a73c6e062c6256fb429d6797999ab02fa32f29e03", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "4da49a4609e41fd99b7836945c26f373623ea968cfb6282742bcb94440cf7e5c"},
"mogrify": {:hex, :mogrify, "0.7.4", "9b2496dde44b1ce12676f85d7dc531900939e6367bc537c7243a1b089435b32d", [:mix], [], "hexpm", "50d79e337fba6bc95bfbef918058c90f50b17eed9537771e61d4619488f099c3"},
"mox": {:hex, :mox, "1.0.0", "4b3c7005173f47ff30641ba044eb0fe67287743eec9bd9545e37f3002b0a9f8b", [:mix], [], "hexpm", "201b0a20b7abdaaab083e9cf97884950f8a30a1350a1da403b3145e213c6f4df"},
"myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]},
- "nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"},
+ "nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm", "5c040b8469c1ff1b10093d3186e2e10dbe483cd73d79ec017993fb3985b8a9b3"},
"nimble_pool": {:hex, :nimble_pool, "0.1.0", "ffa9d5be27eee2b00b0c634eb649aa27f97b39186fec3c493716c2a33e784ec6", [:mix], [], "hexpm", "343a1eaa620ddcf3430a83f39f2af499fe2370390d4f785cd475b4df5acaf3f9"},
"nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
"oban": {:hex, :oban, "2.3.4", "ec7509b9af2524d55f529cb7aee93d36131ae0bf0f37706f65d2fe707f4d9fd8", [:mix], [{:ecto_sql, ">= 3.4.3", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c70ca0434758fd1805422ea4446af5e910ddc697c0c861549c8f0eb0cfbd2fdf"},
"open_api_spex": {:hex, :open_api_spex, "3.10.0", "94e9521ad525b3fcf6dc77da7c45f87fdac24756d4de588cb0816b413e7c1844", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.1", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm", "2dbb2bde3d2b821f06936e8dfaf3284331186556291946d84eeba3750ac28765"},
"p1_utils": {:hex, :p1_utils, "1.0.18", "3fe224de5b2e190d730a3c5da9d6e8540c96484cf4b4692921d1e28f0c32b01c", [:rebar3], [], "hexpm", "1fc8773a71a15553b179c986b22fbeead19b28fe486c332d4929700ffeb71f88"},
- "parse_trans": {:git, "https://github.com/uwiger/parse_trans.git", "76abb347c3c1d00fb0ccf9e4b43e22b3d2288484", [tag: "3.3.0"]},
+ "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"pbkdf2_elixir": {:hex, :pbkdf2_elixir, "1.2.1", "9cbe354b58121075bd20eb83076900a3832324b7dd171a6895fab57b6bb2752c", [:mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}], "hexpm", "d3b40a4a4630f0b442f19eca891fcfeeee4c40871936fed2f68e1c4faa30481f"},
- "phoenix": {:hex, :phoenix, "1.5.6", "8298cdb4e0f943242ba8410780a6a69cbbe972fef199b341a36898dd751bdd66", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0dc4d39af1306b6aa5122729b0a95ca779e42c708c6fe7abbb3d336d5379e956"},
+ "phoenix": {:hex, :phoenix, "1.5.9", "a6368d36cfd59d917b37c44386e01315bc89f7609a10a45a22f47c007edf2597", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7e4bce20a67c012f1fbb0af90e5da49fa7bf0d34e3a067795703b74aef75427d"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.2.1", "13f124cf0a3ce0f1948cf24654c7b9f2347169ff75c1123f44674afee6af3b03", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 2.15", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "478a1bae899cac0a6e02be1deec7e2944b7754c04e7d4107fc5a517f877743c0"},
- "phoenix_html": {:hex, :phoenix_html, "2.14.2", "b8a3899a72050f3f48a36430da507dd99caf0ac2d06c77529b1646964f3d563e", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "58061c8dfd25da5df1ea0ca47c972f161beb6c875cd293917045b92ffe1bf617"},
+ "phoenix_html": {:hex, :phoenix_html, "2.14.3", "51f720d0d543e4e157ff06b65de38e13303d5778a7919bcc696599e5934271b8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "efd697a7fff35a13eeeb6b43db884705cba353a1a41d127d118fda5f90c8e80f"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"},
- "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.3.2", "43d3518349a22b8b1910ea28b4dd5119926d5017b3187db3fbd1a1e05769a851", [:mix], [{:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.0", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "3e2ac4e883db7af0702d75ba00c19901760e8342b91f8f66e13941de552e777f"},
- "plug": {:hex, :plug, "1.10.4", "41eba7d1a2d671faaf531fa867645bd5a3dce0957d8e2a3f398ccff7d2ef017f", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad1e233fe73d2eec56616568d260777b67f53148a999dc2d048f4eb9778fe4a0"},
- "plug_cowboy": {:hex, :plug_cowboy, "2.4.0", "e936ef151751f386804c51f87f7300f5aaae6893cdad726559c3930c6c032948", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e25ddcfc06b1b76e55af79d078b03cbc86bbcb99ce4e5e0a5e4a8114ee039be6"},
- "plug_crypto": {:hex, :plug_crypto, "1.2.0", "1cb20793aa63a6c619dd18bb33d7a3aa94818e5fd39ad357051a67f26dfa2df6", [:mix], [], "hexpm", "a48b538ae8bf381ffac344520755f3007cc10bd8e90b240af98ea29b69683fc2"},
+ "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.3.3", "039435dd975f7e55953525b88f1d596f26c6141412584c16f4db109708a8ee68", [:mix], [{:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.0", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "4a540cea32e05356541737033d666ee7fea7700eb2101bf76783adbfe06601cd"},
+ "plug": {:hex, :plug, "1.11.1", "f2992bac66fdae679453c9e86134a4201f6f43a687d8ff1cd1b2862d53c80259", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "23524e4fefbb587c11f0833b3910bfb414bf2e2534d61928e920f54e3a1b881f"},
+ "plug_cowboy": {:hex, :plug_cowboy, "2.5.0", "51c998f788c4e68fc9f947a5eba8c215fbb1d63a520f7604134cab0270ea6513", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5b2c8925a5e2587446f33810a58c01e66b3c345652eeec809b76ba007acde71a"},
+ "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"},
"plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm", "fec8660eb7733ee4117b85f55799fd3833eb769a6df71ccf8903e8dc5447cfce"},
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
- "postgrex": {:hex, :postgrex, "0.15.7", "724410acd48abac529d0faa6c2a379fb8ae2088e31247687b16cacc0e0883372", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "88310c010ff047cecd73d5ceca1d99205e4b1ab1b9abfdab7e00f5c9d20ef8f9"},
- "pot": {:hex, :pot, "0.11.0", "61bad869a94534739dd4614a25a619bc5c47b9970e9a0ea5bef4628036fc7a16", [:rebar3], [], "hexpm", "57ee6ee6bdeb639661ffafb9acefe3c8f966e45394de6a766813bb9e1be4e54b"},
- "prometheus": {:hex, :prometheus, "4.6.0", "20510f381db1ccab818b4cf2fac5fa6ab5cc91bc364a154399901c001465f46f", [:mix, :rebar3], [], "hexpm", "4905fd2992f8038eccd7aa0cd22f40637ed618c0bed1f75c05aacec15b7545de"},
+ "postgrex": {:hex, :postgrex, "0.15.9", "46f8fe6f25711aeb861c4d0ae09780facfdf3adbd2fb5594ead61504dd489bda", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "610719103e4cb2223d4ab78f9f0f3e720320eeca6011415ab4137ddef730adee"},
+ "pot": {:hex, :pot, "1.0.1", "81b511b1fa7c3123171c265cb7065a1528cebd7277b0cbc94257c50a8b2e4c17", [:rebar3], [], "hexpm", "ed87f5976531d91528452faa1138a5328db7f9f20d8feaae15f5051f79bcfb6d"},
+ "prometheus": {:hex, :prometheus, "4.8.0", "1ce1e1002b173c336d61f186b56263346536e76814edd9a142e12aeb2d6c1ad2", [:mix, :rebar3], [], "hexpm", "0fc2e17103073edb3758a46a5d44b006191bf25b73cbaa2b779109de396afcb5"},
"prometheus_ecto": {:hex, :prometheus_ecto, "1.4.3", "3dd4da1812b8e0dbee81ea58bb3b62ed7588f2eae0c9e97e434c46807ff82311", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "8d66289f77f913b37eda81fd287340c17e61a447549deb28efc254532b2bed82"},
"prometheus_ex": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/prometheus.ex.git", "a4e9beb3c1c479d14b352fd9d6dd7b1f6d7deee5", [ref: "a4e9beb3c1c479d14b352fd9d6dd7b1f6d7deee5"]},
"prometheus_phoenix": {:hex, :prometheus_phoenix, "1.3.0", "c4b527e0b3a9ef1af26bdcfbfad3998f37795b9185d475ca610fe4388fdd3bb5", [:mix], [{:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "c4d1404ac4e9d3d963da601db2a7d8ea31194f0017057fabf0cfb9bf5a6c8c75"},
"prometheus_phx": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/prometheus-phx.git", "9cd8f248c9381ffedc799905050abce194a97514", [branch: "no-logging"]},
"prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm", "0273a6483ccb936d79ca19b0ab629aef0dba958697c94782bb728b920dfc6a79"},
"quack": {:hex, :quack, "0.1.1", "cca7b4da1a233757fdb44b3334fce80c94785b3ad5a602053b7a002b5a8967bf", [:mix], [{:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: false]}, {:tesla, "~> 1.2.0", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "d736bfa7444112eb840027bb887832a0e403a4a3437f48028c3b29a2dbbd2543"},
- "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"},
+ "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"recon": {:hex, :recon, "2.5.1", "430ffa60685ac1efdfb1fe4c97b8767c92d0d92e6e7c3e8621559ba77598678a", [:mix, :rebar3], [], "hexpm", "5721c6b6d50122d8f68cccac712caa1231f97894bab779eff5ff0f886cb44648"},
"remote_ip": {:git, "https://git.pleroma.social/pleroma/remote_ip.git", "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8", [ref: "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8"]},
"sleeplocks": {:hex, :sleeplocks, "1.1.1", "3d462a0639a6ef36cc75d6038b7393ae537ab394641beb59830a1b8271faeed3", [:rebar3], [], "hexpm", "84ee37aeff4d0d92b290fff986d6a95ac5eedf9b383fadfd1d88e9b84a1c02e1"},
- "ssl_verify_fun": {:git, "https://github.com/deadtrickster/ssl_verify_fun.erl", "c5718226b0b9f3d1a38ef6ca3c3b4c75f53dda92", [tag: "1.1.4"]},
+ "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm", "2e1ec458f892ffa81f9f8386e3f35a1af6db7a7a37748a64478f13163a1f3573"},
- "swoosh": {:hex, :swoosh, "1.0.6", "6765e334c67dacabe721f0d701c7e5a6f06e4595c90df6f91e73ebd54d555833", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "7c50ef78e4acfd1cbd4907dc1fa87b5540675a6be9dc979d04890f49d7ec1830"},
+ "swoosh": {:hex, :swoosh, "1.3.11", "34f79c57f19892b43bd2168de9ff5de478a721a26328ef59567aad4243e7a77b", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "f1e2a048db454f9982b9cf840f75e7399dd48be31ecc2a7dc10012a803b913af"},
"syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"},
- "telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"},
- "tesla": {:hex, :tesla, "1.4.0", "1081bef0124b8bdec1c3d330bbe91956648fb008cf0d3950a369cda466a31a87", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.3", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "bf1374a5569f5fca8e641363b63f7347d680d91388880979a33bc12a6eb3e0aa"},
- "timex": {:hex, :timex, "3.7.3", "df8a2ea814749d700d6878ab9eacac9fdb498ecee2f507cb0002ec172bc24d0f", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8691c1d86ca3a7bc14a156e2199dc8927be95d1a8f0e3b69e4bb2d6262c53ac6"},
+ "telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"},
+ "tesla": {:hex, :tesla, "1.4.1", "ff855f1cac121e0d16281b49e8f066c4a0d89965f98864515713878cca849ac8", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.3", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "95f5de35922c8c4b3945bee7406f66eb680b0955232f78f5fb7e853aa1ce201a"},
+ "timex": {:hex, :timex, "3.7.5", "3eca56e23bfa4e0848f0b0a29a92fa20af251a975116c6d504966e8a90516dfd", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "a15608dca680f2ef663d71c95842c67f0af08a0f3b1d00e17bbd22872e2874e4"},
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"},
"tzdata": {:hex, :tzdata, "1.0.5", "69f1ee029a49afa04ad77801febaf69385f3d3e3d1e4b56b9469025677b89a28", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "55519aa2a99e5d2095c1e61cc74c9be69688f8ab75c27da724eb8279ff402a5a"},
"ueberauth": {:hex, :ueberauth, "0.6.3", "d42ace28b870e8072cf30e32e385579c57b9cc96ec74fa1f30f30da9c14f3cc0", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "afc293d8a1140d6591b53e3eaf415ca92842cb1d32fad3c450c6f045f7f91b60"},
- "unicode_util_compat": {:git, "https://github.com/benoitc/unicode_util_compat.git", "38d7bc105f51159e8ea3279c40121db9db1e652f", [tag: "0.3.1"]},
+ "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
"unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"},
- "web_push_encryption": {:hex, :web_push_encryption, "0.3.0", "598b5135e696fd1404dc8d0d7c0fa2c027244a4e5d5e5a98ba267f14fdeaabc8", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "f10bdd1afe527ede694749fb77a2f22f146a51b054c7fa541c9fd920fba7c875"},
+ "web_push_encryption": {:git, "https://github.com/lanodan/elixir-web-push-encryption.git", "026a043037a89db4da8f07560bc8f9c68bcf0cc0", [branch: "bugfix/otp-24"]},
"websocket_client": {:git, "https://github.com/jeremyong/websocket_client.git", "9a6f65d05ebf2725d62fb19262b21f1805a59fbf", []},
}
--- /dev/null
+defmodule Pleroma.Repo.Migrations.RenameInstanceChat do
+ use Ecto.Migration
+
+ alias Pleroma.ConfigDB
+
+ @instance_params %{group: :pleroma, key: :instance}
+ @shout_params %{group: :pleroma, key: :shout}
+ @chat_params %{group: :pleroma, key: :chat}
+
+ def up do
+ instance_updated? = maybe_update_instance_key(:up) != :noop
+ chat_updated? = maybe_update_chat_key(:up) != :noop
+
+ case Enum.any?([instance_updated?, chat_updated?]) do
+ true -> :ok
+ false -> :noop
+ end
+ end
+
+ def down do
+ instance_updated? = maybe_update_instance_key(:down) != :noop
+ chat_updated? = maybe_update_chat_key(:down) != :noop
+
+ case Enum.any?([instance_updated?, chat_updated?]) do
+ true -> :ok
+ false -> :noop
+ end
+ end
+
+ # pleroma.instance.chat_limit -> pleroma.shout.limit
+ defp maybe_update_instance_key(:up) do
+ with %ConfigDB{value: values} <- ConfigDB.get_by_params(@instance_params),
+ limit when is_integer(limit) <- values[:chat_limit] do
+ @shout_params |> Map.put(:value, limit: limit) |> ConfigDB.update_or_create()
+ @instance_params |> Map.put(:subkeys, [":chat_limit"]) |> ConfigDB.delete()
+ else
+ _ ->
+ :noop
+ end
+ end
+
+ # pleroma.shout.limit -> pleroma.instance.chat_limit
+ defp maybe_update_instance_key(:down) do
+ with %ConfigDB{value: values} <- ConfigDB.get_by_params(@shout_params),
+ limit when is_integer(limit) <- values[:limit] do
+ @instance_params |> Map.put(:value, chat_limit: limit) |> ConfigDB.update_or_create()
+ @shout_params |> Map.put(:subkeys, [":limit"]) |> ConfigDB.delete()
+ else
+ _ ->
+ :noop
+ end
+ end
+
+ # pleroma.chat.enabled -> pleroma.shout.enabled
+ defp maybe_update_chat_key(:up) do
+ with %ConfigDB{value: values} <- ConfigDB.get_by_params(@chat_params),
+ enabled? when is_boolean(enabled?) <- values[:enabled] do
+ @shout_params |> Map.put(:value, enabled: enabled?) |> ConfigDB.update_or_create()
+ @chat_params |> Map.put(:subkeys, [":enabled"]) |> ConfigDB.delete()
+ else
+ _ ->
+ :noop
+ end
+ end
+
+ # pleroma.shout.enabled -> pleroma.chat.enabled
+ defp maybe_update_chat_key(:down) do
+ with %ConfigDB{value: values} <- ConfigDB.get_by_params(@shout_params),
+ enabled? when is_boolean(enabled?) <- values[:enabled] do
+ @chat_params |> Map.put(:value, enabled: enabled?) |> ConfigDB.update_or_create()
+ @shout_params |> Map.put(:subkeys, [":enabled"]) |> ConfigDB.delete()
+ else
+ _ ->
+ :noop
+ end
+ end
+end
--- /dev/null
+defmodule Pleroma.Repo.Migrations.DeleteHashtagsObjectsCascade do
+ use Ecto.Migration
+
+ def up do
+ execute("ALTER TABLE hashtags_objects DROP CONSTRAINT hashtags_objects_object_id_fkey")
+
+ alter table(:hashtags_objects) do
+ modify(:object_id, references(:objects, on_delete: :delete_all))
+ end
+ end
+
+ def down do
+ execute("ALTER TABLE hashtags_objects DROP CONSTRAINT hashtags_objects_object_id_fkey")
+
+ alter table(:hashtags_objects) do
+ modify(:object_id, references(:objects, on_delete: :nothing))
+ end
+ end
+end
"type": "Create",
"object": {
"type": "Note",
+ "to": ["https://www.w3.org/ns/activitystreams#Public"],
"content": "It's a note"
},
"to": ["https://www.w3.org/ns/activitystreams#Public"]
defmodule Fixtures.Modules.GoodMRF do
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
@impl true
def filter(a), do: {:ok, a}
"type" => "Note",
"content" => "find me!",
"id" => "http://mastodon.example.org/users/admin/objects/1",
- "attributedTo" => "http://mastodon.example.org/users/admin"
+ "attributedTo" => "http://mastodon.example.org/users/admin",
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"]
},
"to" => ["https://www.w3.org/ns/activitystreams#Public"]
}
{:ok, japanese_activity} = Pleroma.Web.CommonAPI.post(user, %{status: "更新情報"})
{:ok, job} = Pleroma.Web.Federator.incoming_ap_doc(params)
{:ok, remote_activity} = ObanHelpers.perform(job)
+ remote_activity = Activity.get_by_id_with_object(remote_activity.id)
%{
japanese_activity: japanese_activity,
"Your config is using old setting name `timeout` instead of `recv_timeout` in pool settings"
end
end
+
+ test "check_old_chat_shoutbox/0" do
+ clear_config([:instance, :chat_limit], 1_000)
+ clear_config([:chat, :enabled], true)
+
+ assert capture_log(fn ->
+ DeprecationWarnings.check_old_chat_shoutbox()
+ end) =~
+ "Your config is using the old namespace for the Shoutbox configuration."
+ end
end
end
test "on reboot time key" do
- clear_config(:chat)
- insert(:config, key: :chat, value: [enabled: false])
+ clear_config(:shout)
+ insert(:config, key: :shout, value: [enabled: false])
assert capture_log(fn -> TransferTask.start_link([]) end) =~ "pleroma restarted"
end
end
test "don't restart pleroma on reboot time key and subkey if there is false flag" do
- clear_config(:chat)
+ clear_config(:shout)
clear_config(Pleroma.Captcha)
- insert(:config, key: :chat, value: [enabled: false])
+ insert(:config, key: :shout, value: [enabled: false])
insert(:config, key: Pleroma.Captcha, value: [seconds_valid: 60])
refute String.contains?(
alias Pleroma.EctoType.ActivityPub.ObjectValidators.Recipients
use Pleroma.DataCase, async: true
- test "it asserts that all elements of the list are object ids" do
+ test "it only keeps elements that are valid object ids" do
list = ["https://lain.com/users/lain", "invalid"]
- assert :error == Recipients.cast(list)
+ assert {:ok, ["https://lain.com/users/lain"]} == Recipients.cast(list)
end
test "it works with a list" do
describe "add_param/4" do
test "add file parameter" do
- %Request{
- body: %Tesla.Multipart{
- boundary: _,
- content_type_params: [],
- parts: [
- %Tesla.Multipart.Part{
- body: %File.Stream{
- line_or_bytes: 2048,
- modes: [:raw, :read_ahead, :read, :binary],
- path: "some-path/filename.png",
- raw: true
- },
- dispositions: [name: "filename.png", filename: "filename.png"],
- headers: []
- }
- ]
- }
- } = RequestBuilder.add_param(%Request{}, :file, "filename.png", "some-path/filename.png")
+ assert match?(
+ %Request{
+ body: %Tesla.Multipart{
+ boundary: _,
+ content_type_params: [],
+ parts: [
+ %Tesla.Multipart.Part{
+ body: %File.Stream{
+ line_or_bytes: 2048,
+ modes: [:raw, :read_ahead, :binary],
+ path: "some-path/filename.png",
+ raw: true
+ },
+ dispositions: [name: "filename.png", filename: "filename.png"],
+ headers: []
+ }
+ ]
+ }
+ },
+ RequestBuilder.add_param(
+ %Request{},
+ :file,
+ "filename.png",
+ "some-path/filename.png"
+ )
+ )
end
test "add key to body" do
"actor" => user.ap_id,
"object" => %{
"type" => "Note",
+ "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
"content" => "message with a Mention tag, but no explicit tagging",
"tag" => [
%{
"actor" => user.ap_id,
"object" => %{
"type" => "Note",
+ "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [other_user.ap_id],
"content" => "hi everyone",
"attributedTo" => user.ap_id
}
"cc" => [],
"object" => %{
"type" => "Note",
+ "id" => remote_user.ap_id <> "/objects/test",
"content" => "Hello!",
"tag" => [
%{
%Tesla.Env{
status: 500
}
+
+ %{
+ method: :get,
+ url: "https://stereophonic.space/objects/02997b83-3ea7-4b63-94af-ef3aa2d4ed17"
+ } ->
+ %Tesla.Env{
+ status: 500
+ }
end)
:ok
{:ok, object} =
Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
- assert activity = Activity.get_create_by_object_ap_id(object.data["id"])
- assert activity.data["id"]
+ assert _activity = Activity.get_create_by_object_ap_id(object.data["id"])
{:ok, object_again} =
Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
--- /dev/null
+defmodule Pleroma.Repo.Migrations.RenameInstanceChatTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+ import Pleroma.Tests.Helpers
+ alias Pleroma.ConfigDB
+
+ setup do: clear_config([:instance])
+ setup do: clear_config([:chat])
+ setup_all do: require_migration("20200806175913_rename_instance_chat")
+
+ describe "up/0" do
+ test "migrates chat settings to shout", %{migration: migration} do
+ insert(:config, group: :pleroma, key: :instance, value: [chat_limit: 6000])
+ insert(:config, group: :pleroma, key: :chat, value: [enabled: true])
+
+ assert migration.up() == :ok
+
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :chat}) == nil
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :instance}) == nil
+
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :shout}).value == [
+ limit: 6000,
+ enabled: true
+ ]
+ end
+
+ test "does nothing when chat settings are not set", %{migration: migration} do
+ assert migration.up() == :noop
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :chat}) == nil
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :shout}) == nil
+ end
+ end
+
+ describe "down/0" do
+ test "migrates shout settings back to instance and chat", %{migration: migration} do
+ insert(:config, group: :pleroma, key: :shout, value: [limit: 42, enabled: true])
+
+ assert migration.down() == :ok
+
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :chat}).value == [enabled: true]
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :instance}).value == [chat_limit: 42]
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :shout}) == nil
+ end
+
+ test "does nothing when shout settings are not set", %{migration: migration} do
+ assert migration.down() == :noop
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :chat}) == nil
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :instance}) == nil
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :shout}) == nil
+ end
+ end
+end
test "ap_id returns the activity pub id for the user" do
user = UserBuilder.build()
- expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
+ expected_ap_id = "#{Pleroma.Web.Endpoint.url()}/users/#{user.nickname}"
assert expected_ap_id == User.ap_id(user)
end
File.read!("test/fixtures/mastodon-post-activity.json")
|> Jason.decode!()
|> Map.put("actor", user.ap_id)
- |> put_in(["object", "attridbutedTo"], user.ap_id)
+ |> put_in(["object", "attributedTo"], user.ap_id)
conn =
conn
test "it inserts an incoming activity into the database", %{conn: conn, data: data} do
user = insert(:user)
- data = Map.put(data, "bcc", [user.ap_id])
+
+ data =
+ data
+ |> Map.put("bcc", [user.ap_id])
+ |> Kernel.put_in(["object", "bcc"], [user.ap_id])
conn =
conn
user = insert(:user)
data =
- Map.put(data, "to", user.ap_id)
- |> Map.delete("cc")
+ data
+ |> Map.put("to", user.ap_id)
+ |> Map.put("cc", [])
+ |> Kernel.put_in(["object", "to"], user.ap_id)
+ |> Kernel.put_in(["object", "cc"], [])
conn =
conn
user = insert(:user)
data =
- Map.put(data, "cc", user.ap_id)
- |> Map.delete("to")
+ data
+ |> Map.put("to", [])
+ |> Map.put("cc", user.ap_id)
+ |> Kernel.put_in(["object", "to"], [])
+ |> Kernel.put_in(["object", "cc"], user.ap_id)
conn =
conn
user = insert(:user)
data =
- Map.put(data, "bcc", user.ap_id)
- |> Map.delete("to")
- |> Map.delete("cc")
+ data
+ |> Map.put("to", [])
+ |> Map.put("cc", [])
+ |> Map.put("bcc", user.ap_id)
+ |> Kernel.put_in(["object", "to"], [])
+ |> Kernel.put_in(["object", "cc"], [])
+ |> Kernel.put_in(["object", "bcc"], user.ap_id)
conn =
conn
assert Instances.reachable?(sender_host)
end
+ @tag capture_log: true
test "it removes all follower collections but actor's", %{conn: conn} do
[actor, recipient] = insert_pair(:user)
- data =
- File.read!("test/fixtures/activitypub-client-post-activity.json")
- |> Jason.decode!()
+ to = [
+ recipient.ap_id,
+ recipient.follower_address,
+ "https://www.w3.org/ns/activitystreams#Public"
+ ]
- object = Map.put(data["object"], "attributedTo", actor.ap_id)
+ cc = [recipient.follower_address, actor.follower_address]
- data =
- data
- |> Map.put("id", Utils.generate_object_id())
- |> Map.put("actor", actor.ap_id)
- |> Map.put("object", object)
- |> Map.put("cc", [
- recipient.follower_address,
- actor.follower_address
- ])
- |> Map.put("to", [
- recipient.ap_id,
- recipient.follower_address,
- "https://www.w3.org/ns/activitystreams#Public"
- ])
+ data = %{
+ "@context" => ["https://www.w3.org/ns/activitystreams"],
+ "type" => "Create",
+ "id" => Utils.generate_activity_id(),
+ "to" => to,
+ "cc" => cc,
+ "actor" => actor.ap_id,
+ "object" => %{
+ "type" => "Note",
+ "to" => to,
+ "cc" => cc,
+ "content" => "It's a note",
+ "attributedTo" => actor.ap_id,
+ "id" => Utils.generate_object_id()
+ }
+ }
conn
|> assign(:valid_signature, true)
ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
- activity = Activity.get_by_ap_id(data["id"])
+ assert activity = Activity.get_by_ap_id(data["id"])
assert activity.id
assert actor.follower_address in activity.recipients
"actor" => remote_actor,
"content" => "test report",
"id" => "https://#{remote_domain}/e3b12fd1-948c-446e-b93b-a5e67edbe1d8",
- "nickname" => reported_user.nickname,
"object" => [
reported_user.ap_id,
note.data["object"]
defp build_local_message do
%{
- "actor" => "#{Pleroma.Web.base_url()}/users/alice",
+ "actor" => "#{Pleroma.Web.Endpoint.url()}/users/alice",
"to" => [],
"cc" => []
}
},
%{
"rel" => "http://ostatus.org/schema/1.0/subscribe",
- "template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}"
+ "template" => "#{Pleroma.Web.Endpoint.url()}/ostatus_subscribe?acct={uri}"
}
]
"actor" => "http://mastodon.example.org/users/admin",
"object" => %{
"type" => "Audio",
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [],
"id" => "http://mastodon.example.org/users/admin/listens/1234",
"attributedTo" => "http://mastodon.example.org/users/admin",
"title" => "lain radio episode 1",
assert object.data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
- assert object.data["cc"] == []
+ assert object.data["cc"] == [
+ "https://channels.tests.funkwhale.audio/federation/actors/compositions/followers"
+ ]
assert object.data["url"] == "https://channels.tests.funkwhale.audio/library/tracks/74"
)
assert object.data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
- assert object.data["cc"] == []
+ assert object.data["cc"] == ["https://mobilizon.org/@tcit/followers"]
assert object.data["url"] ==
"https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Transmogrifier
+ alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI
import Mock
import Pleroma.Factory
- import ExUnit.CaptureLog
setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
assert Object.hashtags(object) == ["test"]
end
- test "it cleans up incoming notices which are not really DMs" do
- user = insert(:user)
- other_user = insert(:user)
-
- to = [user.ap_id, other_user.ap_id]
-
- data =
- File.read!("test/fixtures/mastodon-post-activity.json")
- |> Jason.decode!()
- |> Map.put("to", to)
- |> Map.put("cc", [])
-
- object =
- data["object"]
- |> Map.put("to", to)
- |> Map.put("cc", [])
-
- data = Map.put(data, "object", object)
-
- {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
-
- assert data["to"] == []
- assert data["cc"] == to
-
- object_data = Object.normalize(activity, fetch: false).data
-
- assert object_data["to"] == []
- assert object_data["cc"] == to
- end
-
test "it ignores an incoming notice if we already have it" do
activity = insert(:note_activity)
data
|> Map.put("object", object)
- assert capture_log(fn ->
- {:ok, _returned_activity} = Transmogrifier.handle_incoming(data)
- end) =~ "[warn] Couldn't fetch \"https://404.site/whatever\", error: nil"
+ assert {:ok, _returned_activity} = Transmogrifier.handle_incoming(data)
end
test "it does not work for deactivated users" do
assert data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
assert data["cc"] == [
- "http://mastodon.example.org/users/admin/followers",
- "http://localtesting.pleroma.lol/users/lain"
+ "http://localtesting.pleroma.lol/users/lain",
+ "http://mastodon.example.org/users/admin/followers"
]
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert object_data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
assert object_data["cc"] == [
- "http://mastodon.example.org/users/admin/followers",
- "http://localtesting.pleroma.lol/users/lain"
+ "http://localtesting.pleroma.lol/users/lain",
+ "http://mastodon.example.org/users/admin/followers"
]
assert object_data["actor"] == "http://mastodon.example.org/users/admin"
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
object = Object.normalize(data["object"], fetch: false)
- assert Enum.at(Object.tags(object), 2) == "moo"
- assert Object.hashtags(object) == ["moo"]
+ assert match?(
+ %{
+ "href" => "http://localtesting.pleroma.lol/users/lain",
+ "name" => "@lain@localtesting.pleroma.lol",
+ "type" => "Mention"
+ },
+ Enum.at(object.data["tag"], 0)
+ )
+
+ assert match?(
+ %{
+ "href" => "http://mastodon.example.org/tags/moo",
+ "name" => "#moo",
+ "type" => "Hashtag"
+ },
+ Enum.at(object.data["tag"], 1)
+ )
+
+ assert "moo" == Enum.at(object.data["tag"], 2)
end
test "it works for incoming notices with contentMap" do
File.read!("test/fixtures/mastodon-post-activity.json")
|> Jason.decode!()
|> Map.put("actor", user.ap_id)
- |> Map.put("to", nil)
|> Map.put("cc", nil)
object =
data["object"]
|> Map.put("attributedTo", user.ap_id)
- |> Map.put("to", nil)
|> Map.put("cc", nil)
|> Map.put("id", user.ap_id <> "/activities/12345678")
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
- assert !is_nil(data["to"])
- assert !is_nil(data["cc"])
+ refute is_nil(data["cc"])
end
test "it strips internal likes" do
object = Map.put(data["object"], "likes", likes)
data = Map.put(data, "object", object)
- {:ok, %Activity{object: object}} = Transmogrifier.handle_incoming(data)
+ {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(data)
+
+ object = Object.normalize(activity)
- refute Map.has_key?(object.data, "likes")
+ assert object.data["likes"] == []
end
test "it strips internal reactions" do
end
test "it correctly processes messages with non-array to field" do
- user = insert(:user)
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Poison.decode!()
+ |> Map.put("to", "https://www.w3.org/ns/activitystreams#Public")
+ |> put_in(["object", "to"], "https://www.w3.org/ns/activitystreams#Public")
- message = %{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "to" => "https://www.w3.org/ns/activitystreams#Public",
- "type" => "Create",
- "object" => %{
- "content" => "blah blah blah",
- "type" => "Note",
- "attributedTo" => user.ap_id,
- "inReplyTo" => nil
- },
- "actor" => user.ap_id
- }
+ assert {:ok, activity} = Transmogrifier.handle_incoming(data)
- assert {:ok, activity} = Transmogrifier.handle_incoming(message)
+ assert [
+ "http://localtesting.pleroma.lol/users/lain",
+ "http://mastodon.example.org/users/admin/followers"
+ ] == activity.data["cc"]
assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"]
end
test "it correctly processes messages with non-array cc field" do
- user = insert(:user)
-
- message = %{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "to" => user.follower_address,
- "cc" => "https://www.w3.org/ns/activitystreams#Public",
- "type" => "Create",
- "object" => %{
- "content" => "blah blah blah",
- "type" => "Note",
- "attributedTo" => user.ap_id,
- "inReplyTo" => nil
- },
- "actor" => user.ap_id
- }
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Poison.decode!()
+ |> Map.put("cc", "http://mastodon.example.org/users/admin/followers")
+ |> put_in(["object", "cc"], "http://mastodon.example.org/users/admin/followers")
- assert {:ok, activity} = Transmogrifier.handle_incoming(message)
+ assert {:ok, activity} = Transmogrifier.handle_incoming(data)
- assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"]
- assert [user.follower_address] == activity.data["to"]
+ assert ["http://mastodon.example.org/users/admin/followers"] == activity.data["cc"]
+ assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"]
end
test "it correctly processes messages with weirdness in address fields" do
- user = insert(:user)
-
- message = %{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "to" => [nil, user.follower_address],
- "cc" => ["https://www.w3.org/ns/activitystreams#Public", ["¿"]],
- "type" => "Create",
- "object" => %{
- "content" => "…",
- "type" => "Note",
- "attributedTo" => user.ap_id,
- "inReplyTo" => nil
- },
- "actor" => user.ap_id
- }
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Poison.decode!()
+ |> Map.put("cc", ["http://mastodon.example.org/users/admin/followers", ["¿"]])
+ |> put_in(["object", "cc"], ["http://mastodon.example.org/users/admin/followers", ["¿"]])
- assert {:ok, activity} = Transmogrifier.handle_incoming(message)
+ assert {:ok, activity} = Transmogrifier.handle_incoming(data)
- assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"]
- assert [user.follower_address] == activity.data["to"]
+ assert ["http://mastodon.example.org/users/admin/followers"] == activity.data["cc"]
+ assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"]
end
end
} do
clear_config([:instance, :federation_incoming_replies_max_depth], 10)
- {:ok, _activity} = Transmogrifier.handle_incoming(data)
+ {:ok, activity} = Transmogrifier.handle_incoming(data)
+
+ object = Object.normalize(activity.data["object"])
+
+ assert object.data["replies"] == items
for id <- items do
job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1}
setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
setup do
- user = insert(:user)
-
- {:ok, activity} = CommonAPI.post(user, %{status: "post1"})
-
- {:ok, reply1} =
- CommonAPI.post(user, %{status: "reply1", in_reply_to_status_id: activity.id})
-
- {:ok, reply2} =
- CommonAPI.post(user, %{status: "reply2", in_reply_to_status_id: activity.id})
-
- replies_uris = Enum.map([reply1, reply2], fn a -> a.object.data["id"] end)
-
- {:ok, federation_output} = Transmogrifier.prepare_outgoing(activity.data)
+ replies = %{
+ "type" => "Collection",
+ "items" => [Utils.generate_object_id(), Utils.generate_object_id()]
+ }
- Repo.delete(activity.object)
- Repo.delete(activity)
+ activity =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Poison.decode!()
+ |> Kernel.put_in(["object", "replies"], replies)
- %{federation_output: federation_output, replies_uris: replies_uris}
+ %{activity: activity}
end
test "schedules background fetching of `replies` items if max thread depth limit allows", %{
- federation_output: federation_output,
- replies_uris: replies_uris
+ activity: activity
} do
clear_config([:instance, :federation_incoming_replies_max_depth], 1)
- {:ok, _activity} = Transmogrifier.handle_incoming(federation_output)
+ assert {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(activity)
+ object = Object.normalize(data["object"])
- for id <- replies_uris do
+ for id <- object.data["replies"] do
job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1}
assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args)
end
end
test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows",
- %{federation_output: federation_output} do
+ %{activity: activity} do
clear_config([:instance, :federation_incoming_replies_max_depth], 0)
- {:ok, _activity} = Transmogrifier.handle_incoming(federation_output)
+ {:ok, _activity} = Transmogrifier.handle_incoming(activity)
assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == []
end
"object" => %{
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"cc" => [],
+ "id" => Utils.generate_object_id(),
"type" => "Note",
"content" => "Hi",
"inReplyTo" => nil,
"object" => %{
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"cc" => [],
+ "id" => Utils.generate_object_id(),
"type" => "Note",
"content" => "Hi",
"inReplyTo" => nil,
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Transmogrifier
+ alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.CommonAPI
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
{:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
- assert modified["@context"] ==
- Pleroma.Web.ActivityPub.Utils.make_json_ld_header()["@context"]
+ assert modified["@context"] == Utils.make_json_ld_header()["@context"]
assert modified["object"]["conversation"] == modified["context"]
end
end)
}
- fixed_object = Transmogrifier.fix_explicit_addressing(object)
+ fixed_object = Transmogrifier.fix_explicit_addressing(object, user.follower_address)
assert Enum.all?(explicitly_mentioned_actors, &(&1 in fixed_object["to"]))
refute "https://social.beepboop.ga/users/dirb" in fixed_object["to"]
assert "https://social.beepboop.ga/users/dirb" in fixed_object["cc"]
"cc" => []
}
- fixed_object = Transmogrifier.fix_explicit_addressing(object)
+ fixed_object = Transmogrifier.fix_explicit_addressing(object, user.follower_address)
assert user.follower_address in fixed_object["to"]
refute user.follower_address in fixed_object["cc"]
end
"cc" => [user.follower_address, recipient.follower_address]
}
- fixed_object = Transmogrifier.fix_explicit_addressing(object)
+ fixed_object = Transmogrifier.fix_explicit_addressing(object, user.follower_address)
assert user.follower_address in fixed_object["cc"]
refute recipient.follower_address in fixed_object["cc"]
end
test "saving config which need pleroma reboot", %{conn: conn} do
- clear_config([:chat, :enabled], true)
+ clear_config([:shout, :enabled], true)
assert conn
|> put_req_header("content-type", "application/json")
"/api/pleroma/admin/config",
%{
configs: [
- %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
+ %{group: ":pleroma", key: ":shout", value: [%{"tuple" => [":enabled", true]}]}
]
}
)
%{
"db" => [":enabled"],
"group" => ":pleroma",
- "key" => ":chat",
+ "key" => ":shout",
"value" => [%{"tuple" => [":enabled", true]}]
}
],
end
test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do
- clear_config([:chat, :enabled], true)
+ clear_config([:shout, :enabled], true)
assert conn
|> put_req_header("content-type", "application/json")
"/api/pleroma/admin/config",
%{
configs: [
- %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
+ %{group: ":pleroma", key: ":shout", value: [%{"tuple" => [":enabled", true]}]}
]
}
)
%{
"db" => [":enabled"],
"group" => ":pleroma",
- "key" => ":chat",
+ "key" => ":shout",
"value" => [%{"tuple" => [":enabled", true]}]
}
],
import Pleroma.Factory
- alias Pleroma.Web
+ alias Pleroma.Web.Endpoint
setup do
admin = insert(:user, is_admin: true)
end
test "success", %{conn: conn} do
- base_url = Web.base_url()
+ base_url = Endpoint.url()
app_name = "Trusted app"
response =
end
test "with trusted", %{conn: conn} do
- base_url = Web.base_url()
+ base_url = Endpoint.url()
app_name = "Trusted app"
response =
alias Pleroma.Repo
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
- alias Pleroma.Web
alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.Endpoint
alias Pleroma.Web.MediaProxy
setup_all do
end
test "pagination works correctly with service users", %{conn: conn} do
- service1 = User.get_or_create_service_actor_by_ap_id(Web.base_url() <> "/meido", "meido")
+ service1 = User.get_or_create_service_actor_by_ap_id(Endpoint.url() <> "/meido", "meido")
insert_list(25, :user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey :blank:"})
assert %{"blank" => url} = Object.normalize(activity).data["emoji"]
- assert url == "#{Pleroma.Web.base_url()}/emoji/blank.png"
+ assert url == "#{Pleroma.Web.Endpoint.url()}/emoji/blank.png"
end
test "it copies emoji from the subject of the parent post" do
spoiler_text: ":joker_smile:"
})
- assert Object.normalize(reply_activity).data["emoji"][":joker_smile:"]
- refute Object.normalize(reply_activity).data["emoji"][":joker_disapprove:"]
+ assert Object.normalize(reply_activity).data["emoji"]["joker_smile"]
+ refute Object.normalize(reply_activity).data["emoji"]["joker_disapprove"]
end
test "deactivated users can't post" do
"type" => "Note",
"content" => "hi world!",
"id" => "http://mastodon.example.org/users/admin/objects/1",
- "attributedTo" => "http://mastodon.example.org/users/admin"
+ "attributedTo" => "http://mastodon.example.org/users/admin",
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"]
},
"to" => ["https://www.w3.org/ns/activitystreams#Public"]
}
"type" => "Note",
"content" => "hi world!",
"id" => "http://mastodon.example.org/users/admin/objects/1",
- "attributedTo" => "http://mastodon.example.org/users/admin"
+ "attributedTo" => "http://mastodon.example.org/users/admin",
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"]
},
"to" => ["https://www.w3.org/ns/activitystreams#Public"]
}
"These are public toots tagged with #pleromaart. You can interact with them if you have an account anywhere in the fediverse."
assert xpath(xml, ~x"//channel/link/text()") ==
- '#{Pleroma.Web.base_url()}/tags/pleromaart.rss'
+ '#{Pleroma.Web.Endpoint.url()}/tags/pleromaart.rss'
assert xpath(xml, ~x"//channel/webfeeds:logo/text()") ==
- '#{Pleroma.Web.base_url()}/static/logo.svg'
+ '#{Pleroma.Web.Endpoint.url()}/static/logo.svg'
assert xpath(xml, ~x"//channel/item/title/text()"l) == [
'42 This is :moominmamm...',
|> get("/users/#{user.nickname}")
assert conn.status == 302
- assert redirected_to(conn) == "#{Pleroma.Web.base_url()}/users/#{user.nickname}/feed.atom"
+
+ assert redirected_to(conn) ==
+ "#{Pleroma.Web.Endpoint.url()}/users/#{user.nickname}/feed.atom"
end
test "with non-html / non-json format, it returns error when user is not found", %{conn: conn} do
{:ok, post_2} = CommonAPI.post(user, %{status: "second post"})
response_1 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1")
- assert [res] = json_response(response_1, 200)
+ assert [res] = json_response_and_validate_schema(response_1, 200)
assert res["id"] == post_2.id
response_2 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1&max_id=#{res["id"]}")
- assert [res] = json_response(response_2, 200)
+ assert [res] = json_response_and_validate_schema(response_2, 200)
assert res["id"] == post_1.id
refute response_1 == response_2
assert [] ==
conn
|> get("/api/v1/timelines/home")
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
assert %{"showing_reblogs" => true} =
conn
assert [%{"id" => ^reblog_id}] =
conn
|> get("/api/v1/timelines/home")
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
end
test "following with reblogs" do
assert [%{"id" => ^reblog_id}] =
conn
|> get("/api/v1/timelines/home")
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
assert %{"showing_reblogs" => false} =
conn
assert [] ==
conn
|> get("/api/v1/timelines/home")
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
end
test "following / unfollowing errors", %{user: user, conn: conn} do
res_conn = get(conn, "/api/v1/statuses/#{direct.id}/context")
- assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200)
+ assert %{"ancestors" => [], "descendants" => []} ==
+ json_response_and_validate_schema(res_conn, 200)
end
test "Removes a conversation", %{user: user_one, conn: conn} do
assert result = json_response_and_validate_schema(conn, 200)
email = Pleroma.Config.get([:instance, :email])
- thumbnail = Pleroma.Web.base_url() <> Pleroma.Config.get([:instance, :instance_thumbnail])
- background = Pleroma.Web.base_url() <> Pleroma.Config.get([:instance, :background_image])
+ thumbnail = Pleroma.Web.Endpoint.url() <> Pleroma.Config.get([:instance, :instance_thumbnail])
+ background = Pleroma.Web.Endpoint.url() <> Pleroma.Config.get([:instance, :background_image])
# Note: not checking for "max_toot_chars" since it's optional
assert %{
"background_upload_limit" => _,
"banner_upload_limit" => _,
"background_image" => from_config_background,
- "chat_limit" => _,
+ "shout_limit" => _,
"description_limit" => _
} = result
conn
|> get("/api/v1/media/#{object.id}")
- |> json_response(403)
+ |> json_response_and_validate_schema(403)
end
end
end
use Pleroma.Web.ConnCase
alias Pleroma.Object
- alias Pleroma.Web
alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.Endpoint
import Pleroma.Factory
import ExUnit.CaptureLog
import Tesla.Mock
assert account["id"] == to_string(user_three.id)
assert results["hashtags"] == [
- %{"name" => "private", "url" => "#{Web.base_url()}/tag/private"}
+ %{"name" => "private", "url" => "#{Endpoint.url()}/tag/private"}
]
[status] = results["statuses"]
|> json_response_and_validate_schema(200)
assert results["hashtags"] == [
- %{"name" => "天子", "url" => "#{Web.base_url()}/tag/天子"}
+ %{"name" => "天子", "url" => "#{Endpoint.url()}/tag/天子"}
]
[status] = results["statuses"]
|> json_response_and_validate_schema(200)
assert results["hashtags"] == [
- %{"name" => "explicit", "url" => "#{Web.base_url()}/tag/explicit"},
- %{"name" => "hashtags", "url" => "#{Web.base_url()}/tag/hashtags"}
+ %{"name" => "explicit", "url" => "#{Endpoint.url()}/tag/explicit"},
+ %{"name" => "hashtags", "url" => "#{Endpoint.url()}/tag/hashtags"}
]
results =
|> json_response_and_validate_schema(200)
assert results["hashtags"] == [
- %{"name" => "john", "url" => "#{Web.base_url()}/tag/john"},
- %{"name" => "doe", "url" => "#{Web.base_url()}/tag/doe"},
- %{"name" => "JohnDoe", "url" => "#{Web.base_url()}/tag/JohnDoe"}
+ %{"name" => "john", "url" => "#{Endpoint.url()}/tag/john"},
+ %{"name" => "doe", "url" => "#{Endpoint.url()}/tag/doe"},
+ %{"name" => "JohnDoe", "url" => "#{Endpoint.url()}/tag/JohnDoe"}
]
results =
|> json_response_and_validate_schema(200)
assert results["hashtags"] == [
- %{"name" => "accident", "url" => "#{Web.base_url()}/tag/accident"},
- %{"name" => "prone", "url" => "#{Web.base_url()}/tag/prone"},
- %{"name" => "AccidentProne", "url" => "#{Web.base_url()}/tag/AccidentProne"}
+ %{"name" => "accident", "url" => "#{Endpoint.url()}/tag/accident"},
+ %{"name" => "prone", "url" => "#{Endpoint.url()}/tag/prone"},
+ %{"name" => "AccidentProne", "url" => "#{Endpoint.url()}/tag/AccidentProne"}
]
results =
|> json_response_and_validate_schema(200)
assert results["hashtags"] == [
- %{"name" => "shpuld", "url" => "#{Web.base_url()}/tag/shpuld"}
+ %{"name" => "shpuld", "url" => "#{Endpoint.url()}/tag/shpuld"}
]
results =
|> json_response_and_validate_schema(200)
assert results["hashtags"] == [
- %{"name" => "nascar", "url" => "#{Web.base_url()}/tag/nascar"},
- %{"name" => "ban", "url" => "#{Web.base_url()}/tag/ban"},
- %{"name" => "display", "url" => "#{Web.base_url()}/tag/display"},
- %{"name" => "confederate", "url" => "#{Web.base_url()}/tag/confederate"},
- %{"name" => "flag", "url" => "#{Web.base_url()}/tag/flag"},
- %{"name" => "all", "url" => "#{Web.base_url()}/tag/all"},
- %{"name" => "events", "url" => "#{Web.base_url()}/tag/events"},
- %{"name" => "properties", "url" => "#{Web.base_url()}/tag/properties"},
+ %{"name" => "nascar", "url" => "#{Endpoint.url()}/tag/nascar"},
+ %{"name" => "ban", "url" => "#{Endpoint.url()}/tag/ban"},
+ %{"name" => "display", "url" => "#{Endpoint.url()}/tag/display"},
+ %{"name" => "confederate", "url" => "#{Endpoint.url()}/tag/confederate"},
+ %{"name" => "flag", "url" => "#{Endpoint.url()}/tag/flag"},
+ %{"name" => "all", "url" => "#{Endpoint.url()}/tag/all"},
+ %{"name" => "events", "url" => "#{Endpoint.url()}/tag/events"},
+ %{"name" => "properties", "url" => "#{Endpoint.url()}/tag/properties"},
%{
"name" => "NascarBanDisplayConfederateFlagAllEventsProperties",
"url" =>
- "#{Web.base_url()}/tag/NascarBanDisplayConfederateFlagAllEventsProperties"
+ "#{Endpoint.url()}/tag/NascarBanDisplayConfederateFlagAllEventsProperties"
}
]
end
|> json_response_and_validate_schema(200)
assert results["hashtags"] == [
- %{"name" => "text", "url" => "#{Web.base_url()}/tag/text"},
- %{"name" => "with", "url" => "#{Web.base_url()}/tag/with"}
+ %{"name" => "text", "url" => "#{Endpoint.url()}/tag/text"},
+ %{"name" => "with", "url" => "#{Endpoint.url()}/tag/with"}
]
end
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
"sensitive" => 0
})
+ # Idempotency plug response means detection fail
assert %{"id" => second_id} = json_response(conn_two, 200)
assert id == second_id
|> assign(:token, insert(:oauth_token, user: user3, scopes: ["read:statuses"]))
|> get("api/v1/timelines/home")
- [reblogged_activity] = json_response(conn3, 200)
+ [reblogged_activity] = json_response_and_validate_schema(conn3, 200)
assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
"visibility" => "local"
})
- local = Pleroma.Constants.as_local_public()
+ local = Utils.as_local_public()
assert %{"content" => "cofe", "id" => id, "visibility" => "local"} =
- json_response(conn_one, 200)
+ json_response_and_validate_schema(conn_one, 200)
assert %Activity{id: ^id, data: %{"to" => [^local]}} = Activity.get_by_id(id)
end
%{conn: auth_conn} = oauth_access(["read:statuses"])
res_conn = get(auth_conn, "#{base_uri}?local=true")
- assert length(json_response(res_conn, 200)) == 1
+ assert length(json_response_and_validate_schema(res_conn, 200)) == 1
res_conn = get(auth_conn, "#{base_uri}?local=false")
- assert length(json_response(res_conn, 200)) == 2
+ assert length(json_response_and_validate_schema(res_conn, 200)) == 2
end
test "with default settings on private instances, returns 403 for unauthenticated users", %{
for local <- [true, false] do
res_conn = get(conn, "#{base_uri}?local=#{local}")
- assert json_response(res_conn, :unauthorized) == error_response
+ assert json_response_and_validate_schema(res_conn, :unauthorized) == error_response
end
ensure_authenticated_access(base_uri)
for local <- [true, false] do
res_conn = get(conn, "#{base_uri}?local=#{local}")
- assert json_response(res_conn, :unauthorized) == error_response
+ assert json_response_and_validate_schema(res_conn, :unauthorized) == error_response
end
ensure_authenticated_access(base_uri)
clear_config([:restrict_unauthenticated, :timelines, :federated], true)
res_conn = get(conn, "#{base_uri}?local=true")
- assert length(json_response(res_conn, 200)) == 1
+ assert length(json_response_and_validate_schema(res_conn, 200)) == 1
res_conn = get(conn, "#{base_uri}?local=false")
- assert json_response(res_conn, :unauthorized) == error_response
+ assert json_response_and_validate_schema(res_conn, :unauthorized) == error_response
ensure_authenticated_access(base_uri)
end
clear_config([:restrict_unauthenticated, :timelines, :federated], false)
res_conn = get(conn, "#{base_uri}?local=true")
- assert json_response(res_conn, :unauthorized) == error_response
+ assert json_response_and_validate_schema(res_conn, :unauthorized) == error_response
# Note: local activities get delivered as part of federated timeline
res_conn = get(conn, "#{base_uri}?local=false")
- assert length(json_response(res_conn, 200)) == 2
+ assert length(json_response_and_validate_schema(res_conn, 200)) == 2
ensure_authenticated_access(base_uri)
end
|> assign(:token, insert(:oauth_token, user: user, scopes: ["write:accounts"]))
|> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
- assert _result = json_response(conn, 200)
+ assert %{} = json_response(conn, 200)
user = User.get_cached_by_ap_id(user.ap_id)
assert user.mastofe_settings == %{"programming" => "socks"}
AccountView.render("show.json", %{user: user, skip_visibility_check: true})
|> Enum.all?(fn
{key, url} when key in [:avatar, :avatar_static, :header, :header_static] ->
- String.starts_with?(url, Pleroma.Web.base_url())
+ String.starts_with?(url, Pleroma.Web.Endpoint.url())
{:emojis, emojis} ->
Enum.all?(emojis, fn %{url: url, static_url: static_url} ->
- String.starts_with?(url, Pleroma.Web.base_url()) &&
- String.starts_with?(static_url, Pleroma.Web.base_url())
+ String.starts_with?(url, Pleroma.Web.Endpoint.url()) &&
+ String.starts_with?(static_url, Pleroma.Web.Endpoint.url())
end)
_ ->
assert String.starts_with?(
encoded,
- Config.get([:media_proxy, :base_url], Pleroma.Web.base_url())
+ Config.get([:media_proxy, :base_url], Pleroma.Web.Endpoint.url())
)
assert String.ends_with?(encoded, "/logo.png")
|> response(200)
assert resp =~
- "<meta content=\"#{Pleroma.Web.base_url()}/notice/#{note_activity.id}\" property=\"og:url\">"
+ "<meta content=\"#{Pleroma.Web.Endpoint.url()}/notice/#{note_activity.id}\" property=\"og:url\">"
user = insert(:user)
assert %{"error" => "Insufficient permissions: follow | write:follows."} ==
json_response(conn, 403)
else
- assert json_response(conn, 200)
+ assert json_response_and_validate_schema(conn, 200)
end
end
end
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.ChatChannelTest do
+defmodule Pleroma.Web.ShoutChannelTest do
use Pleroma.Web.ChannelCase
- alias Pleroma.Web.ChatChannel
+ alias Pleroma.Web.ShoutChannel
alias Pleroma.Web.UserSocket
import Pleroma.Factory
{:ok, _, socket} =
socket(UserSocket, "", %{user_name: user.nickname})
- |> subscribe_and_join(ChatChannel, "chat:public")
+ |> subscribe_and_join(ShoutChannel, "shout:public")
{:ok, socket: socket}
end
end
describe "message lengths" do
- setup do: clear_config([:instance, :chat_limit])
+ setup do: clear_config([:shout, :limit])
test "it ignores messages of length zero", %{socket: socket} do
push(socket, "new_msg", %{"text" => ""})
end
test "it ignores messages above a certain length", %{socket: socket} do
- clear_config([:instance, :chat_limit], 2)
+ clear_config([:shout, :limit], 2)
push(socket, "new_msg", %{"text" => "123"})
refute_broadcast("new_msg", %{text: "123"})
end
alias Pleroma.Activity
alias Pleroma.Web.ActivityPub.Transmogrifier
+ alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
test "302 for remote cached status", %{conn: conn, user: user} do
message = %{
"@context" => "https://www.w3.org/ns/activitystreams",
- "to" => user.follower_address,
- "cc" => "https://www.w3.org/ns/activitystreams#Public",
"type" => "Create",
+ "actor" => user.ap_id,
"object" => %{
+ "to" => user.follower_address,
+ "cc" => "https://www.w3.org/ns/activitystreams#Public",
+ "id" => Utils.generate_object_id(),
"content" => "blah blah blah",
"type" => "Note",
- "attributedTo" => user.ap_id,
- "inReplyTo" => nil
- },
- "actor" => user.ap_id
+ "attributedTo" => user.ap_id
+ }
}
assert {:ok, activity} = Transmogrifier.handle_incoming(message)
alias Pleroma.Repo
alias Pleroma.User
- alias Pleroma.Web.CommonAPI
alias Pleroma.Web.OAuth.Token
import Pleroma.Factory
- describe "POST /api/qvitter/statuses/notifications/read" do
- test "without valid credentials", %{conn: conn} do
- conn = post(conn, "/api/qvitter/statuses/notifications/read", %{"latest_id" => 1_234_567})
- assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
- end
-
- test "with credentials, without any params" do
- %{conn: conn} = oauth_access(["write:notifications"])
-
- conn = post(conn, "/api/qvitter/statuses/notifications/read")
-
- assert json_response(conn, 400) == %{
- "error" => "You need to specify latest_id",
- "request" => "/api/qvitter/statuses/notifications/read"
- }
- end
-
- test "with credentials, with params" do
- %{user: current_user, conn: conn} =
- oauth_access(["read:notifications", "write:notifications"])
-
- other_user = insert(:user)
-
- {:ok, _activity} =
- CommonAPI.post(other_user, %{
- status: "Hey @#{current_user.nickname}"
- })
-
- response_conn =
- conn
- |> get("/api/v1/notifications")
-
- [notification] = json_response(response_conn, 200)
-
- assert notification["pleroma"]["is_seen"] == false
-
- response_conn =
- conn
- |> post("/api/qvitter/statuses/notifications/read", %{"latest_id" => notification["id"]})
-
- [notification] = response = json_response(response_conn, 200)
-
- assert length(response) == 1
-
- assert notification["pleroma"]["is_seen"] == true
- end
- end
-
describe "GET /api/account/confirm_email/:id/:token" do
setup do
{:ok, user} =
test "it updates notification settings", %{user: user, conn: conn} do
conn
- |> put("/api/pleroma/notification_settings", %{
- "block_from_strangers" => true,
- "bar" => 1
- })
- |> json_response(:ok)
+ |> put(
+ "/api/pleroma/notification_settings?#{
+ URI.encode_query(%{
+ block_from_strangers: true
+ })
+ }"
+ )
+ |> json_response_and_validate_schema(:ok)
user = refresh_record(user)
test "it updates notification settings to enable hiding contents", %{user: user, conn: conn} do
conn
- |> put("/api/pleroma/notification_settings", %{"hide_notification_contents" => "1"})
- |> json_response(:ok)
+ |> put(
+ "/api/pleroma/notification_settings?#{
+ URI.encode_query(%{
+ hide_notification_contents: 1
+ })
+ }"
+ )
+ |> json_response_and_validate_schema(:ok)
user = refresh_record(user)
response =
conn
|> get("/api/pleroma/frontend_configurations")
- |> json_response(:ok)
+ |> json_response_and_validate_schema(:ok)
assert response == Jason.encode!(config |> Enum.into(%{})) |> Jason.decode!()
end
emoji =
conn
|> get("/api/pleroma/emoji")
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
assert Enum.all?(emoji, fn
{_key,
response =
conn
|> get("/api/pleroma/healthcheck")
- |> json_response(503)
+ |> json_response_and_validate_schema(503)
assert response == %{}
end
response =
conn
|> get("/api/pleroma/healthcheck")
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
assert %{
"active" => _,
response =
conn
|> get("/api/pleroma/healthcheck")
- |> json_response(503)
+ |> json_response_and_validate_schema(503)
assert %{
"active" => _,
test "with valid permissions and password, it disables the account", %{conn: conn, user: user} do
response =
conn
- |> post("/api/pleroma/disable_account", %{"password" => "test"})
- |> json_response(:ok)
+ |> post("/api/pleroma/disable_account?password=test")
+ |> json_response_and_validate_schema(:ok)
assert response == %{"status" => "success"}
ObanHelpers.perform_all()
response =
conn
- |> post("/api/pleroma/disable_account", %{"password" => "test1"})
- |> json_response(:ok)
+ |> post("/api/pleroma/disable_account?password=test1")
+ |> json_response_and_validate_schema(:ok)
assert response == %{"error" => "Invalid password."}
user = User.get_cached_by_id(user.id)
conn =
conn
|> assign(:token, nil)
- |> post("/api/pleroma/change_email")
-
- assert json_response(conn, 403) == %{"error" => "Insufficient permissions: write:accounts."}
+ |> post(
+ "/api/pleroma/change_email?#{
+ URI.encode_query(%{password: "hi", email: "test@test.com"})
+ }"
+ )
+
+ assert json_response_and_validate_schema(conn, 403) == %{
+ "error" => "Insufficient permissions: write:accounts."
+ }
end
test "with proper permissions and invalid password", %{conn: conn} do
conn =
- post(conn, "/api/pleroma/change_email", %{
- "password" => "hi",
- "email" => "test@test.com"
- })
-
- assert json_response(conn, 200) == %{"error" => "Invalid password."}
+ post(
+ conn,
+ "/api/pleroma/change_email?#{
+ URI.encode_query(%{password: "hi", email: "test@test.com"})
+ }"
+ )
+
+ assert json_response_and_validate_schema(conn, 200) == %{"error" => "Invalid password."}
end
test "with proper permissions, valid password and invalid email", %{
conn: conn
} do
conn =
- post(conn, "/api/pleroma/change_email", %{
- "password" => "test",
- "email" => "foobar"
- })
+ post(
+ conn,
+ "/api/pleroma/change_email?#{URI.encode_query(%{password: "test", email: "foobar"})}"
+ )
- assert json_response(conn, 200) == %{"error" => "Email has invalid format."}
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "error" => "Email has invalid format."
+ }
end
test "with proper permissions, valid password and no email", %{
conn: conn
} do
- conn =
- post(conn, "/api/pleroma/change_email", %{
- "password" => "test"
- })
+ conn = post(conn, "/api/pleroma/change_email?#{URI.encode_query(%{password: "test"})}")
- assert json_response(conn, 200) == %{"error" => "Email can't be blank."}
+ assert %{"error" => "Missing field: email."} = json_response_and_validate_schema(conn, 400)
end
test "with proper permissions, valid password and blank email", %{
conn: conn
} do
conn =
- post(conn, "/api/pleroma/change_email", %{
- "password" => "test",
- "email" => ""
- })
+ post(
+ conn,
+ "/api/pleroma/change_email?#{URI.encode_query(%{password: "test", email: ""})}"
+ )
- assert json_response(conn, 200) == %{"error" => "Email can't be blank."}
+ assert json_response_and_validate_schema(conn, 200) == %{"error" => "Email can't be blank."}
end
test "with proper permissions, valid password and non unique email", %{
user = insert(:user)
conn =
- post(conn, "/api/pleroma/change_email", %{
- "password" => "test",
- "email" => user.email
- })
+ post(
+ conn,
+ "/api/pleroma/change_email?#{URI.encode_query(%{password: "test", email: user.email})}"
+ )
- assert json_response(conn, 200) == %{"error" => "Email has already been taken."}
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "error" => "Email has already been taken."
+ }
end
test "with proper permissions, valid password and valid email", %{
conn: conn
} do
conn =
- post(conn, "/api/pleroma/change_email", %{
- "password" => "test",
- "email" => "cofe@foobar.com"
- })
-
- assert json_response(conn, 200) == %{"status" => "success"}
+ post(
+ conn,
+ "/api/pleroma/change_email?#{
+ URI.encode_query(%{password: "test", email: "cofe@foobar.com"})
+ }"
+ )
+
+ assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
end
end
conn =
conn
|> assign(:token, nil)
- |> post("/api/pleroma/change_password")
-
- assert json_response(conn, 403) == %{"error" => "Insufficient permissions: write:accounts."}
+ |> post(
+ "/api/pleroma/change_password?#{
+ URI.encode_query(%{
+ password: "hi",
+ new_password: "newpass",
+ new_password_confirmation: "newpass"
+ })
+ }"
+ )
+
+ assert json_response_and_validate_schema(conn, 403) == %{
+ "error" => "Insufficient permissions: write:accounts."
+ }
end
test "with proper permissions and invalid password", %{conn: conn} do
conn =
- post(conn, "/api/pleroma/change_password", %{
- "password" => "hi",
- "new_password" => "newpass",
- "new_password_confirmation" => "newpass"
- })
-
- assert json_response(conn, 200) == %{"error" => "Invalid password."}
+ post(
+ conn,
+ "/api/pleroma/change_password?#{
+ URI.encode_query(%{
+ password: "hi",
+ new_password: "newpass",
+ new_password_confirmation: "newpass"
+ })
+ }"
+ )
+
+ assert json_response_and_validate_schema(conn, 200) == %{"error" => "Invalid password."}
end
test "with proper permissions, valid password and new password and confirmation not matching",
conn: conn
} do
conn =
- post(conn, "/api/pleroma/change_password", %{
- "password" => "test",
- "new_password" => "newpass",
- "new_password_confirmation" => "notnewpass"
- })
-
- assert json_response(conn, 200) == %{
+ post(
+ conn,
+ "/api/pleroma/change_password?#{
+ URI.encode_query(%{
+ password: "test",
+ new_password: "newpass",
+ new_password_confirmation: "notnewpass"
+ })
+ }"
+ )
+
+ assert json_response_and_validate_schema(conn, 200) == %{
"error" => "New password does not match confirmation."
}
end
conn: conn
} do
conn =
- post(conn, "/api/pleroma/change_password", %{
- "password" => "test",
- "new_password" => "",
- "new_password_confirmation" => ""
- })
-
- assert json_response(conn, 200) == %{
+ post(
+ conn,
+ "/api/pleroma/change_password?#{
+ URI.encode_query(%{password: "test", new_password: "", new_password_confirmation: ""})
+ }"
+ )
+
+ assert json_response_and_validate_schema(conn, 200) == %{
"error" => "New password can't be blank."
}
end
user: user
} do
conn =
- post(conn, "/api/pleroma/change_password", %{
- "password" => "test",
- "new_password" => "newpass",
- "new_password_confirmation" => "newpass"
- })
-
- assert json_response(conn, 200) == %{"status" => "success"}
+ post(
+ conn,
+ "/api/pleroma/change_password?#{
+ URI.encode_query(%{
+ password: "test",
+ new_password: "newpass",
+ new_password_confirmation: "newpass"
+ })
+ }"
+ )
+
+ assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
fetched_user = User.get_cached_by_id(user.id)
assert Pleroma.Password.Pbkdf2.verify_pass("newpass", fetched_user.password_hash) == true
end
|> assign(:token, nil)
|> post("/api/pleroma/delete_account")
- assert json_response(conn, 403) ==
+ assert json_response_and_validate_schema(conn, 403) ==
%{"error" => "Insufficient permissions: write:accounts."}
end
for params <- [%{"password" => "hi"}, %{}] do
ret_conn = post(conn, "/api/pleroma/delete_account", params)
- assert json_response(ret_conn, 200) == %{"error" => "Invalid password."}
+ assert json_response_and_validate_schema(ret_conn, 200) == %{
+ "error" => "Invalid password."
+ }
end
end
test "with proper permissions and valid password", %{conn: conn, user: user} do
- conn = post(conn, "/api/pleroma/delete_account", %{"password" => "test"})
+ conn = post(conn, "/api/pleroma/delete_account?password=test")
ObanHelpers.perform_all()
- assert json_response(conn, 200) == %{"status" => "success"}
+ assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
user = User.get_by_id(user.id)
refute user.is_active
assert response.resp_body ==
~s(<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Link rel="lrdd" template="#{
- Pleroma.Web.base_url()
+ Pleroma.Web.Endpoint.url()
}/.well-known/webfinger?resource={uri}" type="application/xrd+xml" /></XRD>)
end
test "returns a link to the xml lrdd" do
host_info = WebFinger.host_meta()
- assert String.contains?(host_info, Pleroma.Web.base_url())
+ assert String.contains?(host_info, Pleroma.Web.Endpoint.url())
end
end
end
def article_factory do
- note_factory()
- |> Map.put("type", "Article")
+ %Pleroma.Object{data: data} = note_factory()
+ %Pleroma.Object{data: Map.merge(data, %{"type" => "Article"})}
end
def tombstone_factory do
# Displaying a warning to prevent unintentional clearing of all but one keys in section
if Keyword.keyword?(temp_setting) and length(temp_setting) == 1 do
Logger.warn(
- "Please change to `clear_config([section]); clear_config([section, key], value)`: " <>
- "#{inspect(config_path)}, #{inspect(temp_setting)}"
+ "Please change `clear_config([section], key: value)` to `clear_config([section, key], value)`"
)
end
# SPDX-License-Identifier: AGPL-3.0-only
defmodule MRFModuleMock do
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
@impl true
def filter(message), do: {:ok, message}