Merge remote-tracking branch 'pleroma/develop' into merge-pleroma

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2022-12-22 17:56:29 +01:00
commit 7ee63904ec
63 changed files with 1104 additions and 363 deletions

View file

@ -83,6 +83,7 @@
# lanodan: I think PreferImplicitTry should be consistency, and the behaviour seems
# inconsistent, see: https://github.com/rrrene/credo/issues/224
{Credo.Check.Readability.PreferImplicitTry, false},
{Credo.Check.Readability.PipeIntoAnonymousFunctions, exit_status: 0},
{Credo.Check.Readability.RedundantBlankLines},
{Credo.Check.Readability.StringSigils},
{Credo.Check.Readability.TrailingBlankLine},
@ -90,6 +91,7 @@
{Credo.Check.Readability.VariableNames},
{Credo.Check.Readability.Semicolons},
{Credo.Check.Readability.SpaceAfterCommas},
{Credo.Check.Readability.WithSingleClause, exit_status: 0},
{Credo.Check.Refactor.DoubleBooleanNegation},
{Credo.Check.Refactor.CondStatements},
{Credo.Check.Refactor.CyclomaticComplexity},

View file

@ -158,4 +158,4 @@ docker:
- docker push $CI_REGISTRY_IMAGE
only:
refs:
- develop
- develop

View file

@ -1,6 +1,8 @@
### Release checklist
* [ ] Bump version in `mix.exs`
* [ ] Compile a changelog
* [ ] Create an MR with an announcement to pleroma.social
* [ ] Tag the release
* [ ] Bump version in `mix.exs`
* [ ] Compile a changelog
* [ ] Create an MR with an announcement to pleroma.social
#### post-merge
* [ ] Tag the release on the merge commit
* [ ] Make the tag into a Gitlab Release™
* [ ] Merge `stable` into `develop` (in case the fixes are already in develop, use `git merge -s ours --no-commit` and manually merge the changelogs)

View file

@ -59,10 +59,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fixed lowercase HTTP HEAD method in the Media Proxy Preview code
- Removed useless notification call on Delete activities
- Improved performance for filtering out deactivated and invisible users
- RSS and Atom feeds for users work again
- TwitterCard meta tags conformance
### Removed
- Quack, the logging backend that pushes to Slack channels
## 2.4.5 - 2022-08-27
## Fixed
- Image `class` attributes not being scrubbed, allowing to exploit frontend special classes [!3792](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3792)
- Delete report notifs when demoting from superuser [!3642](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3642)
- Validate `mediaType` only by it's format rather than using a list [!3597](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3597)
- Pagination: Make mutes and blocks lists behave the same as other lists [!3693](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3693)
- Compatibility with Elixir 1.14 [!3740](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3740)
- Frontend installer: FediFE build URL [!3736](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3736)
- Streaming: Don't stream ChatMessage into the home timeline [!3738](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3738)
- Streaming: Stream local-only posts in the local timeline [!3738](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3738)
- Signatures: Fix `keyId` lookup for GoToSocial [!3725](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3725)
- Validator: Fix `replies` handling for GoToSocial [!3725](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3725)
## 2.4.4 - 2022-08-19
### Security

View file

@ -88,10 +88,7 @@
"BLH1qVhJItRGCfxgTtONfsOKDc9VRAraXw-3NsmjMngWSh7NxOizN6bkuRA7iLTMPS82PjwJAr3UoK9EC1IFrz4",
private_key: "_-XZ0iebPrRfZ_o0-IatTdszYa8VCH1yLN-JauK7HHA"
config :pleroma, Oban,
queues: false,
crontab: false,
plugins: false
config :pleroma, Oban, testing: :manual
config :pleroma, Pleroma.ScheduledActivity,
daily_user_limit: 2,

View file

@ -17,7 +17,7 @@ su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate"
## For from source installations (using git)
1. Go to the working directory of Pleroma (default is `/opt/pleroma`)
2. Run `git pull` [^1]. This pulls the latest changes from upstream.
2. Run `git checkout <tagged release>` [^1]. e.g. `git checkout v2.4.5` This pulls the [tagged release](https://git.pleroma.social/pleroma/pleroma/-/releases) from upstream.
3. Run `mix deps.get` [^1]. This pulls in any new dependencies.
4. Stop the Pleroma service.
5. Run `mix ecto.migrate` [^1] [^2]. This task performs database migrations, if there were any.

View file

@ -0,0 +1,15 @@
# Installing on NixOS
NixOS contains a source build package of pleroma and a NixOS module to install it.
For installation add this to your configuration.nix and add a config.exs next to it:
```nix
services.pleroma = {
enable = true;
configs = [ (lib.fileContents ./config.exs) ];
secretConfigFile = "/var/lib/pleroma/secret.exs";
};
```
## Questions
The nix community uses matrix for communication: [#nix:nixos.org](https://matrix.to/#/#nix:nixos.org)

View file

@ -637,7 +637,13 @@ defp put_change_if_present(changeset, map_field, value_function) do
{:ok, new_value} <- value_function.(value) do
put_change(changeset, map_field, new_value)
else
_ -> changeset
{:error, :file_too_large} ->
Ecto.Changeset.validate_change(changeset, map_field, fn map_field, _value ->
[{map_field, "file is too large"}]
end)
_ ->
changeset
end
end
@ -934,7 +940,7 @@ def post_register_action(%User{is_approved: true, is_confirmed: true} = user) do
end
end
defp send_user_approval_email(user) do
defp send_user_approval_email(%User{email: email} = user) when is_binary(email) do
user
|> Pleroma.Emails.UserEmail.approval_pending_email()
|> Pleroma.Emails.Mailer.deliver_async()
@ -942,6 +948,10 @@ defp send_user_approval_email(user) do
{:ok, :enqueued}
end
defp send_user_approval_email(_user) do
{:ok, :skipped}
end
defp send_admin_approval_emails(user) do
all_superusers()
|> Enum.filter(fn user -> not is_nil(user.email) end)

View file

@ -40,9 +40,9 @@ defp check_reject(%{host: actor_host} = _actor_info, object) do
defp check_media_removal(
%{host: actor_host} = _actor_info,
%{"type" => "Create", "object" => %{"attachment" => child_attachment}} = object
%{"type" => type, "object" => %{"attachment" => child_attachment}} = object
)
when length(child_attachment) > 0 do
when length(child_attachment) > 0 and type in ["Create", "Update"] do
media_removal =
instance_list(:media_removal)
|> MRF.subdomains_regex()
@ -63,10 +63,11 @@ defp check_media_removal(_actor_info, object), do: {:ok, object}
defp check_media_nsfw(
%{host: actor_host} = _actor_info,
%{
"type" => "Create",
"type" => type,
"object" => %{} = _child_object
} = object
) do
)
when type in ["Create", "Update"] do
media_nsfw =
instance_list(:media_nsfw)
|> MRF.subdomains_regex()

View file

@ -27,22 +27,22 @@ defp get_tags(_), do: []
defp process_tag(
"mrf_tag:media-force-nsfw",
%{
"type" => "Create",
"type" => type,
"object" => %{"attachment" => child_attachment}
} = message
)
when length(child_attachment) > 0 do
when length(child_attachment) > 0 and type in ["Create", "Update"] do
{:ok, Kernel.put_in(message, ["object", "sensitive"], true)}
end
defp process_tag(
"mrf_tag:media-strip",
%{
"type" => "Create",
"type" => type,
"object" => %{"attachment" => child_attachment} = object
} = message
)
when length(child_attachment) > 0 do
when length(child_attachment) > 0 and type in ["Create", "Update"] do
object = Map.delete(object, "attachment")
message = Map.put(message, "object", object)
@ -152,7 +152,7 @@ def filter(%{"object" => target_actor, "type" => "Follow"} = message),
do: filter_message(target_actor, message)
@impl true
def filter(%{"actor" => actor, "type" => "Create"} = message),
def filter(%{"actor" => actor, "type" => type} = message) when type in ["Create", "Update"],
do: filter_message(actor, message)
@impl true

View file

@ -89,6 +89,6 @@ defp fix_url(data) do
defp validate_data(cng) do
cng
|> validate_inclusion(:type, ~w[Link Document Audio Image Video])
|> validate_required([:type, :mediaType])
|> validate_required([:mediaType, :type])
end
end

View file

@ -748,20 +748,24 @@ defp build_flag_object(%{statuses: statuses}) do
Enum.map(statuses || [], &build_flag_object/1)
end
defp build_flag_object(%Activity{data: %{"id" => id}, object: %{data: data}}) do
activity_actor = User.get_by_ap_id(data["actor"])
defp build_flag_object(%Activity{} = activity) do
object = Object.normalize(activity, fetch: false)
%{
"type" => "Note",
"id" => id,
"content" => data["content"],
"published" => data["published"],
"actor" =>
AccountView.render(
"show.json",
%{user: activity_actor, skip_visibility_check: true}
)
}
# Do not allow people to report Creates. Instead, report the Object that is Created.
if activity.data["type"] != "Create" do
build_flag_object_with_actor_and_id(
object,
User.get_by_ap_id(activity.data["actor"]),
activity.data["id"]
)
else
build_flag_object(object)
end
end
defp build_flag_object(%Object{} = object) do
actor = User.get_by_ap_id(object.data["actor"])
build_flag_object_with_actor_and_id(object, actor, object.data["id"])
end
defp build_flag_object(act) when is_map(act) or is_binary(act) do
@ -773,12 +777,12 @@ defp build_flag_object(act) when is_map(act) or is_binary(act) do
end
case Activity.get_by_ap_id_with_object(id) do
%Activity{} = activity ->
build_flag_object(activity)
%Activity{object: object} = _ ->
build_flag_object(object)
nil ->
if activity = Activity.get_by_object_ap_id_with_object(id) do
build_flag_object(activity)
if %Object{} = object = Object.get_by_ap_id(id) do
build_flag_object(object)
else
%{"id" => id, "deleted" => true}
end
@ -787,6 +791,20 @@ defp build_flag_object(act) when is_map(act) or is_binary(act) do
defp build_flag_object(_), do: []
defp build_flag_object_with_actor_and_id(%Object{data: data}, actor, id) do
%{
"type" => "Note",
"id" => id,
"content" => data["content"],
"published" => data["published"],
"actor" =>
AccountView.render(
"show.json",
%{user: actor, skip_visibility_check: true}
)
}
end
#### Report-related helpers
def get_reports(params, page, page_size) do
params =

View file

@ -23,10 +23,12 @@ def extract_report_info(
|> Enum.reject(&is_nil(&1))
|> Enum.map(fn
act when is_map(act) ->
Activity.get_by_ap_id_with_object(act["id"]) || make_fake_activity(act, user)
Activity.get_create_by_object_ap_id_with_object(act["id"]) ||
Activity.get_by_ap_id_with_object(act["id"]) || make_fake_activity(act, user)
act when is_binary(act) ->
Activity.get_by_ap_id_with_object(act)
Activity.get_create_by_object_ap_id_with_object(act) ||
Activity.get_by_ap_id_with_object(act)
end)
%{

View file

@ -64,7 +64,8 @@ def update_credentials_operation do
requestBody: request_body("Parameters", update_credentials_request(), required: true),
responses: %{
200 => Operation.response("Account", "application/json", Account),
403 => Operation.response("Error", "application/json", ApiError)
403 => Operation.response("Error", "application/json", ApiError),
413 => Operation.response("Error", "application/json", ApiError)
}
}
end
@ -229,12 +230,12 @@ def follow_operation do
type: :object,
properties: %{
reblogs: %Schema{
type: :boolean,
allOf: [BooleanLike],
description: "Receive this account's reblogs in home timeline? Defaults to true.",
default: true
},
notify: %Schema{
type: :boolean,
allOf: [BooleanLike],
description:
"Receive notifications for all statuses posted by the account? Defaults to false.",
default: false

View file

@ -14,14 +14,8 @@ defmodule Pleroma.Web.Feed.FeedView do
require Pleroma.Constants
@spec pub_date(String.t() | DateTime.t()) :: String.t()
def pub_date(date) when is_binary(date) do
date
|> Timex.parse!("{ISO:Extended}")
|> pub_date
end
def pub_date(%DateTime{} = date), do: Timex.format!(date, "{RFC822}")
@days ~w(Mon Tue Wed Thu Fri Sat Sun)
@months ~w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
def prepare_activity(activity, opts \\ []) do
object = Object.normalize(activity, fetch: false)
@ -41,13 +35,18 @@ def prepare_activity(activity, opts \\ []) do
def most_recent_update(activities) do
with %{updated_at: updated_at} <- List.first(activities) do
NaiveDateTime.to_iso8601(updated_at)
to_rfc3339(updated_at)
end
end
def most_recent_update(activities, user) do
def most_recent_update(activities, user, :atom) do
(List.first(activities) || user).updated_at
|> NaiveDateTime.to_iso8601()
|> to_rfc3339()
end
def most_recent_update(activities, user, :rss) do
(List.first(activities) || user).updated_at
|> to_rfc2822()
end
def feed_logo do
@ -61,6 +60,10 @@ def feed_logo do
|> MediaProxy.url()
end
def email(user) do
user.nickname <> "@" <> Pleroma.Web.Endpoint.host()
end
def logo(user) do
user
|> User.avatar_url()
@ -69,18 +72,34 @@ def logo(user) do
def last_activity(activities), do: List.last(activities)
def activity_title(%{"content" => content}, opts \\ %{}) do
content
def activity_title(%{"content" => content, "summary" => summary} = data, opts \\ %{}) do
title =
cond do
summary != "" -> summary
content != "" -> activity_content(data)
true -> "a post"
end
title
|> Pleroma.Web.Metadata.Utils.scrub_html()
|> Pleroma.Emoji.Formatter.demojify()
|> Formatter.truncate(opts[:max_length], opts[:omission])
|> escape()
end
def activity_description(data) do
content = activity_content(data)
summary = data["summary"]
cond do
content != "" -> escape(content)
summary != "" -> escape(summary)
true -> escape(data["type"])
end
end
def activity_content(%{"content" => content}) do
content
|> String.replace(~r/[\n\r]/, "")
|> escape()
end
def activity_content(_), do: ""
@ -112,4 +131,60 @@ def escape(html) do
|> html_escape()
|> safe_to_string()
end
@spec to_rfc3339(String.t() | NativeDateTime.t()) :: String.t()
def to_rfc3339(date) when is_binary(date) do
date
|> Timex.parse!("{ISO:Extended}")
|> to_rfc3339()
end
def to_rfc3339(nd) do
nd
|> Timex.to_datetime()
|> Timex.format!("{RFC3339}")
end
@spec to_rfc2822(String.t() | DateTime.t() | NativeDateTime.t()) :: String.t()
def to_rfc2822(datestr) when is_binary(datestr) do
datestr
|> Timex.parse!("{ISO:Extended}")
|> to_rfc2822()
end
def to_rfc2822(%DateTime{} = date) do
date
|> DateTime.to_naive()
|> NaiveDateTime.to_erl()
|> rfc2822_from_erl()
end
def to_rfc2822(nd) do
nd
|> Timex.to_datetime()
|> DateTime.to_naive()
|> NaiveDateTime.to_erl()
|> rfc2822_from_erl()
end
@doc """
Builds a RFC2822 timestamp from an Erlang timestamp
[RFC2822 3.3 - Date and Time Specification](https://tools.ietf.org/html/rfc2822#section-3.3)
This function always assumes the Erlang timestamp is in Universal time, not Local time
"""
def rfc2822_from_erl({{year, month, day} = date, {hour, minute, second}}) do
day_name = Enum.at(@days, :calendar.day_of_the_week(date) - 1)
month_name = Enum.at(@months, month - 1)
date_part = "#{day_name}, #{day} #{month_name} #{year}"
time_part = "#{pad(hour)}:#{pad(minute)}:#{pad(second)}"
date_part <> " " <> time_part <> " +0000"
end
defp pad(num) do
num
|> Integer.to_string()
|> String.pad_leading(2, "0")
end
end

View file

@ -253,7 +253,17 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p
with_pleroma_settings: true
)
else
_e -> render_error(conn, :forbidden, "Invalid request")
{:error, %Ecto.Changeset{errors: [avatar: {"file is too large", _}]}} ->
render_error(conn, :request_entity_too_large, "File is too large")
{:error, %Ecto.Changeset{errors: [banner: {"file is too large", _}]}} ->
render_error(conn, :request_entity_too_large, "File is too large")
{:error, %Ecto.Changeset{errors: [background: {"file is too large", _}]}} ->
render_error(conn, :request_entity_too_large, "File is too large")
_e ->
render_error(conn, :forbidden, "Invalid request")
end
end

View file

@ -88,7 +88,7 @@ defp get_quoted_activities(activities) do
# This should be removed in a future version of Pleroma. Pleroma-FE currently
# depends on this field, as well.
defp get_context_id(%{data: %{"context" => context}}) when is_binary(context) do
use Bitwise
import Bitwise
:erlang.crc32(context)
|> band(bnot(0x8000_0000))

View file

@ -20,12 +20,12 @@ def build_tags(%{activity_id: id, object: object, user: user}) do
[
title_tag(user),
{:meta, [property: "twitter:description", content: scrubbed_content], []}
{:meta, [name: "twitter:description", content: scrubbed_content], []}
] ++
if attachments == [] or Metadata.activity_nsfw?(object) do
[
image_tag(user),
{:meta, [property: "twitter:card", content: "summary"], []}
{:meta, [name: "twitter:card", content: "summary"], []}
]
else
attachments
@ -37,20 +37,19 @@ def build_tags(%{user: user}) do
with truncated_bio = Utils.scrub_html_and_truncate(user.bio) do
[
title_tag(user),
{:meta, [property: "twitter:description", content: truncated_bio], []},
{:meta, [name: "twitter:description", content: truncated_bio], []},
image_tag(user),
{:meta, [property: "twitter:card", content: "summary"], []}
{:meta, [name: "twitter:card", content: "summary"], []}
]
end
end
defp title_tag(user) do
{:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []}
{:meta, [name: "twitter:title", content: Utils.user_name_string(user)], []}
end
def image_tag(user) do
{:meta, [property: "twitter:image", content: MediaProxy.preview_url(User.avatar_url(user))],
[]}
{:meta, [name: "twitter:image", content: MediaProxy.preview_url(User.avatar_url(user))], []}
end
defp build_attachments(id, %{data: %{"attachment" => attachments}}) do
@ -60,10 +59,10 @@ defp build_attachments(id, %{data: %{"attachment" => attachments}}) do
case Utils.fetch_media_type(@media_types, url["mediaType"]) do
"audio" ->
[
{:meta, [property: "twitter:card", content: "player"], []},
{:meta, [property: "twitter:player:width", content: "480"], []},
{:meta, [property: "twitter:player:height", content: "80"], []},
{:meta, [property: "twitter:player", content: player_url(id)], []}
{:meta, [name: "twitter:card", content: "player"], []},
{:meta, [name: "twitter:player:width", content: "480"], []},
{:meta, [name: "twitter:player:height", content: "80"], []},
{:meta, [name: "twitter:player", content: player_url(id)], []}
| acc
]
@ -74,10 +73,10 @@ defp build_attachments(id, %{data: %{"attachment" => attachments}}) do
# workaround.
"image" ->
[
{:meta, [property: "twitter:card", content: "summary_large_image"], []},
{:meta, [name: "twitter:card", content: "summary_large_image"], []},
{:meta,
[
property: "twitter:player",
name: "twitter:player",
content: MediaProxy.url(url["href"])
], []}
| acc
@ -90,14 +89,14 @@ defp build_attachments(id, %{data: %{"attachment" => attachments}}) do
width = url["width"] || 480
[
{:meta, [property: "twitter:card", content: "player"], []},
{:meta, [property: "twitter:player", content: player_url(id)], []},
{:meta, [property: "twitter:player:width", content: "#{width}"], []},
{:meta, [property: "twitter:player:height", content: "#{height}"], []},
{:meta, [property: "twitter:player:stream", content: MediaProxy.url(url["href"])],
{:meta, [name: "twitter:card", content: "player"], []},
{:meta, [name: "twitter:player", content: player_url(id)], []},
{:meta, [name: "twitter:player:width", content: "#{width}"], []},
{:meta, [name: "twitter:player:height", content: "#{height}"], []},
{:meta, [name: "twitter:player:stream", content: MediaProxy.url(url["href"])],
[]},
{:meta,
[property: "twitter:player:stream:content_type", content: url["mediaType"]], []}
{:meta, [name: "twitter:player:stream:content_type", content: url["mediaType"]],
[]}
| acc
]
@ -123,8 +122,8 @@ defp maybe_add_dimensions(metadata, url) do
!is_nil(url["height"]) && !is_nil(url["width"]) ->
metadata ++
[
{:meta, [property: "twitter:player:width", content: "#{url["width"]}"], []},
{:meta, [property: "twitter:player:height", content: "#{url["height"]}"], []}
{:meta, [name: "twitter:player:width", content: "#{url["width"]}"], []},
{:meta, [name: "twitter:player:height", content: "#{url["height"]}"], []}
]
true ->

View file

@ -3,15 +3,15 @@
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<id><%= @data["id"] %></id>
<title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
<content type="html"><%= activity_content(@data) %></content>
<published><%= @activity.data["published"] %></published>
<updated><%= @activity.data["published"] %></updated>
<content type="html"><%= activity_description(@data) %></content>
<published><%= to_rfc3339(@activity.data["published"]) %></published>
<updated><%= to_rfc3339(@activity.data["published"]) %></updated>
<ostatus:conversation ref="<%= activity_context(@activity) %>">
<%= activity_context(@activity) %>
</ostatus:conversation>
<link href="<%= activity_context(@activity) %>" rel="ostatus:conversation"/>
<%= if @data["summary"] do %>
<%= if @data["summary"] != "" do %>
<summary><%= escape(@data["summary"]) %></summary>
<% end %>

View file

@ -3,17 +3,12 @@
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<guid><%= @data["id"] %></guid>
<title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
<description><%= activity_content(@data) %></description>
<pubDate><%= @activity.data["published"] %></pubDate>
<updated><%= @activity.data["published"] %></updated>
<description><%= activity_description(@data) %></description>
<pubDate><%= to_rfc2822(@activity.data["published"]) %></pubDate>
<ostatus:conversation ref="<%= activity_context(@activity) %>">
<%= activity_context(@activity) %>
</ostatus:conversation>
<%= if @data["summary"] do %>
<description><%= escape(@data["summary"]) %></description>
<% end %>
<%= if @activity.local do %>
<link><%= @data["id"] %></link>
<% else %>
@ -27,7 +22,7 @@
<% end %>
<%= for attachment <- @data["attachment"] || [] do %>
<link type="<%= attachment_type(attachment) %>"><%= attachment_href(attachment) %></link>
<enclosure url="<%= attachment_href(attachment) %>" type="<%= attachment_type(attachment) %>" />
<% end %>
<%= if @data["inReplyTo"] do %>

View file

@ -1,17 +1,14 @@
<author>
<id><%= @user.ap_id %></id>
<activity:object>http://activitystrea.ms/schema/1.0/person</activity:object>
<uri><%= @user.ap_id %></uri>
<name><%= @user.nickname %></name>
<activity:object>http://activitystrea.ms/schema/1.0/person</activity:object>
<activity:displayName><%= @user.name %></activity:displayName>
<activity:image><%= User.avatar_url(@user) %></activity:image>
<activity:id><%= @user.ap_id %></activity:id>
<activity:published><%= to_rfc3339(@user.inserted_at) %></activity:published>
<activity:updated><%= to_rfc3339(@user.updated_at) %></activity:updated>
<activity:url><%= @user.ap_id %></activity:url>
<poco:preferredUsername><%= @user.nickname %></poco:preferredUsername>
<poco:displayName><%= @user.name %></poco:displayName>
<poco:note><%= escape(@user.bio) %></poco:note>
<summary><%= escape(@user.bio) %></summary>
<name><%= @user.nickname %></name>
<link rel="avatar" href="<%= User.avatar_url(@user) %>"/>
<%= if User.banner_url(@user) do %>
<link rel="header" href="<%= User.banner_url(@user) %>"/>
<% end %>
<%= if @user.local do %>
<ap_enabled>true</ap_enabled>
<% end %>
</author>

View file

@ -1,17 +1,10 @@
<managingEditor>
<guid><%= @user.ap_id %></guid>
<activity:object>http://activitystrea.ms/schema/1.0/person</activity:object>
<uri><%= @user.ap_id %></uri>
<poco:preferredUsername><%= @user.nickname %></poco:preferredUsername>
<poco:displayName><%= @user.name %></poco:displayName>
<poco:note><%= escape(@user.bio) %></poco:note>
<description><%= escape(@user.bio) %></description>
<name><%= @user.nickname %></name>
<link rel="avatar"><%= User.avatar_url(@user) %></link>
<%= if User.banner_url(@user) do %>
<link rel="header"><%= User.banner_url(@user) %></link>
<% end %>
<%= if @user.local do %>
<ap_enabled>true</ap_enabled>
<% end %>
</managingEditor>
<managingEditor><%= "#{email(@user)} (#{escape(@user.name)})" %></managingEditor>
<activity:object>http://activitystrea.ms/schema/1.0/person</activity:object>
<activity:displayName><%= @user.name %></activity:displayName>
<activity:image><%= User.avatar_url(@user) %></activity:image>
<activity:id><%= @user.ap_id %></activity:id>
<activity:published><%= to_rfc3339(@user.inserted_at) %></activity:published>
<activity:updated><%= to_rfc3339(@user.updated_at) %></activity:updated>
<poco:preferredUsername><%= @user.nickname %></poco:preferredUsername>
<poco:displayName><%= @user.name %></poco:displayName>
<poco:note><%= escape(@user.bio) %></poco:note>

View file

@ -1,12 +1,22 @@
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<%= render "_tag_author.atom", assigns %>
<%= render Phoenix.Controller.view_module(@conn), "_tag_author.atom", assigns %>
<id><%= @data["id"] %></id>
<title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
<content type="html"><%= activity_content(@data) %></content>
<id><%= @data["id"] %></id>
<title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
<content type="html"><%= activity_description(@data) %></content>
<published><%= to_rfc3339(@activity.data["published"]) %></published>
<updated><%= to_rfc3339(@activity.data["published"]) %></updated>
<ostatus:conversation ref="<%= activity_context(@activity) %>">
<%= activity_context(@activity) %>
</ostatus:conversation>
<link href="<%= activity_context(@activity) %>" rel="ostatus:conversation"/>
<%= if @data["summary"] != "" do %>
<summary><%= @data["summary"] %></summary>
<% end %>
<%= if @activity.local do %>
<link type="application/atom+xml" href='<%= @data["id"] %>' rel="self"/>
@ -15,37 +25,25 @@
<link type="text/html" href='<%= @data["external_url"] %>' rel="alternate"/>
<% end %>
<published><%= @activity.data["published"] %></published>
<updated><%= @activity.data["published"] %></updated>
<ostatus:conversation ref="<%= activity_context(@activity) %>">
<%= activity_context(@activity) %>
</ostatus:conversation>
<link href="<%= activity_context(@activity) %>" rel="ostatus:conversation"/>
<%= if @data["summary"] do %>
<summary><%= @data["summary"] %></summary>
<% end %>
<%= for id <- @activity.recipients do %>
<%= if id == Pleroma.Constants.as_public() do %>
<%= for id <- @activity.recipients do %>
<%= 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.Endpoint.url()}.+followers$/, id) 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.Endpoint.url()}.+followers$/, id) do %>
<link rel="mentioned"
ostatus:object-type="http://activitystrea.ms/schema/1.0/person"
href="<%= id %>" />
<% end %>
ostatus:object-type="http://activitystrea.ms/schema/1.0/person"
href="<%= id %>" />
<% end %>
<% end %>
<% end %>
<%= for tag <- Pleroma.Object.hashtags(@object) do %>
<category term="<%= tag %>"></category>
<% end %>
<%= for tag <- Pleroma.Object.hashtags(@object) do %>
<category term="<%= tag %>"></category>
<% end %>
<%= for {emoji, file} <- @data["emoji"] || %{} do %>
<link name="<%= emoji %>" rel="emoji" href="<%= file %>"/>
<% end %>
<%= for {emoji, file} <- @data["emoji"] || %{} do %>
<link name="<%= emoji %>" rel="emoji" href="<%= file %>"/>
<% end %>
</entry>

View file

@ -4,9 +4,9 @@
<guid isPermalink="true"><%= activity_context(@activity) %></guid>
<link><%= activity_context(@activity) %></link>
<pubDate><%= pub_date(@activity.data["published"]) %></pubDate>
<pubDate><%= to_rfc2822(@activity.data["published"]) %></pubDate>
<description><%= activity_content(@data) %></description>
<description><%= activity_description(@data) %></description>
<%= for attachment <- @data["attachment"] || [] do %>
<enclosure url="<%= attachment_href(attachment) %>" type="<%= attachment_type(attachment) %>"/>
<% end %>

View file

@ -1,18 +1,14 @@
<author>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<id><%= @actor.ap_id %></id>
<uri><%= @actor.ap_id %></uri>
<name><%= @actor.nickname %></name>
<summary><%= escape(@actor.bio) %></summary>
<link rel="avatar" href="<%= User.avatar_url(@actor) %>"/>
<%= if User.banner_url(@actor) do %>
<link rel="header" href="<%= User.banner_url(@actor) %>"/>
<% end %>
<%= if @actor.local do %>
<ap_enabled>true</ap_enabled>
<% end %>
<poco:preferredUsername><%= @actor.nickname %></poco:preferredUsername>
<poco:displayName><%= @actor.name %></poco:displayName>
<poco:note><%= escape(@actor.bio) %></poco:note>
<uri><%= @actor.ap_id %></uri>
<name><%= @actor.nickname %></name>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<activity:displayName><%= @actor.name %></activity:displayName>
<activity:image><%= User.avatar_url(@actor) %></activity:image>
<activity:id><%= @actor.ap_id %></activity:id>
<activity:published><%= to_rfc3339(@actor.inserted_at) %></activity:published>
<activity:updated><%= to_rfc3339(@actor.updated_at) %></activity:updated>
<activity:url><%= @actor.ap_id %></activity:url>
<poco:preferredUsername><%= @actor.nickname %></poco:preferredUsername>
<poco:displayName><%= @actor.name %></poco:displayName>
<poco:note><%= escape(@actor.bio) %></poco:note>
</author>

View file

@ -1,22 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<feed
xmlns="http://www.w3.org/2005/Atom"
xmlns:thr="http://purl.org/syndication/thread/1.0"
xmlns:activity="http://activitystrea.ms/spec/1.0/"
xmlns:poco="http://portablecontacts.net/spec/1.0"
xmlns:ostatus="http://ostatus.org/schema/1.0"
xmlns:statusnet="http://status.net/schema/api/1/">
<feed xml:lang="<%= Gettext.language_tag() %>" xmlns="http://www.w3.org/2005/Atom"
xmlns:thr="http://purl.org/syndication/thread/1.0"
xmlns:georss="http://www.georss.org/georss"
xmlns:activity="http://activitystrea.ms/spec/1.0/"
xmlns:media="http://purl.org/syndication/atommedia"
xmlns:poco="http://portablecontacts.net/spec/1.0"
xmlns:ostatus="http://ostatus.org/schema/1.0"
xmlns:statusnet="http://status.net/schema/api/1/">
<id><%= Routes.tag_feed_url(@conn, :feed, @tag) <> ".atom" %></id>
<title>#<%= @tag %></title>
<subtitle><%= Gettext.dpgettext("static_pages", "tag feed description", "These are public toots tagged with #%{tag}. You can interact with them if you have an account anywhere in the fediverse.", tag: @tag) %></subtitle>
<logo><%= feed_logo() %></logo>
<updated><%= most_recent_update(@activities) %></updated>
<link rel="self" href="<%= '#{Routes.tag_feed_url(@conn, :feed, @tag)}.atom' %>" type="application/atom+xml"/>
<id><%= '#{Routes.tag_feed_url(@conn, :feed, @tag)}.rss' %></id>
<title>#<%= @tag %></title>
<subtitle><%= Gettext.dpgettext("static_pages", "tag feed description", "These are public toots tagged with #%{tag}. You can interact with them if you have an account anywhere in the fediverse.", tag: @tag) %></subtitle>
<logo><%= feed_logo() %></logo>
<updated><%= most_recent_update(@activities) %></updated>
<link rel="self" href="<%= '#{Routes.tag_feed_url(@conn, :feed, @tag)}.atom' %>" type="application/atom+xml"/>
<%= for activity <- @activities do %>
<%= render "_tag_activity.atom", Map.merge(assigns, prepare_activity(activity, actor: true)) %>
<% end %>
<%= for activity <- @activities do %>
<%= render Phoenix.Controller.view_module(@conn), "_tag_activity.atom", Map.merge(assigns, prepare_activity(activity, actor: true)) %>
<% end %>
</feed>

View file

@ -1,15 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:webfeeds="http://webfeeds.org/rss/1.0">
<rss version="2.0"
xmlns:webfeeds="http://webfeeds.org/rss/1.0"
xmlns:thr="http://purl.org/syndication/thread/1.0">
<channel>
<title>#<%= @tag %></title>
<description><%= Gettext.dpgettext("static_pages", "tag feed description", "These are public toots tagged with #%{tag}. You can interact with them if you have an account anywhere in the fediverse.", tag: @tag) %></description>
<link><%= '#{Routes.tag_feed_url(@conn, :feed, @tag)}.rss' %></link>
<webfeeds:logo><%= feed_logo() %></webfeeds:logo>
<webfeeds:accentColor>2b90d9</webfeeds:accentColor>
<%= for activity <- @activities do %>
<%= render "_tag_activity.xml", Map.merge(assigns, prepare_activity(activity)) %>
<%= render Phoenix.Controller.view_module(@conn), "_tag_activity.xml", Map.merge(assigns, prepare_activity(activity)) %>
<% end %>
</channel>
</rss>

View file

@ -8,17 +8,18 @@
<id><%= Routes.user_feed_url(@conn, :feed, @user.nickname) <> ".atom" %></id>
<title><%= @user.nickname <> "'s timeline" %></title>
<updated><%= most_recent_update(@activities, @user) %></updated>
<subtitle><%= escape(@user.bio) %></subtitle>
<updated><%= most_recent_update(@activities, @user, :atom) %></updated>
<logo><%= logo(@user) %></logo>
<link rel="self" href="<%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.atom' %>" type="application/atom+xml"/>
<%= render "_author.atom", assigns %>
<%= render Phoenix.Controller.view_module(@conn), "_author.atom", assigns %>
<%= if last_activity(@activities) do %>
<link rel="next" href="<%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.atom?max_id=#{last_activity(@activities).id}' %>" type="application/atom+xml"/>
<% end %>
<%= for activity <- @activities do %>
<%= render "_activity.atom", Map.merge(assigns, prepare_activity(activity)) %>
<%= render Phoenix.Controller.view_module(@conn), "_activity.atom", Map.merge(assigns, prepare_activity(activity)) %>
<% end %>
</feed>

View file

@ -1,20 +1,30 @@
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<rss version="2.0"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:thr="http://purl.org/syndication/thread/1.0"
xmlns:activity="http://activitystrea.ms/spec/1.0/"
xmlns:ostatus="http://ostatus.org/schema/1.0"
xmlns:poco="http://portablecontacts.net/spec/1.0">
<channel>
<guid><%= Routes.user_feed_url(@conn, :feed, @user.nickname) <> ".rss" %></guid>
<title><%= @user.nickname <> "'s timeline" %></title>
<updated><%= most_recent_update(@activities, @user) %></updated>
<image><%= logo(@user) %></image>
<link><%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.rss' %></link>
<atom:link href="<%= Routes.user_feed_url(@conn, :feed, @user.nickname) <> ".atom" %>"
rel="self" type="application/rss+xml" />
<description><%= escape(@user.bio) %></description>
<image>
<url><%= logo(@user) %></url>
<title><%= @user.nickname <> "'s timeline" %></title>
<link><%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.rss' %></link>
</image>
<%= render "_author.rss", assigns %>
<%= render Phoenix.Controller.view_module(@conn), "_author.rss", assigns %>
<%= if last_activity(@activities) do %>
<link rel="next"><%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.rss?max_id=#{last_activity(@activities).id}' %></link>
<% end %>
<%= for activity <- @activities do %>
<%= render "_activity.rss", Map.merge(assigns, prepare_activity(activity)) %>
<%= render Phoenix.Controller.view_module(@conn), "_activity.rss", Map.merge(assigns, prepare_activity(activity)) %>
<% end %>
</channel>
</rss>

View file

@ -5,6 +5,6 @@
<title><%= @email.subject %></title>
</head>
<body>
<%= @inner_content %>
<%= render Phoenix.Controller.view_module(@conn), Phoenix.Controller.view_template(@conn), assigns %>
</body>
</html>

View file

@ -10,6 +10,6 @@
<base target="_parent">
</head>
<body>
<%= @inner_content %>
<%= render Phoenix.Controller.view_module(@conn), Phoenix.Controller.view_template(@conn), assigns %>
</body>
</html>

View file

@ -2,7 +2,7 @@
<%= form_for @conn, Routes.o_auth_path(@conn, :prepare_request), [as: "authorization", method: "get"], fn f -> %>
<div style="display: none">
<%= render "_scopes.html", Map.merge(assigns, %{form: f}) %>
<%= render Phoenix.Controller.view_module(@conn), "_scopes.html", Map.merge(assigns, %{form: f}) %>
</div>
<%= hidden_input f, :client_id, value: @client_id %>

View file

@ -21,7 +21,7 @@
<div class="container__content">
<%= if @app do %>
<p><%= raw Gettext.dpgettext("static_pages", "oauth authorize message", "Application <strong>%{client_name}</strong> is requesting access to your account.", client_name: safe_to_string(html_escape(@app.client_name))) %></p>
<%= render "_scopes.html", Map.merge(assigns, %{form: f}) %>
<%= render Phoenix.Controller.view_module(@conn), "_scopes.html", Map.merge(assigns, %{form: f}) %>
<% end %>
<%= if @user do %>
@ -63,5 +63,5 @@
<% end %>
<%= if Pleroma.Config.oauth_consumer_enabled?() do %>
<%= render Pleroma.Web.Auth.WrapperAuthenticator.oauth_consumer_template(), assigns %>
<%= render Phoenix.Controller.view_module(@conn), Pleroma.Web.Auth.WrapperAuthenticator.oauth_consumer_template(), assigns %>
<% end %>

18
mix.exs
View file

@ -8,8 +8,8 @@ def project do
app: :pleroma,
name: "Rebased",
compat_name: "Pleroma",
version: version("2.4.53"),
elixir: "~> 1.10",
version: version("2.4.55"),
elixir: "~> 1.11",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
elixirc_options: [warnings_as_errors: warnings_as_errors()],
@ -121,11 +121,17 @@ defp deps do
{:tzdata, "~> 1.0.3"},
{:plug_cowboy, "~> 2.5.1"},
{:phoenix_pubsub, "~> 2.0"},
{:phoenix_ecto, "~> 4.0"},
{:phoenix_ecto, "~> 4.4.0"},
{:ecto_enum, "~> 1.4"},
{:ecto_sql, "~> 3.9.0"},
{:postgrex, ">= 0.15.5"},
{:oban, "~> 2.9"},
{:phoenix_html, "~> 3.1"},
{:phoenix_live_reload, "~> 1.3.3", only: :dev},
{:phoenix_live_view, "~> 0.17.1"},
{:phoenix_live_dashboard, "~> 0.6.2"},
{:telemetry_metrics, "~> 0.6.1"},
{:telemetry_poller, "~> 1.0"},
{:oban, "~> 2.13"},
{:gettext,
git: "https://github.com/tusooa/gettext.git",
ref: "72fb2496b6c5280ed911bdc3756890e7f38a4808",
@ -134,7 +140,6 @@ defp deps do
{:trailing_format_plug, "~> 0.0.7"},
{:fast_sanitize, "~> 0.2.0"},
{:html_entities, "~> 0.5", override: true},
{:phoenix_html, "~> 3.1", override: true},
{:calendar, "~> 1.0"},
{:cachex, "~> 3.2"},
{:csv, "~> 2.4"},
@ -199,7 +204,6 @@ defp deps do
{:eblurhash, "~> 1.2.2"},
{:oembed_providers, "~> 0.1.0"},
{:open_api_spex, "~> 3.10"},
{:phoenix_live_dashboard, "~> 0.6.2"},
{:ecto_psql_extras, "~> 0.6"},
{:icalendar, "~> 1.1"},
{:geospatial, "~> 0.2.0"},
@ -213,7 +217,7 @@ defp deps do
## dev & test
{:ex_doc, "~> 0.22", only: :dev, runtime: false},
{:ex_machina, "~> 2.4", only: :test},
{:credo, "~> 1.4", only: [:dev, :test], runtime: false},
{:credo, "~> 1.6", only: [:dev, :test], runtime: false},
{:mock, "~> 0.3.5", only: :test},
{:covertool, "~> 2.0", only: :test},
{:hackney, "~> 1.18.0", override: true},

View file

@ -4,7 +4,7 @@
"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.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"},
"bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"},
"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://gitlab.com/soapbox-pub/elixir-libraries/elixir-captcha.git", "e0f16822d578866e186a0974d65ad58cddc1e2ab", [ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"]},
@ -19,7 +19,8 @@
"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.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
"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"},
"credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [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", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"},
"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://github.com/msantos/crypt.git", "f75cd55325e33cbea198fb41fe41871392f8fb76", [ref: "f75cd55325e33cbea198fb41fe41871392f8fb76"]},
"csv": {:hex, :csv, "2.4.1", "50e32749953b6bf9818dbfed81cf1190e38cdf24f95891303108087486c5925e", [:mix], [{:parallel_stream, "~> 1.0.4", [hex: :parallel_stream, repo: "hexpm", optional: false]}], "hexpm", "54508938ac67e27966b10ef49606e3ad5995d665d7fc2688efb3eab1307c9079"},
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
@ -29,12 +30,13 @@
"earmark": {:hex, :earmark, "1.4.18", "618c4ff1563450d1832b7fb41dc6755e470f91a6fd4c70f350a58b14f64a7db8", [:mix], [{:earmark_parser, ">= 1.4.17", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "57ac3b6da3958ed09c669a9b159e86377fcccda56bacde8a209fa4dcdef52560"},
"earmark_parser": {:hex, :earmark_parser, "1.4.17", "6f3c7e94170377ba45241d394389e800fb15adc5de51d0a3cd52ae766aafd63f", [:mix], [], "hexpm", "f93ac89c9feca61c165b264b5837bf82344d13bebc634cd575cb711e2e342023"},
"eblurhash": {:hex, :eblurhash, "1.2.2", "7da4255aaea984b31bb71155f673257353b0e0554d0d30dcf859547e74602582", [:rebar3], [], "hexpm", "8c20ca00904de023a835a9dcb7b7762fed32264c85a80c3cafa85288e405044c"},
"ecto": {:hex, :ecto, "3.9.1", "67173b1687afeb68ce805ee7420b4261649d5e2deed8fe5550df23bab0bc4396", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c80bb3d736648df790f7f92f81b36c922d9dd3203ca65be4ff01d067f54eb304"},
"ecto": {:hex, :ecto, "3.9.2", "017db3bc786ff64271108522c01a5d3f6ba0aea5c84912cfb0dd73bf13684108", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "21466d5177e09e55289ac7eade579a642578242c7a3a9f91ad5c6583337a9d15"},
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.4", "5d43fd088d39a158c860b17e8d210669587f63ec89ea122a4654861c8c6e2db4", [:mix], [{:ecto_sql, "~> 3.4", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, ">= 0.15.7", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "311db02f1b772e3d0dc7f56a05044b5e1499d78ed6abf38885e1ca70059449e5"},
"ecto_sql": {:hex, :ecto_sql, "3.9.0", "2bb21210a2a13317e098a420a8c1cc58b0c3421ab8e3acfa96417dab7817918c", [:mix], [{:db_connection, "~> 2.5 or ~> 2.4.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a8f3f720073b8b1ac4c978be25fa7960ed7fd44997420c304a4a2e200b596453"},
"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"},
"esbuild": {:hex, :esbuild, "0.5.0", "d5bb08ff049d7880ee3609ed5c4b864bd2f46445ea40b16b4acead724fb4c4a3", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "f183a0b332d963c4cfaf585477695ea59eef9a6f2204fdd0efa00e099694ffe5"},
"esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"},
"eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"},
"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"},
@ -86,22 +88,25 @@
"nimble_options": {:hex, :nimble_options, "0.4.0", "c89babbab52221a24b8d1ff9e7d838be70f0d871be823165c94dd3418eea728f", [:mix], [], "hexpm", "e6701c1af326a11eea9634a3b1c62b475339ace9456c1a23ec3bc9a847bca02d"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm", "5c040b8469c1ff1b10093d3186e2e10dbe483cd73d79ec017993fb3985b8a9b3"},
"nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
"nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
"oauth2": {:hex, :oauth2, "0.9.4", "632e8e8826a45e33ac2ea5ac66dcc019ba6bb5a0d2ba77e342d33e3b7b252c6e", [:mix], [{:hackney, "~> 1.7", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "407c6b9f60aa0d01b915e2347dc6be78adca706a37f0c530808942da3b62e7af"},
"oauther": {:hex, :oauther, "1.3.0", "82b399607f0ca9d01c640438b34d74ebd9e4acd716508f868e864537ecdb1f76", [:mix], [], "hexpm", "78eb888ea875c72ca27b0864a6f550bc6ee84f2eeca37b093d3d833fbcaec04e"},
"oban": {:hex, :oban, "2.10.1", "202a90f2aed0130b7d750bdbfea8090c8321bce255bade10fd3699733565add0", [:mix], [{:ecto_sql, "~> 3.6", [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 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "161cdd01194147cd6a3efdb1d6c3d9689309991412f799c1e242c18912e307c3"},
"oban": {:hex, :oban, "2.13.4", "b4c4f48f4c89cc01036670eefa28aa9c03d09aadd402655475b936983d597006", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a7d26f82b409e2d7928fbb75a17716e06ad3f783ebe9af260e3dd23abed7f124"},
"oembed_providers": {:hex, :oembed_providers, "0.1.0", "9b336ee5f3ca20ee4ed005383c74b154d30d0abeb98e95828855c0e2841ae46b", [:mix], [{:glob, "~> 1.0", [hex: :glob, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "ac1dda0f743aa6fdead3eef59decfefc9de91d550bf0805b8fce16ed10d421ba"},
"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"},
"parallel_stream": {:hex, :parallel_stream, "1.0.6", "b967be2b23f0f6787fab7ed681b4c45a215a81481fb62b01a5b750fa8f30f76c", [:mix], [], "hexpm", "639b2e8749e11b87b9eb42f2ad325d161c170b39b288ac8d04c4f31f8f0823eb"},
"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.6.15", "0a1d96bbc10747fd83525370d691953cdb6f3ccbac61aa01b4acb012474b047d", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d70ab9fbf6b394755ea88b644d34d79d8b146e490973151f248cacd122d20672"},
"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_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
"phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.2", "0769470265eb13af01b5001b29cb935f4710d6adaa1ffc18417a570a337a2f0f", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.1", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "5bc6c6b38a2ca8b5020b442322fcee6afd5e641637a0b1fb059d4bd89bc58e7b"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.3.3", "3a53772a6118d5679bf50fc1670505a290e32a1d195df9e069d8c53ab040c054", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "766796676e5f558dbae5d1bdb066849673e956005e3730dfd5affd7a6da4abac"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.17.5", "63f52a6f9f6983f04e424586ff897c016ecc5e4f8d1e2c22c2887af1c57215d8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.5.9 or ~> 1.6.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c5586e6a3d4df71b8214c769d4f5eb8ece2b4001711a7ca0f97323c36958b0e3"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"},
"phoenix_swoosh": {:hex, :phoenix_swoosh, "1.1.0", "f8e4780705c9f254cc853f7a40e25f7198ba4d91102bcfad2226669b69766b35", [:mix], [{:finch, "~> 0.8", [hex: :finch, repo: "hexpm", optional: true]}, {:hackney, "~> 1.10", [hex: :hackney, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.5", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "aa82f10afd9a4b6080fdf3274dbb9432b25b210d42b4b6b55308f6e59cd87c3d"},
"phoenix_template": {:hex, :phoenix_template, "1.0.0", "c57bc5044f25f007dc86ab21895688c098a9f846a8dda6bc40e2d0ddc146e38f", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "1b066f99a26fd22064c12b2600a9a6e56700f591bf7b20b418054ea38b4d4357"},
"phoenix_view": {:hex, :phoenix_view, "2.0.0", "e676c3058cdfd878faece9cc791fe2f7c810877fdf002db46ee8c01403b4b801", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "6511dd875191aa737092d1e9a74c73858e10253f4111fec8ba9c1a215bfccc77"},
"phoenix_view": {:hex, :phoenix_view, "2.0.1", "a653e3d9d944aace0a064e4a13ad473ffa68f7bc4ca42dbf83cc1d464f1fb295", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "6c358e2cefc5f341c728914b867c556bbfd239fed9e881bac257d70cb2b8a6f6"},
"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.5.2", "62894ccd601cf9597e2c23911ff12798a8a18d237e9739f58a6b04e4988899fe", [: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]}], "hexpm", "ea6e87f774c8608d60c8d34022a7d073bd7680a0a013f049fc62bf35efea1044"},
"plug_crypto": {:hex, :plug_crypto, "1.2.3", "8f77d13aeb32bfd9e654cb68f0af517b371fb34c56c9f2b58fe3df1235c1251a", [:mix], [], "hexpm", "b5672099c6ad5c202c45f5a403f21a3411247f164e4a8fab056e5cd8a290f4a2"},

View file

@ -40,12 +40,6 @@ msgctxt "config description at :pleroma"
msgid "Authenticator"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config description at :quack"
msgid "Quack-related settings"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config label at :cors_plug"
@ -82,12 +76,6 @@ msgctxt "config label at :pleroma"
msgid "Pleroma Authenticator"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config label at :quack"
msgid "Quack Logger"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config description at :logger-:console"
@ -2302,12 +2290,6 @@ msgctxt "config description at :pleroma-:mrf_mention > :actors"
msgid "A list of actors for which any post mentioning them will be dropped"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config description at :pleroma-:mrf_object_age > :actions"
msgid "A list of actions to apply to the post. `:delist` removes the post from public timelines; `:strip_followers` removes followers from the ActivityPub recipient list ensuring they won't be delivered to home timelines; `:reject` rejects the message entirely"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config description at :pleroma-:mrf_object_age > :threshold"
@ -3298,24 +3280,6 @@ msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter
msgid "App metrics endpoint URI path."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config description at :quack > :level"
msgid "Log level"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config description at :quack > :meta"
msgid "Configure which metadata you want to report on"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config description at :quack > :webhook_url"
msgid "Configure the Slack incoming webhook"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config description at :web_push_encryption-:vapid_details > :private_key"
@ -5956,24 +5920,6 @@ msgctxt "config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :pat
msgid "Path"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config label at :quack > :level"
msgid "Level"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config label at :quack > :meta"
msgid "Meta"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config label at :quack > :webhook_url"
msgid "Webhook URL"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config label at :web_push_encryption-:vapid_details > :private_key"
@ -6057,3 +6003,21 @@ msgstr ""
msgctxt "config label at :pleroma-:delete_context_objects > :sleep_interval_ms"
msgid "Sleep interval ms"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config description at :pleroma-:instance > :report_strip_status"
msgid "Strip associated statuses in reports to ids when closed/resolved, otherwise keep a copy"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config description at :pleroma-:mrf_object_age > :actions"
msgid "A list of actions to apply to the post. `:delist` removes the post from public timelines; `:strip_followers` removes followers from the ActivityPub recipient list ensuring they won't be delivered to home timelines, additionally for followers-only it degrades to a direct message; `:reject` rejects the message entirely"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config label at :pleroma-:instance > :report_strip_status"
msgid "Report strip status"
msgstr ""

View file

@ -90,12 +90,12 @@ msgid "must be equal to %{number}"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/common_api.ex:558
#: lib/pleroma/web/common_api.ex:574
msgid "Account not found"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/common_api.ex:316
#: lib/pleroma/web/common_api.ex:332
msgid "Already voted"
msgstr ""
@ -111,7 +111,7 @@ msgid "Can't display this activity"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:327
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:337
msgid "Can't find user"
msgstr ""
@ -131,34 +131,34 @@ msgid "Comment must be up to %{max_size} characters"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/config_db.ex:200
#: lib/pleroma/config_db.ex:199
msgid "Config with params %{params} not found"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/common_api.ex:167
#: lib/pleroma/web/common_api.ex:171
#: lib/pleroma/web/common_api.ex:183
#: lib/pleroma/web/common_api.ex:187
msgid "Could not delete"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/common_api.ex:217
#: lib/pleroma/web/common_api.ex:233
msgid "Could not favorite"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/common_api.ex:254
#: lib/pleroma/web/common_api.ex:270
msgid "Could not unfavorite"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/common_api.ex:202
#: lib/pleroma/web/common_api.ex:218
msgid "Could not unrepeat"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/common_api.ex:565
#: lib/pleroma/web/common_api.ex:574
#: lib/pleroma/web/common_api.ex:581
#: lib/pleroma/web/common_api.ex:590
msgid "Could not update state"
msgstr ""
@ -184,7 +184,7 @@ msgid "Invalid credentials."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/common_api.ex:337
#: lib/pleroma/web/common_api.ex:353
msgid "Invalid indices"
msgstr ""
@ -199,7 +199,7 @@ msgid "Invalid password."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:257
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:267
msgid "Invalid request"
msgstr ""
@ -231,12 +231,12 @@ msgid "Not found"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/common_api.ex:308
#: lib/pleroma/web/common_api.ex:324
msgid "Poll's author can't vote"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:492
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:502
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:20
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:39
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:51
@ -275,7 +275,7 @@ msgid "Throttled"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/common_api.ex:338
#: lib/pleroma/web/common_api.ex:354
msgid "Too many choices"
msgstr ""
@ -307,7 +307,7 @@ msgid "can't update outbox of %{nickname} as %{as_nickname}"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/common_api.ex:510
#: lib/pleroma/web/common_api.ex:526
msgid "conversation is already muted"
msgstr ""
@ -419,12 +419,12 @@ msgid "CAPTCHA Error"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/common_api.ex:266
#: lib/pleroma/web/common_api.ex:282
msgid "Could not add reaction emoji"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/common_api.ex:277
#: lib/pleroma/web/common_api.ex:293
msgid "Could not remove reaction emoji"
msgstr ""
@ -558,7 +558,7 @@ msgid "Access denied"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:324
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:334
msgid "This API requires an authenticated user"
msgstr ""
@ -595,3 +595,10 @@ msgstr ""
#: lib/pleroma/web/o_auth/o_auth_controller.ex:366
msgid "Your account is awaiting approval."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:258
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:261
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:264
msgid "File is too large"
msgstr ""

View file

@ -0,0 +1,197 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-12-01 19:17+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: ko\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Translate Toolkit 3.7.2\n"
## This file is a PO Template file.
##
## "msgid"s here are often extracted from source code.
## Add new translations manually only if they're dynamic
## translations that can't be statically extracted.
##
## Run "mix gettext.extract" to bring this file up to
## date. Leave "msgstr"s empty as changing them here as no
## effect: edit them in PO (.po) files instead.
#: lib/pleroma/web/api_spec/render_error.ex:122
#, elixir-autogen, elixir-format
msgid "%{name} - %{count} is not a multiple of %{multiple}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:131
#, elixir-autogen, elixir-format
msgid "%{name} - %{value} is larger than exclusive maximum %{max}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:140
#, elixir-autogen, elixir-format
msgid "%{name} - %{value} is larger than inclusive maximum %{max}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:149
#, elixir-autogen, elixir-format
msgid "%{name} - %{value} is smaller than exclusive minimum %{min}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:158
#, elixir-autogen, elixir-format
msgid "%{name} - %{value} is smaller than inclusive minimum %{min}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:102
#, elixir-autogen, elixir-format
msgid "%{name} - Array items must be unique."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:114
#, elixir-autogen, elixir-format
msgid "%{name} - Array length %{length} is larger than maxItems: %{}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:106
#, elixir-autogen, elixir-format
msgid "%{name} - Array length %{length} is smaller than minItems: %{min}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:166
#, elixir-autogen, elixir-format
msgid "%{name} - Invalid %{type}. Got: %{value}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:174
#, elixir-autogen, elixir-format
msgid "%{name} - Invalid format. Expected %{format}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:51
#, elixir-autogen, elixir-format
msgid "%{name} - Invalid schema.type. Got: %{type}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:178
#, elixir-autogen, elixir-format
msgid "%{name} - Invalid value for enum."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:95
#, elixir-autogen, elixir-format
msgid "%{name} - String length is larger than maxLength: %{length}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:88
#, elixir-autogen, elixir-format
msgid "%{name} - String length is smaller than minLength: %{length}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:63
#, elixir-autogen, elixir-format
msgid "%{name} - null value where %{type} expected."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:60
#, elixir-autogen, elixir-format
msgid "%{name} - null value."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:182
#, elixir-autogen, elixir-format
msgid "Failed to cast to any schema in %{polymorphic_type}"
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:71
#, elixir-autogen, elixir-format
msgid "Failed to cast value as %{invalid_schema}. Value must be castable using `allOf` schemas listed."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:84
#, elixir-autogen, elixir-format
msgid "Failed to cast value to one of: %{failed_schemas}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:78
#, elixir-autogen, elixir-format
msgid "Failed to cast value using any of: %{failed_schemas}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:212
#, elixir-autogen, elixir-format
msgid "Invalid value for header: %{name}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:204
#, elixir-autogen, elixir-format
msgid "Missing field: %{name}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:208
#, elixir-autogen, elixir-format
msgid "Missing header: %{name}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:196
#, elixir-autogen, elixir-format
msgid "No value provided for required discriminator `%{field}`."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:216
#, elixir-autogen, elixir-format
msgid "Object property count %{property_count} is greater than maxProperties: %{max_properties}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:224
#, elixir-autogen, elixir-format
msgid "Object property count %{property_count} is less than minProperties: %{min_properties}"
msgstr ""
#: lib/pleroma/web/templates/static_fe/static_fe/error.html.eex:2
#, elixir-autogen, elixir-format
msgid "Oops"
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:188
#, elixir-autogen, elixir-format
msgid "Unexpected field: %{name}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:200
#, elixir-autogen, elixir-format
msgid "Unknown schema: %{name}."
msgstr ""
#: lib/pleroma/web/api_spec/render_error.ex:192
#, elixir-autogen, elixir-format
msgid "Value used as discriminator for `%{field}` matches no schemas."
msgstr ""
#: lib/pleroma/web/templates/embed/show.html.eex:43
#: lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex:37
#, elixir-autogen, elixir-format
msgid "announces"
msgstr ""
#: lib/pleroma/web/templates/embed/show.html.eex:44
#: lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex:38
#, elixir-autogen, elixir-format
msgid "likes"
msgstr ""
#: lib/pleroma/web/templates/embed/show.html.eex:42
#: lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex:36
#, elixir-autogen, elixir-format
msgid "replies"
msgstr ""
#: lib/pleroma/web/templates/embed/show.html.eex:27
#: lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex:22
#, elixir-autogen, elixir-format
msgid "sensitive media"
msgstr ""

View file

@ -156,8 +156,8 @@ msgid "Password changed!"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/templates/feed/feed/tag.atom.eex:15
#: lib/pleroma/web/templates/feed/feed/tag.rss.eex:7
#: lib/pleroma/web/templates/feed/feed/tag.atom.eex:12
#: lib/pleroma/web/templates/feed/feed/tag.rss.eex:8
msgctxt "tag feed description"
msgid "These are public toots tagged with #%{tag}. You can interact with them if you have an account anywhere in the fediverse."
msgstr ""

View file

@ -0,0 +1,7 @@
defmodule Pleroma.Repo.Migrations.CreateObanPeers do
use Ecto.Migration
def up, do: Oban.Migrations.up(version: 11)
def down, do: Oban.Migrations.down(version: 11)
end

View file

@ -0,0 +1,26 @@
defmodule Pleroma.Repo.Migrations.SwapPrimaryObanIndexes do
use Ecto.Migration
@disable_ddl_transaction true
@disable_migration_lock true
def change do
create_if_not_exists(
index(
:oban_jobs,
[:state, :queue, :priority, :scheduled_at, :id],
concurrently: true,
prefix: "public"
)
)
drop_if_exists(
index(
:oban_jobs,
[:queue, :state, :priority, :scheduled_at, :id],
concurrently: true,
prefix: "public"
)
)
end
end

View file

@ -73,6 +73,8 @@ defmodule Pleroma.HTML.Scrubber.Default do
@allow_inline_images Pleroma.Config.get([:markup, :allow_inline_images])
if @allow_inline_images do
Meta.allow_tag_with_this_attribute_values(:img, "class", ["emoji"])
# restrict img tags to http/https only, because of MediaProxy.
Meta.allow_tag_with_uri_attributes(:img, ["src"], ["http", "https"])

View file

@ -45,13 +45,14 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do
# allow inline images for custom emoji
if Pleroma.Config.get([:markup, :allow_inline_images]) do
Meta.allow_tag_with_this_attribute_values(:img, "class", ["emoji"])
# restrict img tags to http/https only, because of MediaProxy.
Meta.allow_tag_with_uri_attributes(:img, ["src"], ["http", "https"])
Meta.allow_tag_with_these_attributes(:img, [
"width",
"height",
"class",
"title",
"alt"
])

View file

@ -145,6 +145,7 @@ test "when association is not loaded" do
setup do: clear_config([:instance, :limit_to_local_content])
@tag :skip_on_mac
test "finds utf8 text in statuses", %{
japanese_activity: japanese_activity,
user: user

View file

@ -17,6 +17,7 @@ defmodule Pleroma.HTMLTest do
this is a link with allowed "rel" attribute: <a href="http://example.com/" rel="tag">example.com</a>
this is a link with not allowed "rel" attribute: <a href="http://example.com/" rel="tag noallowed">example.com</a>
this is an image: <img src="http://example.com/image.jpg"><br />
this is an inline emoji: <img class="emoji" src="http://example.com/image.jpg"><br />
<script>alert('hacked')</script>
"""
@ -24,6 +25,10 @@ defmodule Pleroma.HTMLTest do
<img src="http://example.com/image.jpg" onerror="alert('hacked')">
"""
@html_stillimage_sample """
<img class="still-image" src="http://example.com/image.jpg">
"""
@html_span_class_sample """
<span class="animate-spin">hi</span>
"""
@ -45,6 +50,7 @@ test "works as expected" do
this is a link with allowed &quot;rel&quot; attribute: example.com
this is a link with not allowed &quot;rel&quot; attribute: example.com
this is an image:
this is an inline emoji:
alert(&#39;hacked&#39;)
"""
@ -67,6 +73,7 @@ test "normalizes HTML as expected" do
this is a link with allowed &quot;rel&quot; attribute: <a href="http://example.com/" rel="tag">example.com</a>
this is a link with not allowed &quot;rel&quot; attribute: <a href="http://example.com/">example.com</a>
this is an image: <img src="http://example.com/image.jpg"/><br/>
this is an inline emoji: <img class="emoji" src="http://example.com/image.jpg"/><br/>
alert(&#39;hacked&#39;)
"""
@ -90,6 +97,15 @@ test "does not allow spans with invalid classes" do
HTML.filter_tags(@html_span_class_sample, Pleroma.HTML.Scrubber.TwitterText)
end
test "does not allow images with invalid classes" do
expected = """
<img src="http://example.com/image.jpg"/>
"""
assert expected ==
HTML.filter_tags(@html_stillimage_sample, Pleroma.HTML.Scrubber.TwitterText)
end
test "does allow microformats" do
expected = """
<span class="h-card"><a class="u-url mention">@<span>foo</span></a></span>
@ -121,6 +137,7 @@ test "normalizes HTML as expected" do
this is a link with allowed &quot;rel&quot; attribute: <a href="http://example.com/" rel="tag">example.com</a>
this is a link with not allowed &quot;rel&quot; attribute: <a href="http://example.com/">example.com</a>
this is an image: <img src="http://example.com/image.jpg"/><br/>
this is an inline emoji: <img class="emoji" src="http://example.com/image.jpg"/><br/>
alert(&#39;hacked&#39;)
"""
@ -143,6 +160,15 @@ test "does not allow spans with invalid classes" do
assert expected == HTML.filter_tags(@html_span_class_sample, Pleroma.HTML.Scrubber.Default)
end
test "does not allow images with invalid classes" do
expected = """
<img src="http://example.com/image.jpg"/>
"""
assert expected ==
HTML.filter_tags(@html_stillimage_sample, Pleroma.HTML.Scrubber.TwitterText)
end
test "does allow microformats" do
expected = """
<span class="h-card"><a class="u-url mention">@<span>foo</span></a></span>

View file

@ -166,7 +166,7 @@ test "it resets instance reachability on successful fetch" do
Instances.set_consistently_unreachable(id)
refute Instances.reachable?(id)
{:ok, object} =
{:ok, _object} =
Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
assert Instances.reachable?(id)

View file

@ -0,0 +1,103 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ResilienceTest do
use Pleroma.Web.ConnCase, async: true
import Pleroma.Factory
alias Pleroma.Activity
alias Pleroma.Repo
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI.StatusView
setup do
# user = insert(:user)
%{user: user, conn: conn} = oauth_access(["write", "read"])
other_user = insert(:user)
{:ok, post_one} = CommonAPI.post(user, %{status: "Here is a post"})
{:ok, like} = CommonAPI.favorite(other_user, post_one.id)
%{
user: user,
other_user: other_user,
post_one: post_one,
like: like,
conn: conn
}
end
test "after destruction of like activities, things still work", %{
user: user,
post_one: post,
other_user: other_user,
conn: conn,
like: like
} do
post = Repo.get(Activity, post.id)
# Rendering the liked status
rendered_for_user = StatusView.render("show.json", %{activity: post, for: user})
assert rendered_for_user.favourites_count == 1
rendered_for_other_user = StatusView.render("show.json", %{activity: post, for: other_user})
assert rendered_for_other_user.favourites_count == 1
assert rendered_for_other_user.favourited
# Getting the favourited by
[liking_user] =
conn
|> get("/api/v1/statuses/#{post.id}/favourited_by")
|> json_response(200)
assert liking_user["id"] == other_user.id
# We have one notification
[notification] =
conn
|> get("/api/v1/notifications")
|> json_response(200)
assert notification["type"] == "favourite"
# Destroying the like
Repo.delete(like)
post = Repo.get(Activity, post.id)
# Rendering the liked status
rendered_for_user = StatusView.render("show.json", %{activity: post, for: user})
assert rendered_for_user.favourites_count == 1
rendered_for_other_user = StatusView.render("show.json", %{activity: post, for: other_user})
assert rendered_for_other_user.favourites_count == 1
assert rendered_for_other_user.favourited
# Getting the favourited by
[liking_user] =
conn
|> get("/api/v1/statuses/#{post.id}/favourited_by")
|> json_response(200)
assert liking_user["id"] == other_user.id
# Notification is removed
assert [] ==
conn
|> get("/api/v1/notifications")
|> json_response(200)
# Favoriting again doesn't hurt
{:ok, _like_two} = CommonAPI.favorite(other_user, post.id)
post = Repo.get(Activity, post.id)
# Rendering the liked status
rendered_for_user = StatusView.render("show.json", %{activity: post, for: user})
assert rendered_for_user.favourites_count == 1
# General fallout: Can't unfavorite stuff anymore. Acceptable for remote users.
end
end

View file

@ -593,6 +593,21 @@ test "it fails gracefully with invalid email config" do
refute_email_sent()
end
test "it works when the registering user does not provide an email" do
clear_config([Pleroma.Emails.Mailer, :enabled], false)
clear_config([:instance, :account_activation_required], false)
clear_config([:instance, :account_approval_required], true)
cng = User.register_changeset(%User{}, @full_user_data |> Map.put(:email, ""))
# The user is still created
assert {:ok, %User{nickname: "nick"}} = User.register(cng)
# No emails are sent
ObanHelpers.perform_all()
refute_email_sent()
end
test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
clear_config([:instance, :account_activation_required], true)

View file

@ -1553,6 +1553,7 @@ test "it filters broken threads" do
reporter_ap_id = reporter.ap_id
target_ap_id = target_account.ap_id
activity_ap_id = activity.data["id"]
object_ap_id = activity.object.data["id"]
activity_with_object = Activity.get_by_ap_id_with_object(activity_ap_id)
@ -1564,6 +1565,7 @@ test "it filters broken threads" do
reported_activity: activity,
content: content,
activity_ap_id: activity_ap_id,
object_ap_id: object_ap_id,
activity_with_object: activity_with_object,
reporter_ap_id: reporter_ap_id,
target_ap_id: target_ap_id
@ -1577,7 +1579,7 @@ test "it can create a Flag activity",
target_account: target_account,
reported_activity: reported_activity,
content: content,
activity_ap_id: activity_ap_id,
object_ap_id: object_ap_id,
activity_with_object: activity_with_object,
reporter_ap_id: reporter_ap_id,
target_ap_id: target_ap_id
@ -1593,7 +1595,7 @@ test "it can create a Flag activity",
note_obj = %{
"type" => "Note",
"id" => activity_ap_id,
"id" => object_ap_id,
"content" => content,
"published" => activity_with_object.object.data["published"],
"actor" =>
@ -1617,6 +1619,7 @@ test "it can create a Flag activity",
context: context,
target_account: target_account,
reported_activity: reported_activity,
object_ap_id: object_ap_id,
content: content
},
Utils,
@ -1631,8 +1634,7 @@ test "it can create a Flag activity",
content: content
})
new_data =
put_in(activity.data, ["object"], [target_account.ap_id, reported_activity.data["id"]])
new_data = put_in(activity.data, ["object"], [target_account.ap_id, object_ap_id])
assert_called(Utils.maybe_federate(%{activity | data: new_data}))
end

View file

@ -57,6 +57,16 @@ test "match with wildcard domain" do
assert SimplePolicy.filter(local_message) == {:ok, local_message}
end
test "works with Updates" do
clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Some reason"}])
media_message = build_media_message(type: "Update")
assert SimplePolicy.filter(media_message) ==
{:ok,
media_message
|> Map.put("object", Map.delete(media_message["object"], "attachment"))}
end
end
describe "when :media_nsfw" do
@ -90,12 +100,20 @@ test "match with wildcard domain" do
assert SimplePolicy.filter(local_message) == {:ok, local_message}
end
test "works with Updates" do
clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "Whetever"}])
media_message = build_media_message(type: "Update")
assert SimplePolicy.filter(media_message) ==
{:ok, put_in(media_message, ["object", "sensitive"], true)}
end
end
defp build_media_message do
defp build_media_message(opts \\ []) do
%{
"actor" => "https://remote.instance/users/bob",
"type" => "Create",
"type" => opts[:type] || "Create",
"object" => %{
"attachment" => [%{}],
"tag" => ["foo"],

View file

@ -99,6 +99,24 @@ test "removes attachments" do
assert TagPolicy.filter(message) == {:ok, except_message}
end
test "removes attachments in Updates" do
actor = insert(:user, tags: ["mrf_tag:media-strip"])
message = %{
"actor" => actor.ap_id,
"type" => "Update",
"object" => %{"attachment" => ["file1"]}
}
except_message = %{
"actor" => actor.ap_id,
"type" => "Update",
"object" => %{}
}
assert TagPolicy.filter(message) == {:ok, except_message}
end
end
describe "mrf_tag:media-force-nsfw" do
@ -119,5 +137,23 @@ test "Mark as sensitive on presence of attachments" do
assert TagPolicy.filter(message) == {:ok, except_message}
end
test "Mark as sensitive on presence of attachments in Updates" do
actor = insert(:user, tags: ["mrf_tag:media-force-nsfw"])
message = %{
"actor" => actor.ap_id,
"type" => "Update",
"object" => %{"tag" => ["test"], "attachment" => ["file1"]}
}
except_message = %{
"actor" => actor.ap_id,
"type" => "Update",
"object" => %{"tag" => ["test"], "attachment" => ["file1"], "sensitive" => true}
}
assert TagPolicy.filter(message) == {:ok, except_message}
end
end
end

View file

@ -11,6 +11,19 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do
import Pleroma.Factory
describe "attachments" do
test "fails without url" do
attachment = %{
"mediaType" => "",
"name" => "",
"summary" => "298p3RG7j27tfsZ9RQ.jpg",
"type" => "Document"
}
assert {:error, _cng} =
AttachmentValidator.cast_and_validate(attachment)
|> Ecto.Changeset.apply_action(:insert)
end
test "works with honkerific attachments" do
attachment = %{
"mediaType" => "",

View file

@ -61,7 +61,7 @@ test "it accepts Flag activities" do
note_obj = %{
"type" => "Note",
"id" => activity.data["id"],
"id" => activity.object.data["id"],
"content" => "test post",
"published" => object.data["published"],
"actor" => AccountView.render("show.json", %{user: user, skip_visibility_check: true})

View file

@ -487,7 +487,7 @@ test "returns map with Flag object" do
content = "foobar"
target_ap_id = target_account.ap_id
activity_ap_id = activity.data["id"]
object_ap_id = activity.object.data["id"]
res =
Utils.make_flag_data(
@ -503,7 +503,7 @@ test "returns map with Flag object" do
note_obj = %{
"type" => "Note",
"id" => activity_ap_id,
"id" => object_ap_id,
"content" => content,
"published" => activity.object.data["published"],
"actor" =>
@ -518,6 +518,49 @@ test "returns map with Flag object" do
"state" => "open"
} = res
end
test "returns map with Flag object with a non-Create Activity" do
reporter = insert(:user)
posting_account = insert(:user)
target_account = insert(:user)
{:ok, activity} = CommonAPI.post(posting_account, %{status: "foobar"})
{:ok, like} = CommonAPI.favorite(target_account, activity.id)
context = Utils.generate_context_id()
content = "foobar"
target_ap_id = target_account.ap_id
object_ap_id = activity.object.data["id"]
res =
Utils.make_flag_data(
%{
actor: reporter,
context: context,
account: target_account,
statuses: [%{"id" => like.data["id"]}],
content: content
},
%{}
)
note_obj = %{
"type" => "Note",
"id" => object_ap_id,
"content" => content,
"published" => activity.object.data["published"],
"actor" =>
AccountView.render("show.json", %{user: posting_account, skip_visibility_check: true})
}
assert %{
"type" => "Flag",
"content" => ^content,
"context" => ^context,
"object" => [^target_ap_id, ^note_obj],
"state" => "open"
} = res
end
end
describe "add_announce_to_object/2" do

View file

@ -76,7 +76,7 @@ test "renders reported content even if the status is deleted", %{conn: conn} do
assert response["id"] == report_id
assert [status] = response["statuses"]
assert activity.data["id"] == status["uri"]
assert activity.object.data["id"] == status["uri"]
assert activity.object.data["content"] == status["content"]
end

View file

@ -1150,10 +1150,11 @@ test "creates a report" do
target_user = insert(:user)
{:ok, activity} = CommonAPI.post(target_user, %{status: "foobar"})
activity = Activity.normalize(activity)
reporter_ap_id = reporter.ap_id
target_ap_id = target_user.ap_id
activity_ap_id = activity.data["id"]
reported_object_ap_id = activity.object.data["id"]
comment = "foobar"
report_data = %{
@ -1164,7 +1165,7 @@ test "creates a report" do
note_obj = %{
"type" => "Note",
"id" => activity_ap_id,
"id" => reported_object_ap_id,
"content" => "foobar",
"published" => activity.object.data["published"],
"actor" => AccountView.render("show.json", %{user: target_user})
@ -1186,6 +1187,7 @@ test "creates a report" do
test "updates report state" do
[reporter, target_user] = insert_pair(:user)
activity = insert(:note_activity, user: target_user)
object = Object.normalize(activity)
{:ok, %Activity{id: report_id}} =
CommonAPI.report(reporter, %{
@ -1198,10 +1200,10 @@ test "updates report state" do
assert report.data["state"] == "resolved"
[reported_user, activity_id] = report.data["object"]
[reported_user, object_id] = report.data["object"]
assert reported_user == target_user.ap_id
assert activity_id == activity.data["id"]
assert object_id == object.data["id"]
end
test "update report state when the actor is deactivated" do

View file

@ -63,7 +63,6 @@ test "gets a feed (ATOM)", %{conn: conn} do
]
assert xpath(xml, ~x"//feed/entry/author/name/text()"ls) == [user.nickname, user.nickname]
assert xpath(xml, ~x"//feed/entry/author/id/text()"ls) == [user.ap_id, user.ap_id]
conn =
conn
@ -138,8 +137,8 @@ test "gets a feed (RSS)", %{conn: conn} do
]
assert xpath(xml, ~x"//channel/item/pubDate/text()"sl) == [
FeedView.pub_date(activity2.data["published"]),
FeedView.pub_date(activity1.data["published"])
FeedView.to_rfc2822(activity2.data["published"]),
FeedView.to_rfc2822(activity1.data["published"])
]
assert xpath(xml, ~x"//channel/item/enclosure/@url"sl) == [

View file

@ -74,7 +74,7 @@ test "gets an atom feed", %{conn: conn, user: user, object: object, max_id: max_
|> SweetXml.parse()
|> SweetXml.xpath(~x"//entry/title/text()"l)
assert activity_titles == ['42 &amp; Thi...', 'This &amp; t...']
assert activity_titles == ['2hu', '2hu & as']
assert resp =~ FeedView.escape(object.data["content"])
assert resp =~ FeedView.escape(object.data["summary"])
assert resp =~ FeedView.escape(object.data["context"])
@ -90,7 +90,7 @@ test "gets an atom feed", %{conn: conn, user: user, object: object, max_id: max_
|> SweetXml.parse()
|> SweetXml.xpath(~x"//entry/title/text()"l)
assert activity_titles == ['This &amp; t...']
assert activity_titles == ['2hu & as']
end
test "gets a rss feed", %{conn: conn, user: user, object: object, max_id: max_id} do
@ -105,7 +105,7 @@ test "gets a rss feed", %{conn: conn, user: user, object: object, max_id: max_id
|> SweetXml.parse()
|> SweetXml.xpath(~x"//item/title/text()"l)
assert activity_titles == ['42 &amp; Thi...', 'This &amp; t...']
assert activity_titles == ['2hu', '2hu & as']
assert resp =~ FeedView.escape(object.data["content"])
assert resp =~ FeedView.escape(object.data["summary"])
assert resp =~ FeedView.escape(object.data["context"])
@ -121,7 +121,7 @@ test "gets a rss feed", %{conn: conn, user: user, object: object, max_id: max_id
|> SweetXml.parse()
|> SweetXml.xpath(~x"//item/title/text()"l)
assert activity_titles == ['This &amp; t...']
assert activity_titles == ['2hu & as']
end
test "returns 404 for a missing feed", %{conn: conn} do

View file

@ -896,6 +896,12 @@ test "following without reblogs" do
|> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: true})
|> json_response_and_validate_schema(200)
assert %{"showing_reblogs" => true} =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: "1"})
|> json_response_and_validate_schema(200)
assert [%{"id" => ^reblog_id}] =
conn
|> get("/api/v1/timelines/home")
@ -925,6 +931,12 @@ test "following with reblogs" do
|> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false})
|> json_response_and_validate_schema(200)
assert %{"showing_reblogs" => false} =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: "0"})
|> json_response_and_validate_schema(200)
assert [] ==
conn
|> get("/api/v1/timelines/home")
@ -935,21 +947,23 @@ test "following with subscription and unsubscribing" do
%{conn: conn} = oauth_access(["follow"])
followed = insert(:user)
ret_conn =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/accounts/#{followed.id}/follow", %{notify: true})
assert %{"subscribing" => true} =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/accounts/#{followed.id}/follow", %{notify: true})
|> json_response_and_validate_schema(200)
assert %{"id" => _id, "subscribing" => true} =
json_response_and_validate_schema(ret_conn, 200)
assert %{"subscribing" => true} =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/accounts/#{followed.id}/follow", %{notify: "1"})
|> json_response_and_validate_schema(200)
ret_conn =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/accounts/#{followed.id}/follow", %{notify: false})
assert %{"id" => _id, "subscribing" => false} =
json_response_and_validate_schema(ret_conn, 200)
assert %{"subscribing" => false} =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/accounts/#{followed.id}/follow", %{notify: false})
|> json_response_and_validate_schema(200)
end
test "following / unfollowing errors", %{user: user, conn: conn} do

View file

@ -6,6 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.ReportControllerTest do
use Pleroma.Web.ConnCase, async: true
alias Pleroma.Activity
alias Pleroma.Repo
alias Pleroma.Rule
alias Pleroma.Web.CommonAPI
@ -29,6 +30,41 @@ test "submit a basic report", %{conn: conn, target_user: target_user} do
|> json_response_and_validate_schema(200)
end
test "submit a report with a fake Create", %{
conn: conn
} do
target_user = insert(:user)
note = insert(:note, user: target_user)
activity_params = %{
"object" => note.data["id"],
"actor" => note.data["actor"],
"to" => note.data["to"] || [],
"cc" => note.data["cc"] || [],
"type" => "Create"
}
{:ok, fake_activity} =
Repo.insert(%Activity{
data: activity_params,
recipients: activity_params["to"] ++ activity_params["cc"],
local: true,
actor: activity_params["actor"]
})
assert %{"action_taken" => false, "id" => _} =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/reports", %{
"account_id" => target_user.id,
"status_ids" => [fake_activity.id],
"comment" => "bad status!",
"forward" => "false"
})
|> json_response_and_validate_schema(200)
end
test "submit a report with statuses and comment", %{
conn: conn,
target_user: target_user,

View file

@ -37,6 +37,7 @@ test "it returns empty result if user or status search return undefined error",
end
end
@tag :skip_on_mac
test "search", %{conn: conn} do
user = insert(:user)
user_two = insert(:user, %{nickname: "shp@shitposter.club"})

View file

@ -266,6 +266,34 @@ test "updates the user's avatar", %{user: user, conn: conn} do
assert user.avatar == nil
end
test "updates the user's avatar, upload_limit, returns a HTTP 413", %{conn: conn, user: user} do
upload_limit = Config.get([:instance, :upload_limit]) * 8 + 8
assert :ok ==
File.write(Path.absname("test/tmp/large_binary.data"), <<0::size(upload_limit)>>)
new_avatar_oversized = %Plug.Upload{
content_type: nil,
path: Path.absname("test/tmp/large_binary.data"),
filename: "large_binary.data"
}
assert user.avatar == %{}
res =
patch(conn, "/api/v1/accounts/update_credentials", %{"avatar" => new_avatar_oversized})
assert user_response = json_response_and_validate_schema(res, 413)
assert user_response["avatar"] != User.avatar_url(user)
user = User.get_by_id(user.id)
assert user.avatar == %{}
clear_config([:instance, :upload_limit], upload_limit)
assert :ok == File.rm(Path.absname("test/tmp/large_binary.data"))
end
test "updates the user's banner", %{user: user, conn: conn} do
new_header = %Plug.Upload{
content_type: "image/jpeg",
@ -285,6 +313,32 @@ test "updates the user's banner", %{user: user, conn: conn} do
assert user.banner == nil
end
test "updates the user's banner, upload_limit, returns a HTTP 413", %{conn: conn, user: user} do
upload_limit = Config.get([:instance, :upload_limit]) * 8 + 8
assert :ok ==
File.write(Path.absname("test/tmp/large_binary.data"), <<0::size(upload_limit)>>)
new_header_oversized = %Plug.Upload{
content_type: nil,
path: Path.absname("test/tmp/large_binary.data"),
filename: "large_binary.data"
}
res =
patch(conn, "/api/v1/accounts/update_credentials", %{"header" => new_header_oversized})
assert user_response = json_response_and_validate_schema(res, 413)
assert user_response["header"] != User.banner_url(user)
user = User.get_by_id(user.id)
assert user.banner == %{}
clear_config([:instance, :upload_limit], upload_limit)
assert :ok == File.rm(Path.absname("test/tmp/large_binary.data"))
end
test "updates the user's background", %{conn: conn, user: user} do
new_header = %Plug.Upload{
content_type: "image/jpeg",
@ -308,6 +362,34 @@ test "updates the user's background", %{conn: conn, user: user} do
assert user.background == nil
end
test "updates the user's background, upload_limit, returns a HTTP 413", %{
conn: conn,
user: user
} do
upload_limit = Config.get([:instance, :upload_limit]) * 8 + 8
assert :ok ==
File.write(Path.absname("test/tmp/large_binary.data"), <<0::size(upload_limit)>>)
new_background_oversized = %Plug.Upload{
content_type: nil,
path: Path.absname("test/tmp/large_binary.data"),
filename: "large_binary.data"
}
res =
patch(conn, "/api/v1/accounts/update_credentials", %{
"pleroma_background_image" => new_background_oversized
})
assert user_response = json_response_and_validate_schema(res, 413)
assert user.background == %{}
clear_config([:instance, :upload_limit], upload_limit)
assert :ok == File.rm(Path.absname("test/tmp/large_binary.data"))
end
test "requires 'write:accounts' permission" do
token1 = insert(:oauth_token, scopes: ["read"])
token2 = insert(:oauth_token, scopes: ["write", "follow"])

View file

@ -22,10 +22,10 @@ test "it renders twitter card for user info" do
res = TwitterCard.build_tags(%{user: user})
assert res == [
{:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []},
{:meta, [property: "twitter:description", content: "born 19 March 1994"], []},
{:meta, [property: "twitter:image", content: avatar_url], []},
{:meta, [property: "twitter:card", content: "summary"], []}
{:meta, [name: "twitter:title", content: Utils.user_name_string(user)], []},
{:meta, [name: "twitter:description", content: "born 19 March 1994"], []},
{:meta, [name: "twitter:image", content: avatar_url], []},
{:meta, [name: "twitter:card", content: "summary"], []}
]
end
@ -47,11 +47,11 @@ test "it uses summary twittercard if post has no attachment" do
result = TwitterCard.build_tags(%{object: note, user: user, activity_id: activity.id})
assert [
{:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []},
{:meta, [property: "twitter:description", content: "pleroma in a nutshell"], []},
{:meta, [property: "twitter:image", content: "http://localhost:4001/images/avi.png"],
{:meta, [name: "twitter:title", content: Utils.user_name_string(user)], []},
{:meta, [name: "twitter:description", content: "pleroma in a nutshell"], []},
{:meta, [name: "twitter:image", content: "http://localhost:4001/images/avi.png"],
[]},
{:meta, [property: "twitter:card", content: "summary"], []}
{:meta, [name: "twitter:card", content: "summary"], []}
] == result
end
@ -73,15 +73,15 @@ test "it uses summary as description if post has one" do
result = TwitterCard.build_tags(%{object: note, user: user, activity_id: activity.id})
assert [
{:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []},
{:meta, [name: "twitter:title", content: Utils.user_name_string(user)], []},
{:meta,
[
property: "twitter:description",
name: "twitter:description",
content: "Public service announcement on caffeine consumption"
], []},
{:meta, [property: "twitter:image", content: "http://localhost:4001/images/avi.png"],
{:meta, [name: "twitter:image", content: "http://localhost:4001/images/avi.png"],
[]},
{:meta, [property: "twitter:card", content: "summary"], []}
{:meta, [name: "twitter:card", content: "summary"], []}
] == result
end
@ -123,11 +123,11 @@ test "it renders avatar not attachment if post is nsfw and unfurl_nsfw is disabl
result = TwitterCard.build_tags(%{object: note, user: user, activity_id: activity.id})
assert [
{:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []},
{:meta, [property: "twitter:description", content: "pleroma in a nutshell"], []},
{:meta, [property: "twitter:image", content: "http://localhost:4001/images/avi.png"],
{:meta, [name: "twitter:title", content: Utils.user_name_string(user)], []},
{:meta, [name: "twitter:description", content: "pleroma in a nutshell"], []},
{:meta, [name: "twitter:image", content: "http://localhost:4001/images/avi.png"],
[]},
{:meta, [property: "twitter:card", content: "summary"], []}
{:meta, [name: "twitter:card", content: "summary"], []}
] == result
end
@ -179,26 +179,26 @@ test "it renders supported types of attachments and skips unknown types" do
result = TwitterCard.build_tags(%{object: note, user: user, activity_id: activity.id})
assert [
{:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []},
{:meta, [property: "twitter:description", content: "pleroma in a nutshell"], []},
{:meta, [property: "twitter:card", content: "summary_large_image"], []},
{:meta, [property: "twitter:player", content: "https://pleroma.gov/tenshi.png"], []},
{:meta, [property: "twitter:player:width", content: "1280"], []},
{:meta, [property: "twitter:player:height", content: "1024"], []},
{:meta, [property: "twitter:card", content: "player"], []},
{:meta, [name: "twitter:title", content: Utils.user_name_string(user)], []},
{:meta, [name: "twitter:description", content: "pleroma in a nutshell"], []},
{:meta, [name: "twitter:card", content: "summary_large_image"], []},
{:meta, [name: "twitter:player", content: "https://pleroma.gov/tenshi.png"], []},
{:meta, [name: "twitter:player:width", content: "1280"], []},
{:meta, [name: "twitter:player:height", content: "1024"], []},
{:meta, [name: "twitter:card", content: "player"], []},
{:meta,
[
property: "twitter:player",
name: "twitter:player",
content: Router.Helpers.o_status_url(Endpoint, :notice_player, activity.id)
], []},
{:meta, [property: "twitter:player:width", content: "800"], []},
{:meta, [property: "twitter:player:height", content: "600"], []},
{:meta, [name: "twitter:player:width", content: "800"], []},
{:meta, [name: "twitter:player:height", content: "600"], []},
{:meta,
[
property: "twitter:player:stream",
name: "twitter:player:stream",
content: "https://pleroma.gov/about/juche.webm"
], []},
{:meta, [property: "twitter:player:stream:content_type", content: "video/webm"], []}
{:meta, [name: "twitter:player:stream:content_type", content: "video/webm"], []}
] == result
end
end