Merge branch 'develop' into gitlab-mr-iid-4426
This commit is contained in:
commit
c7c453ca21
34 changed files with 1574 additions and 115 deletions
1
changelog.d/captcha-package.fix
Normal file
1
changelog.d/captcha-package.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Switch native captcha to the published pleroma_captcha Hex package.
|
||||||
1
changelog.d/host-header-verification.security
Normal file
1
changelog.d/host-header-verification.security
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Ensure Host header is present and matches instance URI
|
||||||
1
changelog.d/iceshrimpnet-reports-fix.fix
Normal file
1
changelog.d/iceshrimpnet-reports-fix.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Handle reports with just actor ap id as the object
|
||||||
1
changelog.d/majic-1.2.0.change
Normal file
1
changelog.d/majic-1.2.0.change
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Update majic to 1.2.0.
|
||||||
1
changelog.d/oban-plugins-lazarus-hex.change
Normal file
1
changelog.d/oban-plugins-lazarus-hex.change
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Use the Hex package for oban_plugins_lazarus.
|
||||||
1
changelog.d/reject-third-party-reports.fix
Normal file
1
changelog.d/reject-third-party-reports.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Reject incoming reports when both the reporter and reported account are remote
|
||||||
1
changelog.d/remote-ip-hex.change
Normal file
1
changelog.d/remote-ip-hex.change
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Use upstream Hex releases for the `remote_ip` dependency and expose client IP ranges for remote IP resolution.
|
||||||
1
changelog.d/user-search-sorting.change
Normal file
1
changelog.d/user-search-sorting.change
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Improve user search / autocompletion ordering.
|
||||||
|
|
@ -738,6 +738,7 @@ config :pleroma, Pleroma.Workers.PurgeExpiredActivity, enabled: true, min_lifeti
|
||||||
config :pleroma, Pleroma.Web.Plugs.RemoteIp,
|
config :pleroma, Pleroma.Web.Plugs.RemoteIp,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
headers: ["x-forwarded-for"],
|
headers: ["x-forwarded-for"],
|
||||||
|
clients: [],
|
||||||
proxies: [],
|
proxies: [],
|
||||||
reserved: [
|
reserved: [
|
||||||
"127.0.0.0/8",
|
"127.0.0.0/8",
|
||||||
|
|
|
||||||
|
|
@ -2910,7 +2910,7 @@ config :pleroma, :config_description, [
|
||||||
key: Pleroma.Web.Plugs.RemoteIp,
|
key: Pleroma.Web.Plugs.RemoteIp,
|
||||||
type: :group,
|
type: :group,
|
||||||
description: """
|
description: """
|
||||||
`Pleroma.Web.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration.
|
`Pleroma.Web.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://hex.pm/packages/remote_ip) but with runtime configuration.
|
||||||
**If your instance is not behind at least one reverse proxy, you should not enable this plug.**
|
**If your instance is not behind at least one reverse proxy, you should not enable this plug.**
|
||||||
""",
|
""",
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -2926,6 +2926,12 @@ config :pleroma, :config_description, [
|
||||||
A list of strings naming the HTTP headers to use when deriving the true client IP. Default: `["x-forwarded-for"]`.
|
A list of strings naming the HTTP headers to use when deriving the true client IP. Default: `["x-forwarded-for"]`.
|
||||||
"""
|
"""
|
||||||
},
|
},
|
||||||
|
%{
|
||||||
|
key: :clients,
|
||||||
|
type: {:list, :string},
|
||||||
|
description:
|
||||||
|
"A list of client IPs or subnets in CIDR notation. These will not be treated as proxies or reserved ranges. Defaults to `[]`. IPv4 entries without a bitmask will be assumed to be /32 and IPv6 /128."
|
||||||
|
},
|
||||||
%{
|
%{
|
||||||
key: :proxies,
|
key: :proxies,
|
||||||
type: {:list, :string},
|
type: {:list, :string},
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ defmodule Pleroma.Signature do
|
||||||
|> put_req_header("(request-target)", request_target)
|
|> put_req_header("(request-target)", request_target)
|
||||||
|> put_req_header("@request-target", request_target)
|
|> put_req_header("@request-target", request_target)
|
||||||
|
|
||||||
@http_signatures_impl.validate_conn(conn)
|
@http_signatures_impl.validate_conn(conn) == true
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec validate_signature(Plug.Conn.t()) :: boolean()
|
@spec validate_signature(Plug.Conn.t()) :: boolean()
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.User.Search do
|
defmodule Pleroma.User.Search do
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators.Uri, as: UriType
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators.Uri, as: UriType
|
||||||
|
alias Pleroma.Instances.Instance
|
||||||
alias Pleroma.Pagination
|
alias Pleroma.Pagination
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
|
|
@ -88,12 +89,13 @@ defmodule Pleroma.User.Search do
|
||||||
|> filter_invisible_users()
|
|> filter_invisible_users()
|
||||||
|> filter_internal_users()
|
|> filter_internal_users()
|
||||||
|> filter_blocked_domains(for_user)
|
|> filter_blocked_domains(for_user)
|
||||||
|
|> filter_unreachable_users()
|
||||||
|> fts_search(query_string)
|
|> fts_search(query_string)
|
||||||
|> select_top_users(top_user_ids)
|
|> select_top_users(top_user_ids)
|
||||||
|> trigram_rank(query_string)
|
|> trigram_rank(query_string)
|
||||||
|> boost_search_rank(for_user, top_user_ids)
|
|> boost_search_rank(for_user, top_user_ids)
|
||||||
|> subquery()
|
|> subquery()
|
||||||
|> order_by(desc: :search_rank)
|
|> order_by_search_rank(for_user)
|
||||||
|> maybe_restrict_local(for_user)
|
|> maybe_restrict_local(for_user)
|
||||||
|> maybe_restrict_accepting_chat_messages(capabilities)
|
|> maybe_restrict_accepting_chat_messages(capabilities)
|
||||||
|> filter_deactivated_users()
|
|> filter_deactivated_users()
|
||||||
|
|
@ -196,6 +198,14 @@ defmodule Pleroma.User.Search do
|
||||||
|
|
||||||
defp filter_blocked_domains(query, _), do: query
|
defp filter_blocked_domains(query, _), do: query
|
||||||
|
|
||||||
|
defp filter_unreachable_users(query) do
|
||||||
|
from(u in query,
|
||||||
|
left_join: i in Instance,
|
||||||
|
on: i.host == fragment("substring(? from '.*://([^/]*)')", u.ap_id),
|
||||||
|
where: is_nil(i.unreachable_since)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
defp maybe_resolve(true, user, query) do
|
defp maybe_resolve(true, user, query) do
|
||||||
case {limit(), user} do
|
case {limit(), user} do
|
||||||
{:all, _} -> :noop
|
{:all, _} -> :noop
|
||||||
|
|
@ -236,6 +246,16 @@ defmodule Pleroma.User.Search do
|
||||||
|
|
||||||
from(u in subquery(query),
|
from(u in subquery(query),
|
||||||
select_merge: %{
|
select_merge: %{
|
||||||
|
search_type:
|
||||||
|
fragment(
|
||||||
|
"""
|
||||||
|
CASE WHEN (?) THEN 2
|
||||||
|
WHEN (?) THEN 1
|
||||||
|
ELSE 0 END
|
||||||
|
""",
|
||||||
|
u.id in ^top_user_ids,
|
||||||
|
u.id in ^friends_ids or u.id in ^followers_ids
|
||||||
|
),
|
||||||
search_rank:
|
search_rank:
|
||||||
fragment(
|
fragment(
|
||||||
"""
|
"""
|
||||||
|
|
@ -261,6 +281,14 @@ defmodule Pleroma.User.Search do
|
||||||
defp boost_search_rank(query, _for_user, top_user_ids) do
|
defp boost_search_rank(query, _for_user, top_user_ids) do
|
||||||
from(u in subquery(query),
|
from(u in subquery(query),
|
||||||
select_merge: %{
|
select_merge: %{
|
||||||
|
search_type:
|
||||||
|
fragment(
|
||||||
|
"""
|
||||||
|
CASE WHEN (?) THEN 2
|
||||||
|
ELSE 0 END
|
||||||
|
""",
|
||||||
|
u.id in ^top_user_ids
|
||||||
|
),
|
||||||
search_rank:
|
search_rank:
|
||||||
fragment(
|
fragment(
|
||||||
"""
|
"""
|
||||||
|
|
@ -273,4 +301,22 @@ defmodule Pleroma.User.Search do
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp order_by_search_rank(query, %User{}) do
|
||||||
|
order_by(
|
||||||
|
query,
|
||||||
|
[u],
|
||||||
|
desc: u.search_type,
|
||||||
|
desc_nulls_last:
|
||||||
|
fragment(
|
||||||
|
"CASE WHEN ? = 1 THEN COALESCE(?, ?) ELSE NULL END",
|
||||||
|
u.search_type,
|
||||||
|
u.last_status_at,
|
||||||
|
u.last_active_at
|
||||||
|
),
|
||||||
|
desc: u.search_rank
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp order_by_search_rank(query, _), do: order_by(query, desc: :search_rank)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def inbox(%{assigns: %{valid_signature: true}} = conn, %{"nickname" => nickname} = params) do
|
def inbox(
|
||||||
|
%{
|
||||||
|
assigns: %{valid_signature: true, valid_host_header: true}
|
||||||
|
} = conn,
|
||||||
|
%{"nickname" => nickname} = params
|
||||||
|
) do
|
||||||
with {:recipient_exists, %User{} = recipient} <-
|
with {:recipient_exists, %User{} = recipient} <-
|
||||||
{:recipient_exists, User.get_cached_by_nickname(nickname)},
|
{:recipient_exists, User.get_cached_by_nickname(nickname)},
|
||||||
{:sender_exists, {:ok, %User{} = actor}} <-
|
{:sender_exists, {:ok, %User{} = actor}} <-
|
||||||
|
|
@ -342,7 +347,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def inbox(%{assigns: %{valid_signature: true}} = conn, params) do
|
def inbox(%{assigns: %{valid_signature: true, valid_host_header: true}} = conn, params) do
|
||||||
Federator.incoming_ap_doc(params)
|
Federator.incoming_ap_doc(params)
|
||||||
json(conn, "ok")
|
json(conn, "ok")
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -430,6 +430,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp reject_third_party_report(%User{local: false}, %User{local: false} = account) do
|
||||||
|
{:reject, "[Transmogrifier] third-party report: #{account.ap_id}"}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp reject_third_party_report(_, _), do: :ok
|
||||||
|
|
||||||
def handle_incoming(data, options \\ []) do
|
def handle_incoming(data, options \\ []) do
|
||||||
data
|
data
|
||||||
|> fix_recursive(&strip_internal_fields/1)
|
|> fix_recursive(&strip_internal_fields/1)
|
||||||
|
|
@ -444,9 +450,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
||||||
) do
|
) do
|
||||||
with context <- data["context"] || Utils.generate_context_id(),
|
with context <- data["context"] || Utils.generate_context_id(),
|
||||||
content <- data["content"] || "",
|
content <- data["content"] || "",
|
||||||
|
objects <- List.wrap(objects),
|
||||||
%User{} = actor <- User.get_cached_by_ap_id(actor),
|
%User{} = actor <- User.get_cached_by_ap_id(actor),
|
||||||
# Reduce the object list to find the reported user.
|
# Reduce the object list to find the reported user.
|
||||||
%User{} = account <- get_reported(objects),
|
%User{} = account <- get_reported(objects),
|
||||||
|
:ok <- reject_third_party_report(actor, account),
|
||||||
# Remove the reported user from the object list.
|
# Remove the reported user from the object list.
|
||||||
statuses <- Enum.filter(objects, fn ap_id -> ap_id != account.ap_id end) do
|
statuses <- Enum.filter(objects, fn ap_id -> ap_id != account.ap_id end) do
|
||||||
%{
|
%{
|
||||||
|
|
|
||||||
63
lib/pleroma/web/plugs/ensure_host_matches_plug.ex
Normal file
63
lib/pleroma/web/plugs/ensure_host_matches_plug.ex
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2026 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.Plugs.EnsureHostMatchesPlug do
|
||||||
|
@moduledoc "Ensures Host header matches instance"
|
||||||
|
|
||||||
|
alias Pleroma.Web.Endpoint
|
||||||
|
|
||||||
|
import Plug.Conn
|
||||||
|
|
||||||
|
def init(options), do: options
|
||||||
|
|
||||||
|
@spec call(Plug.Conn.t(), Plug.opts()) :: Plug.Conn.t()
|
||||||
|
def call(%Plug.Conn{assigns: %{valid_signature: true}} = conn, _opts) do
|
||||||
|
# Host header is scheme-less, URI.parse needs the //
|
||||||
|
host_header = get_req_header(conn, "host")
|
||||||
|
host_uri = URI.parse("//#{host_header}")
|
||||||
|
instance_uri = URI.parse(Endpoint.url())
|
||||||
|
|
||||||
|
case host_header do
|
||||||
|
[host] ->
|
||||||
|
cond do
|
||||||
|
host == "" ->
|
||||||
|
resp(conn, 400, "Host header not provided") |> halt()
|
||||||
|
|
||||||
|
true ->
|
||||||
|
if host_matches?(host_uri, instance_uri),
|
||||||
|
do: assign(conn, :valid_host_header, true),
|
||||||
|
else: resp(conn, 400, "Host header does not match this instance") |> halt()
|
||||||
|
end
|
||||||
|
|
||||||
|
[_head | _rest] ->
|
||||||
|
conn
|
||||||
|
|> resp(400, "More than one Host header provided")
|
||||||
|
|> halt()
|
||||||
|
|
||||||
|
[] ->
|
||||||
|
conn
|
||||||
|
|> resp(400, "Host header not provided")
|
||||||
|
|> halt()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Host header may not be provided, but signature verification failed anyway
|
||||||
|
def call(conn, _opts), do: conn
|
||||||
|
|
||||||
|
defp case_insensitive_compare(checked, authority) do
|
||||||
|
String.downcase(checked) == String.downcase(authority)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Host header did not provide port
|
||||||
|
# Host header is scheme-less, URI.parse does not provide default port
|
||||||
|
defp host_matches?(%URI{host: req_host, port: nil}, %URI{host: instance_host}),
|
||||||
|
do: case_insensitive_compare(req_host, instance_host)
|
||||||
|
|
||||||
|
# Host header provided a port
|
||||||
|
# Any port specified in the Endpoint url configuration is valid here
|
||||||
|
defp host_matches?(%URI{host: req_host, port: port}, %URI{host: instance_host, port: port}),
|
||||||
|
do: case_insensitive_compare(req_host, instance_host)
|
||||||
|
|
||||||
|
defp host_matches?(_, _), do: false
|
||||||
|
end
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.Plugs.RemoteIp do
|
defmodule Pleroma.Web.Plugs.RemoteIp do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
This is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration.
|
This is a shim to call [`RemoteIp`](https://hex.pm/packages/remote_ip) but with runtime configuration.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
|
|
@ -17,15 +17,29 @@ defmodule Pleroma.Web.Plugs.RemoteIp do
|
||||||
|
|
||||||
def call(%{remote_ip: original_remote_ip} = conn, _) do
|
def call(%{remote_ip: original_remote_ip} = conn, _) do
|
||||||
if Config.get([__MODULE__, :enabled]) do
|
if Config.get([__MODULE__, :enabled]) do
|
||||||
%{remote_ip: new_remote_ip} = conn = RemoteIp.call(conn, remote_ip_opts())
|
new_remote_ip = remote_ip(conn) || original_remote_ip
|
||||||
|
|
||||||
|
conn = %{conn | remote_ip: new_remote_ip}
|
||||||
assign(conn, :remote_ip_found, original_remote_ip != new_remote_ip)
|
assign(conn, :remote_ip_found, original_remote_ip != new_remote_ip)
|
||||||
else
|
else
|
||||||
conn
|
conn
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp remote_ip(conn) do
|
||||||
|
opts = remote_ip_opts()
|
||||||
|
|
||||||
|
# Do not use RemoteIp.from/2 here: upstream remote_ip always applies its
|
||||||
|
# built-in reserved ranges. Pleroma keeps :reserved configurable, so reuse
|
||||||
|
# only the header parsing and apply Pleroma's own block classification.
|
||||||
|
conn.req_headers
|
||||||
|
|> RemoteIp.Headers.take(opts[:headers])
|
||||||
|
|> RemoteIp.Headers.parse()
|
||||||
|
|> Enum.reverse()
|
||||||
|
|> Enum.find(&client?(&1, opts))
|
||||||
|
end
|
||||||
|
|
||||||
defp remote_ip_opts do
|
defp remote_ip_opts do
|
||||||
headers = Config.get([__MODULE__, :headers], []) |> MapSet.new()
|
|
||||||
reserved = Config.get([__MODULE__, :reserved], [])
|
reserved = Config.get([__MODULE__, :reserved], [])
|
||||||
|
|
||||||
proxies =
|
proxies =
|
||||||
|
|
@ -33,6 +47,26 @@ defmodule Pleroma.Web.Plugs.RemoteIp do
|
||||||
|> Enum.concat(reserved)
|
|> Enum.concat(reserved)
|
||||||
|> Enum.map(&InetHelper.parse_cidr/1)
|
|> Enum.map(&InetHelper.parse_cidr/1)
|
||||||
|
|
||||||
{headers, proxies}
|
clients =
|
||||||
|
Config.get([__MODULE__, :clients], [])
|
||||||
|
|> Enum.map(&InetHelper.parse_cidr/1)
|
||||||
|
|
||||||
|
[
|
||||||
|
headers: Config.get([__MODULE__, :headers], []),
|
||||||
|
clients: clients,
|
||||||
|
proxies: proxies
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
defp client?(ip, opts) do
|
||||||
|
client_ip?(ip, opts[:clients]) || !proxy_ip?(ip, opts[:proxies])
|
||||||
|
end
|
||||||
|
|
||||||
|
defp client_ip?(ip, clients) do
|
||||||
|
Enum.any?(clients, &InetCidr.contains?(&1, ip))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp proxy_ip?(ip, proxies) do
|
||||||
|
Enum.any?(proxies, &InetCidr.contains?(&1, ip))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,7 @@ defmodule Pleroma.Web.Router do
|
||||||
pipeline :http_signature do
|
pipeline :http_signature do
|
||||||
plug(Pleroma.Web.Plugs.HTTPSignaturePlug)
|
plug(Pleroma.Web.Plugs.HTTPSignaturePlug)
|
||||||
plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)
|
plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)
|
||||||
|
plug(Pleroma.Web.Plugs.EnsureHostMatchesPlug)
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :inbox_guard do
|
pipeline :inbox_guard do
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ defmodule Pleroma.Workers.SignatureRetryWorker do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.Federator
|
alias Pleroma.Web.Federator
|
||||||
|
alias Pleroma.Web.Plugs.EnsureHostMatchesPlug
|
||||||
alias Pleroma.Web.Plugs.MappedSignatureToIdentityPlug
|
alias Pleroma.Web.Plugs.MappedSignatureToIdentityPlug
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
@ -48,6 +49,7 @@ defmodule Pleroma.Workers.SignatureRetryWorker do
|
||||||
{:ok, _public_key} <- Signature.refetch_public_key(conn_data),
|
{:ok, _public_key} <- Signature.refetch_public_key(conn_data),
|
||||||
{:signature, true} <- {:signature, validate_signature(conn_data)},
|
{:signature, true} <- {:signature, validate_signature(conn_data)},
|
||||||
{:same_actor, true} <- {:same_actor, validate_same_actor(conn_data)},
|
{:same_actor, true} <- {:same_actor, validate_same_actor(conn_data)},
|
||||||
|
{:host_header, true} <- {:host_header, validate_host_header(conn_data)},
|
||||||
{:ok, res} <- Federator.perform(:incoming_ap_doc, params) do
|
{:ok, res} <- Federator.perform(:incoming_ap_doc, params) do
|
||||||
unless Instances.reachable?(params["actor"]) do
|
unless Instances.reachable?(params["actor"]) do
|
||||||
domain = URI.parse(params["actor"]).host
|
domain = URI.parse(params["actor"]).host
|
||||||
|
|
@ -103,6 +105,16 @@ defmodule Pleroma.Workers.SignatureRetryWorker do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp validate_host_header(conn_data) do
|
||||||
|
case EnsureHostMatchesPlug.call(conn_data, []) do
|
||||||
|
%Plug.Conn{assigns: %{valid_signature: true, valid_host_header: true}} ->
|
||||||
|
true
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp validate_same_actor(conn_data) do
|
defp validate_same_actor(conn_data) do
|
||||||
case MappedSignatureToIdentityPlug.call(conn_data, []) do
|
case MappedSignatureToIdentityPlug.call(conn_data, []) do
|
||||||
%Plug.Conn{assigns: %{valid_signature: true}} ->
|
%Plug.Conn{assigns: %{valid_signature: true}} ->
|
||||||
|
|
@ -170,6 +182,10 @@ defmodule Pleroma.Workers.SignatureRetryWorker do
|
||||||
{:same_actor, false} ->
|
{:same_actor, false} ->
|
||||||
{:cancel, :actor_signature_mismatch}
|
{:cancel, :actor_signature_mismatch}
|
||||||
|
|
||||||
|
# Host header from request not for us
|
||||||
|
{:host_header, false} ->
|
||||||
|
{:cancel, :host_header_mismatch}
|
||||||
|
|
||||||
# Origin / URL validation failed somewhere possibly due to spoofing
|
# Origin / URL validation failed somewhere possibly due to spoofing
|
||||||
{:error, :origin_containment_failed} ->
|
{:error, :origin_containment_failed} ->
|
||||||
{:cancel, :origin_containment_failed}
|
{:cancel, :origin_containment_failed}
|
||||||
|
|
@ -234,6 +250,7 @@ defmodule Pleroma.Workers.SignatureRetryWorker do
|
||||||
defp log_signature_retry_rejection({:cancel, reason}, context)
|
defp log_signature_retry_rejection({:cancel, reason}, context)
|
||||||
when reason in [
|
when reason in [
|
||||||
:actor_signature_mismatch,
|
:actor_signature_mismatch,
|
||||||
|
:host_header_mismatch,
|
||||||
:invalid_signature,
|
:invalid_signature,
|
||||||
:invalid_signature_retry_metadata,
|
:invalid_signature_retry_metadata,
|
||||||
:missing_signature_retry_metadata,
|
:missing_signature_retry_metadata,
|
||||||
|
|
|
||||||
15
mix.exs
15
mix.exs
|
|
@ -136,9 +136,7 @@ defmodule Pleroma.Mixfile do
|
||||||
{:tzdata, "~> 1.0.5"},
|
{:tzdata, "~> 1.0.5"},
|
||||||
{:plug_cowboy, "~> 2.7"},
|
{:plug_cowboy, "~> 2.7"},
|
||||||
{:oban, "~> 2.19.4"},
|
{:oban, "~> 2.19.4"},
|
||||||
{:oban_plugins_lazarus,
|
{:oban_plugins_lazarus, "~> 0.1.1"},
|
||||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/oban_plugins_lazarus.git",
|
|
||||||
ref: "e49fc355baaf0e435208bf5f534d31e26e897711"},
|
|
||||||
{:oban_web, "~> 2.11"},
|
{:oban_web, "~> 2.11"},
|
||||||
{:gettext, "~> 0.24"},
|
{:gettext, "~> 0.24"},
|
||||||
{:bcrypt_elixir, "~> 2.3"},
|
{:bcrypt_elixir, "~> 2.3"},
|
||||||
|
|
@ -183,14 +181,11 @@ defmodule Pleroma.Mixfile do
|
||||||
{:plug_static_index_html, "~> 1.0.0"},
|
{:plug_static_index_html, "~> 1.0.0"},
|
||||||
{:flake_id, "~> 0.1.0"},
|
{:flake_id, "~> 0.1.0"},
|
||||||
{:concurrent_limiter, "~> 0.1.1"},
|
{:concurrent_limiter, "~> 0.1.1"},
|
||||||
{:remote_ip,
|
{:remote_ip, "~> 1.2.0"},
|
||||||
git: "https://git.pleroma.social/pleroma/remote_ip.git",
|
{:inet_cidr, "~> 1.0"},
|
||||||
ref: "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8"},
|
{:captcha, "~> 1.0.3", hex: :pleroma_captcha},
|
||||||
{:captcha,
|
|
||||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git",
|
|
||||||
ref: "e7b7cc34cc16b383461b966484c297e4ec9aeef6"},
|
|
||||||
{:restarter, path: "./restarter"},
|
{:restarter, path: "./restarter"},
|
||||||
{:majic, "~> 1.1"},
|
{:majic, "~> 1.2"},
|
||||||
{:open_api_spex, "~> 3.22"},
|
{:open_api_spex, "~> 3.22"},
|
||||||
{:ecto_psql_extras, "~> 0.8"},
|
{:ecto_psql_extras, "~> 0.8"},
|
||||||
{:vix, "~> 0.36"},
|
{:vix, "~> 0.36"},
|
||||||
|
|
|
||||||
10
mix.lock
10
mix.lock
|
|
@ -10,7 +10,7 @@
|
||||||
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
|
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
|
||||||
"cachex": {:hex, :cachex, "3.6.0", "14a1bfbeee060dd9bec25a5b6f4e4691e3670ebda28c8ba2884b12fe30b36bf8", [: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", "ebf24e373883bc8e0c8d894a63bbe102ae13d918f790121f5cfe6e485cc8e2e2"},
|
"cachex": {:hex, :cachex, "3.6.0", "14a1bfbeee060dd9bec25a5b6f4e4691e3670ebda28c8ba2884b12fe30b36bf8", [: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", "ebf24e373883bc8e0c8d894a63bbe102ae13d918f790121f5cfe6e485cc8e2e2"},
|
||||||
"calendar": {:hex, :calendar, "1.0.0", "f52073a708528482ec33d0a171954ca610fe2bd28f1e871f247dc7f1565fa807", [:mix], [{:tzdata, "~> 0.1.201603 or ~> 0.5.20 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "990e9581920c82912a5ee50e62ff5ef96da6b15949a2ee4734f935fdef0f0a6f"},
|
"calendar": {:hex, :calendar, "1.0.0", "f52073a708528482ec33d0a171954ca610fe2bd28f1e871f247dc7f1565fa807", [:mix], [{:tzdata, "~> 0.1.201603 or ~> 0.5.20 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "990e9581920c82912a5ee50e62ff5ef96da6b15949a2ee4734f935fdef0f0a6f"},
|
||||||
"captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "e7b7cc34cc16b383461b966484c297e4ec9aeef6", [ref: "e7b7cc34cc16b383461b966484c297e4ec9aeef6"]},
|
"captcha": {:hex, :pleroma_captcha, "1.0.3", "6cc1440e91a092653fe909f028cc4c5d83ea858b1439e3b9a85e446382e2b9a3", [:make, :mix], [], "hexpm", "477f62c1a845a9458c546658223295f958f98136acef89c05beb278b1b6f4a14"},
|
||||||
"castore": {:hex, :castore, "1.0.15", "8aa930c890fe18b6fe0a0cff27b27d0d4d231867897bd23ea772dee561f032a3", [:mix], [], "hexpm", "96ce4c69d7d5d7a0761420ef743e2f4096253931a3ba69e5ff8ef1844fe446d3"},
|
"castore": {:hex, :castore, "1.0.15", "8aa930c890fe18b6fe0a0cff27b27d0d4d231867897bd23ea772dee561f032a3", [:mix], [], "hexpm", "96ce4c69d7d5d7a0761420ef743e2f4096253931a3ba69e5ff8ef1844fe446d3"},
|
||||||
"cc_precompiler": {:hex, :cc_precompiler, "0.1.11", "8c844d0b9fb98a3edea067f94f616b3f6b29b959b6b3bf25fee94ffe34364768", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "3427232caf0835f94680e5bcf082408a70b48ad68a5f5c0b02a3bea9f3a075b9"},
|
"cc_precompiler": {:hex, :cc_precompiler, "0.1.11", "8c844d0b9fb98a3edea067f94f616b3f6b29b959b6b3bf25fee94ffe34364768", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "3427232caf0835f94680e5bcf082408a70b48ad68a5f5c0b02a3bea9f3a075b9"},
|
||||||
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
|
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
|
||||||
|
|
@ -65,7 +65,7 @@
|
||||||
"http_signatures": {:hex, :http_signatures, "0.1.3", "19f26aee35b4684e37efdce3ac4638605e6e41a04368186bd39d2b6138a60ea9", [:mix], [{:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "20313a65516db88006f85b090f6f76cc5b04e9609b45943657e6781eb91174f4"},
|
"http_signatures": {:hex, :http_signatures, "0.1.3", "19f26aee35b4684e37efdce3ac4638605e6e41a04368186bd39d2b6138a60ea9", [:mix], [{:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "20313a65516db88006f85b090f6f76cc5b04e9609b45943657e6781eb91174f4"},
|
||||||
"httpoison": {:hex, :httpoison, "1.8.2", "9eb9c63ae289296a544842ef816a85d881d4a31f518a0fec089aaa744beae290", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "2bb350d26972e30c96e2ca74a1aaf8293d61d0742ff17f01e0279fef11599921"},
|
"httpoison": {:hex, :httpoison, "1.8.2", "9eb9c63ae289296a544842ef816a85d881d4a31f518a0fec089aaa744beae290", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "2bb350d26972e30c96e2ca74a1aaf8293d61d0742ff17f01e0279fef11599921"},
|
||||||
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
|
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
|
||||||
"inet_cidr": {:hex, :inet_cidr, "1.0.8", "d26bb7bdbdf21ae401ead2092bf2bb4bf57fe44a62f5eaa5025280720ace8a40", [:mix], [], "hexpm", "d5b26da66603bb56c933c65214c72152f0de9a6ea53618b56d63302a68f6a90e"},
|
"inet_cidr": {:hex, :inet_cidr, "1.0.9", "e0ef72a2942529da78c8e4147d53f2ef5f6f5293335c3637b0fdf83c012cc816", [:mix], [], "hexpm", "172da15ff7cf635b1feaf14f5818be28c811b37cc5fb7c5f7c01058c1c1066cc"},
|
||||||
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
|
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
|
||||||
"joken": {:hex, :joken, "2.6.2", "5daaf82259ca603af4f0b065475099ada1b2b849ff140ccd37f4b6828ca6892a", [:mix], [{:jose, "~> 1.11.10", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "5134b5b0a6e37494e46dbf9e4dad53808e5e787904b7c73972651b51cce3d72b"},
|
"joken": {:hex, :joken, "2.6.2", "5daaf82259ca603af4f0b065475099ada1b2b849ff140ccd37f4b6828ca6892a", [:mix], [{:jose, "~> 1.11.10", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "5134b5b0a6e37494e46dbf9e4dad53808e5e787904b7c73972651b51cce3d72b"},
|
||||||
"jose": {:hex, :jose, "1.11.10", "a903f5227417bd2a08c8a00a0cbcc458118be84480955e8d251297a425723f83", [:mix, :rebar3], [], "hexpm", "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"},
|
"jose": {:hex, :jose, "1.11.10", "a903f5227417bd2a08c8a00a0cbcc458118be84480955e8d251297a425723f83", [:mix, :rebar3], [], "hexpm", "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"},
|
||||||
|
|
@ -73,7 +73,7 @@
|
||||||
"linkify": {:hex, :linkify, "0.5.3", "5f8143d8f61f5ff08d3aeeff47ef6509492b4948d8f08007fbf66e4d2246a7f2", [:mix], [], "hexpm", "3ef35a1377d47c25506e07c1c005ea9d38d700699d92ee92825f024434258177"},
|
"linkify": {:hex, :linkify, "0.5.3", "5f8143d8f61f5ff08d3aeeff47ef6509492b4948d8f08007fbf66e4d2246a7f2", [:mix], [], "hexpm", "3ef35a1377d47c25506e07c1c005ea9d38d700699d92ee92825f024434258177"},
|
||||||
"logger_backends": {:hex, :logger_backends, "1.0.0", "09c4fad6202e08cb0fbd37f328282f16539aca380f512523ce9472b28edc6bdf", [:mix], [], "hexpm", "1faceb3e7ec3ef66a8f5746c5afd020e63996df6fd4eb8cdb789e5665ae6c9ce"},
|
"logger_backends": {:hex, :logger_backends, "1.0.0", "09c4fad6202e08cb0fbd37f328282f16539aca380f512523ce9472b28edc6bdf", [:mix], [], "hexpm", "1faceb3e7ec3ef66a8f5746c5afd020e63996df6fd4eb8cdb789e5665ae6c9ce"},
|
||||||
"mail": {:hex, :mail, "0.3.1", "cb0a14e4ed8904e4e5a08214e686ccf6f9099346885db17d8c309381f865cc5c", [:mix], [], "hexpm", "1db701e89865c1d5fa296b2b57b1cd587587cca8d8a1a22892b35ef5a8e352a6"},
|
"mail": {:hex, :mail, "0.3.1", "cb0a14e4ed8904e4e5a08214e686ccf6f9099346885db17d8c309381f865cc5c", [:mix], [], "hexpm", "1db701e89865c1d5fa296b2b57b1cd587587cca8d8a1a22892b35ef5a8e352a6"},
|
||||||
"majic": {:hex, :majic, "1.1.1", "16092a3a3376cc5e13d207e82ec06e05a5561170465e50cc11cc4df8a5747938", [:make, :mix], [{:elixir_make, "~> 0.8.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "7fbb0372f0447b3f777056177d6ab3f009742e68474f850521ff56b84bd85b96"},
|
"majic": {:hex, :majic, "1.2.0", "414b69c1460ece692fa892a0ed6669b8db6a44c42bb3071cb723854f22e7bd78", [:make, :mix], [{:elixir_make, "~> 0.8.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0bd0c65f8e4dcc595757d957577f6151b59246da9614ba87debfdc641ccc0514"},
|
||||||
"makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
|
"makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
|
||||||
"makeup_elixir": {:hex, :makeup_elixir, "0.14.1", "4f0e96847c63c17841d42c08107405a005a2680eb9c7ccadfd757bd31dabccfb", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f2438b1a80eaec9ede832b5c41cd4f373b38fd7aa33e3b22d9db79e640cbde11"},
|
"makeup_elixir": {:hex, :makeup_elixir, "0.14.1", "4f0e96847c63c17841d42c08107405a005a2680eb9c7ccadfd757bd31dabccfb", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f2438b1a80eaec9ede832b5c41cd4f373b38fd7aa33e3b22d9db79e640cbde11"},
|
||||||
"makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"},
|
"makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"},
|
||||||
|
|
@ -96,7 +96,7 @@
|
||||||
"oban": {:hex, :oban, "2.19.4", "045adb10db1161dceb75c254782f97cdc6596e7044af456a59decb6d06da73c1", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:igniter, "~> 0.5", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5fcc6219e6464525b808d97add17896e724131f498444a292071bf8991c99f97"},
|
"oban": {:hex, :oban, "2.19.4", "045adb10db1161dceb75c254782f97cdc6596e7044af456a59decb6d06da73c1", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:igniter, "~> 0.5", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5fcc6219e6464525b808d97add17896e724131f498444a292071bf8991c99f97"},
|
||||||
"oban_live_dashboard": {:hex, :oban_live_dashboard, "0.1.1", "8aa4ceaf381c818f7d5c8185cc59942b8ac82ef0cf559881aacf8d3f8ac7bdd3", [:mix], [{:oban, "~> 2.15", [hex: :oban, repo: "hexpm", optional: false]}, {:phoenix_live_dashboard, "~> 0.7", [hex: :phoenix_live_dashboard, repo: "hexpm", optional: false]}], "hexpm", "16dc4ce9c9a95aa2e655e35ed4e675652994a8def61731a18af85e230e1caa63"},
|
"oban_live_dashboard": {:hex, :oban_live_dashboard, "0.1.1", "8aa4ceaf381c818f7d5c8185cc59942b8ac82ef0cf559881aacf8d3f8ac7bdd3", [:mix], [{:oban, "~> 2.15", [hex: :oban, repo: "hexpm", optional: false]}, {:phoenix_live_dashboard, "~> 0.7", [hex: :phoenix_live_dashboard, repo: "hexpm", optional: false]}], "hexpm", "16dc4ce9c9a95aa2e655e35ed4e675652994a8def61731a18af85e230e1caa63"},
|
||||||
"oban_met": {:hex, :oban_met, "1.0.5", "bb633ab06448dab2ef9194f6688d33b3d07fc3f2ad793a1a08f4dfbb2cc9fe50", [:mix], [{:oban, "~> 2.19", [hex: :oban, repo: "hexpm", optional: false]}], "hexpm", "64664d50805bbfd3903aeada1f3c39634652a87844797ee400b0bcc95a28f5ea"},
|
"oban_met": {:hex, :oban_met, "1.0.5", "bb633ab06448dab2ef9194f6688d33b3d07fc3f2ad793a1a08f4dfbb2cc9fe50", [:mix], [{:oban, "~> 2.19", [hex: :oban, repo: "hexpm", optional: false]}], "hexpm", "64664d50805bbfd3903aeada1f3c39634652a87844797ee400b0bcc95a28f5ea"},
|
||||||
"oban_plugins_lazarus": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/oban_plugins_lazarus.git", "e49fc355baaf0e435208bf5f534d31e26e897711", [ref: "e49fc355baaf0e435208bf5f534d31e26e897711"]},
|
"oban_plugins_lazarus": {:hex, :oban_plugins_lazarus, "0.1.1", "a5141d569e5b9f3bec8f4a958231d2c538af097d3c1ad06274f096fc06956821", [:mix], [{:oban, "< 3.0.0", [hex: :oban, repo: "hexpm", optional: false]}], "hexpm", "7e9c51bc44d33f71c0a52cf0cd5c8d4c70380ede065c1042013f5123f2fc9729"},
|
||||||
"oban_web": {:hex, :oban_web, "2.11.6", "53933cb4253c4d9f1098ee311c06f07935259f0e564dcf2d66bae4cc98e317fe", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}, {:oban, "~> 2.19", [hex: :oban, repo: "hexpm", optional: false]}, {:oban_met, "~> 1.0", [hex: :oban_met, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.7", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}], "hexpm", "576d94b705688c313694c2c114ca21aa0f8f2ad1b9ca45c052c5ba316d3e8d10"},
|
"oban_web": {:hex, :oban_web, "2.11.6", "53933cb4253c4d9f1098ee311c06f07935259f0e564dcf2d66bae4cc98e317fe", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}, {:oban, "~> 2.19", [hex: :oban, repo: "hexpm", optional: false]}, {:oban_met, "~> 1.0", [hex: :oban_met, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.7", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}], "hexpm", "576d94b705688c313694c2c114ca21aa0f8f2ad1b9ca45c052c5ba316d3e8d10"},
|
||||||
"octo_fetch": {:hex, :octo_fetch, "0.4.0", "074b5ecbc08be10b05b27e9db08bc20a3060142769436242702931c418695b19", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "cf8be6f40cd519d7000bb4e84adcf661c32e59369ca2827c4e20042eda7a7fc6"},
|
"octo_fetch": {:hex, :octo_fetch, "0.4.0", "074b5ecbc08be10b05b27e9db08bc20a3060142769436242702931c418695b19", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "cf8be6f40cd519d7000bb4e84adcf661c32e59369ca2827c4e20042eda7a7fc6"},
|
||||||
"open_api_spex": {:hex, :open_api_spex, "3.22.0", "fbf90dc82681dc042a4ee79853c8e989efbba73d9e87439085daf849bbf8bc20", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0 or ~> 6.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "dd751ddbdd709bb4a5313e9a24530da6e66594773c7242a0c2592cbd9f589063"},
|
"open_api_spex": {:hex, :open_api_spex, "3.22.0", "fbf90dc82681dc042a4ee79853c8e989efbba73d9e87439085daf849bbf8bc20", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0 or ~> 6.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "dd751ddbdd709bb4a5313e9a24530da6e66594773c7242a0c2592cbd9f589063"},
|
||||||
|
|
@ -132,7 +132,7 @@
|
||||||
"quic": {:hex, :quic, "0.10.2", "4b390507a85f65ce47808f3df1a864e0baf9adb7a1b4ea9f4dcd66fe9d0cb166", [:rebar3], [], "hexpm", "7c196a66973c877a59768a5687f0a0610ff11817254d0a4e45cc4e3a16b1d00b"},
|
"quic": {:hex, :quic, "0.10.2", "4b390507a85f65ce47808f3df1a864e0baf9adb7a1b4ea9f4dcd66fe9d0cb166", [:rebar3], [], "hexpm", "7c196a66973c877a59768a5687f0a0610ff11817254d0a4e45cc4e3a16b1d00b"},
|
||||||
"ranch": {:hex, :ranch, "2.2.0", "25528f82bc8d7c6152c57666ca99ec716510fe0925cb188172f41ce93117b1b0", [:make, :rebar3], [], "hexpm", "fa0b99a1780c80218a4197a59ea8d3bdae32fbff7e88527d7d8a4787eff4f8e7"},
|
"ranch": {:hex, :ranch, "2.2.0", "25528f82bc8d7c6152c57666ca99ec716510fe0925cb188172f41ce93117b1b0", [:make, :rebar3], [], "hexpm", "fa0b99a1780c80218a4197a59ea8d3bdae32fbff7e88527d7d8a4787eff4f8e7"},
|
||||||
"recon": {:hex, :recon, "2.5.6", "9052588e83bfedfd9b72e1034532aee2a5369d9d9343b61aeb7fbce761010741", [:mix, :rebar3], [], "hexpm", "96c6799792d735cc0f0fd0f86267e9d351e63339cbe03df9d162010cefc26bb0"},
|
"recon": {:hex, :recon, "2.5.6", "9052588e83bfedfd9b72e1034532aee2a5369d9d9343b61aeb7fbce761010741", [:mix, :rebar3], [], "hexpm", "96c6799792d735cc0f0fd0f86267e9d351e63339cbe03df9d162010cefc26bb0"},
|
||||||
"remote_ip": {:git, "https://git.pleroma.social/pleroma/remote_ip.git", "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8", [ref: "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8"]},
|
"remote_ip": {:hex, :remote_ip, "1.2.0", "fb078e12a44414f4cef5a75963c33008fe169b806572ccd17257c208a7bc760f", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "2ff91de19c48149ce19ed230a81d377186e4412552a597d6a5137373e5877cb7"},
|
||||||
"rustler": {:hex, :rustler, "0.30.0", "cefc49922132b072853fa9b0ca4dc2ffcb452f68fb73b779042b02d545e097fb", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:toml, "~> 0.6", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "9ef1abb6a7dda35c47cfc649e6a5a61663af6cf842a55814a554a84607dee389"},
|
"rustler": {:hex, :rustler, "0.30.0", "cefc49922132b072853fa9b0ca4dc2ffcb452f68fb73b779042b02d545e097fb", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:toml, "~> 0.6", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "9ef1abb6a7dda35c47cfc649e6a5a61663af6cf842a55814a554a84607dee389"},
|
||||||
"sleeplocks": {:hex, :sleeplocks, "1.1.3", "96a86460cc33b435c7310dbd27ec82ca2c1f24ae38e34f8edde97f756503441a", [:rebar3], [], "hexpm", "d3b3958552e6eb16f463921e70ae7c767519ef8f5be46d7696cc1ed649421321"},
|
"sleeplocks": {:hex, :sleeplocks, "1.1.3", "96a86460cc33b435c7310dbd27ec82ca2c1f24ae38e34f8edde97f756503441a", [:rebar3], [], "hexpm", "d3b3958552e6eb16f463921e70ae7c767519ef8f5be46d7696cc1ed649421321"},
|
||||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
|
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2022-07-22 02:09+0300\n"
|
"POT-Creation-Date: 2022-07-22 02:09+0300\n"
|
||||||
"PO-Revision-Date: 2024-10-13 21:03+0000\n"
|
"PO-Revision-Date: 2025-12-27 07:08+0000\n"
|
||||||
"Last-Translator: Codimp <contact@lithio.fr>\n"
|
"Last-Translator: Codimp <contact@lithio.fr>\n"
|
||||||
"Language-Team: French <https://translate.pleroma.social/projects/pleroma/"
|
"Language-Team: French <https://translate.pleroma.social/projects/pleroma/"
|
||||||
"pleroma-backend-domain-config_descriptions/fr/>\n"
|
"pleroma-backend-domain-config_descriptions/fr/>\n"
|
||||||
|
|
@ -280,7 +280,7 @@ msgstr ""
|
||||||
"Rejeter, Enlever de TWKN ou marquer comme contenu sensible les messages avec "
|
"Rejeter, Enlever de TWKN ou marquer comme contenu sensible les messages avec "
|
||||||
"des mots-croisillons (sans mettre le # du début)\n"
|
"des mots-croisillons (sans mettre le # du début)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Note: cette politique MRF est toujours activée. Si vous voulez la "
|
"Note : cette politique MRF est toujours activée. Si vous voulez la "
|
||||||
"désactiver, vous devez configurer des listes vides.\n"
|
"désactiver, vous devez configurer des listes vides.\n"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
|
|
@ -402,7 +402,7 @@ msgstr ""
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-:shout"
|
msgctxt "config description at :pleroma-:shout"
|
||||||
msgid "Pleroma shout settings"
|
msgid "Pleroma shout settings"
|
||||||
msgstr ""
|
msgstr "Paramètre de Pleroma shout"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
|
|
@ -416,7 +416,7 @@ msgstr ""
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-:streamer"
|
msgctxt "config description at :pleroma-:streamer"
|
||||||
msgid "Settings for notifications streamer"
|
msgid "Settings for notifications streamer"
|
||||||
msgstr ""
|
msgstr "Paramètres des streamers de notifications"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
|
|
@ -429,12 +429,14 @@ msgstr "Paramètres liés au schémas d'URI"
|
||||||
msgctxt "config description at :pleroma-:web_cache_ttl"
|
msgctxt "config description at :pleroma-:web_cache_ttl"
|
||||||
msgid "The expiration time for the web responses cache. Values should be in milliseconds or `nil` to disable expiration."
|
msgid "The expiration time for the web responses cache. Values should be in milliseconds or `nil` to disable expiration."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Temps d'expiration pour le cache des réponses web. Les valeurs doivent être "
|
||||||
|
"en millisecondes ou `nil`pour désactiver l'expiration."
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-:welcome"
|
msgctxt "config description at :pleroma-:welcome"
|
||||||
msgid "Welcome messages settings"
|
msgid "Welcome messages settings"
|
||||||
msgstr ""
|
msgstr "Paramètres de messages de bienvenue"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
|
|
@ -458,133 +460,146 @@ msgstr ""
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Captcha"
|
msgctxt "config description at :pleroma-Pleroma.Captcha"
|
||||||
msgid "Captcha-related settings"
|
msgid "Captcha-related settings"
|
||||||
msgstr ""
|
msgstr "Paramètres liés au Captcha"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Captcha.Kocaptcha"
|
msgctxt "config description at :pleroma-Pleroma.Captcha.Kocaptcha"
|
||||||
msgid "Kocaptcha is a very simple captcha service with a single API endpoint, the source code is here: https://github.com/koto-bank/kocaptcha. The default endpoint (https://captcha.kotobank.ch) is hosted by the developer."
|
msgid "Kocaptcha is a very simple captcha service with a single API endpoint, the source code is here: https://github.com/koto-bank/kocaptcha. The default endpoint (https://captcha.kotobank.ch) is hosted by the developer."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Kocaptcha est un service de captcha très simple avec une API n'utilisant "
|
||||||
|
"qu'une seule ressource, le code source est ici : https://github.com/"
|
||||||
|
"koto-bank/kocaptcha. La ressource par défaut (https://captcha.kotobank.ch) "
|
||||||
|
"est hébergée par son développeur."
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Emails.Mailer"
|
msgctxt "config description at :pleroma-Pleroma.Emails.Mailer"
|
||||||
msgid "Mailer-related settings"
|
msgid "Mailer-related settings"
|
||||||
msgstr ""
|
msgstr "Paramètres liés à l'envoyeur d'email"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Emails.NewUsersDigestEmail"
|
msgctxt "config description at :pleroma-Pleroma.Emails.NewUsersDigestEmail"
|
||||||
msgid "New users admin email digest"
|
msgid "New users admin email digest"
|
||||||
msgstr ""
|
msgstr "Email à l'administrateur de résumé des nouveaux utilisateurs"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Emails.UserEmail"
|
msgctxt "config description at :pleroma-Pleroma.Emails.UserEmail"
|
||||||
msgid "Email template settings"
|
msgid "Email template settings"
|
||||||
msgstr ""
|
msgstr "Paramètres de template d'email"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Formatter"
|
msgctxt "config description at :pleroma-Pleroma.Formatter"
|
||||||
msgid "Configuration for Pleroma's link formatter which parses mentions, hashtags, and URLs."
|
msgid "Configuration for Pleroma's link formatter which parses mentions, hashtags, and URLs."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Configuration du formateur de lien Pleroma qui interprète les mentions, "
|
||||||
|
"hashtags et URLs."
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.ScheduledActivity"
|
msgctxt "config description at :pleroma-Pleroma.ScheduledActivity"
|
||||||
msgid "Scheduled activities settings"
|
msgid "Scheduled activities settings"
|
||||||
msgstr ""
|
msgstr "Paramètres des activités planifiées"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Upload"
|
msgctxt "config description at :pleroma-Pleroma.Upload"
|
||||||
msgid "Upload general settings"
|
msgid "Upload general settings"
|
||||||
msgstr ""
|
msgstr "Paramètres généraux d'upload"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename"
|
msgctxt "config description at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename"
|
||||||
msgid "Filter replaces the filename of the upload"
|
msgid "Filter replaces the filename of the upload"
|
||||||
msgstr ""
|
msgstr "Filtre de remplacement du nom de fichier de l'upload"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Upload.Filter.Mogrify"
|
msgctxt "config description at :pleroma-Pleroma.Upload.Filter.Mogrify"
|
||||||
msgid "Uploads mogrify filter settings"
|
msgid "Uploads mogrify filter settings"
|
||||||
msgstr ""
|
msgstr "Paramètres de filtre mogrify pour les uploads"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Uploaders.Local"
|
msgctxt "config description at :pleroma-Pleroma.Uploaders.Local"
|
||||||
msgid "Local uploader-related settings"
|
msgid "Local uploader-related settings"
|
||||||
msgstr ""
|
msgstr "Paramètres liés aux uploads locaux"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Uploaders.S3"
|
msgctxt "config description at :pleroma-Pleroma.Uploaders.S3"
|
||||||
msgid "S3 uploader-related settings"
|
msgid "S3 uploader-related settings"
|
||||||
msgstr ""
|
msgstr "Paramètres liés à l'uploader S3"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.User.Backup"
|
msgctxt "config description at :pleroma-Pleroma.User.Backup"
|
||||||
msgid "Account Backup"
|
msgid "Account Backup"
|
||||||
msgstr ""
|
msgstr "Sauvegarde de Comptes"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http"
|
msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http"
|
||||||
msgid "HTTP invalidate settings"
|
msgid "HTTP invalidate settings"
|
||||||
msgstr ""
|
msgstr "Paramètres d'invalidation HTTP"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script"
|
msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script"
|
||||||
msgid "Invalidation script settings"
|
msgid "Invalidation script settings"
|
||||||
msgstr ""
|
msgstr "Paramètres du script d'invalidation"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Web.Metadata"
|
msgctxt "config description at :pleroma-Pleroma.Web.Metadata"
|
||||||
msgid "Metadata-related settings"
|
msgid "Metadata-related settings"
|
||||||
msgstr ""
|
msgstr "Paramètres liés aux métadonnées"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Web.Plugs.RemoteIp"
|
msgctxt "config description at :pleroma-Pleroma.Web.Plugs.RemoteIp"
|
||||||
msgid "`Pleroma.Web.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration.\n**If your instance is not behind at least one reverse proxy, you should not enable this plug.**\n"
|
msgid "`Pleroma.Web.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration.\n**If your instance is not behind at least one reverse proxy, you should not enable this plug.**\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"`Pleroma.Web.Plugs.RemoteIp` est un shim pour invoquer "
|
||||||
|
"[`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) mais avec une "
|
||||||
|
"configuration au runtime.\n"
|
||||||
|
"**Si votre instance n'est pas derrière au moins un proxy inverse, vous ne "
|
||||||
|
"devriez pas activer ce plug.**\n"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Web.Preload"
|
msgctxt "config description at :pleroma-Pleroma.Web.Preload"
|
||||||
msgid "Preload-related settings"
|
msgid "Preload-related settings"
|
||||||
msgstr ""
|
msgstr "Paramètres liés au préchargement"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :pleroma-Pleroma.Workers.PurgeExpiredActivity"
|
msgctxt "config description at :pleroma-Pleroma.Workers.PurgeExpiredActivity"
|
||||||
msgid "Expired activities settings"
|
msgid "Expired activities settings"
|
||||||
msgstr ""
|
msgstr "Paramètres des activités expirées"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter"
|
msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter"
|
||||||
msgid "Prometheus app metrics endpoint configuration"
|
msgid "Prometheus app metrics endpoint configuration"
|
||||||
msgstr ""
|
msgstr "Configuration des endpoints de métriques Prometheus"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config description at :web_push_encryption-:vapid_details"
|
msgctxt "config description at :web_push_encryption-:vapid_details"
|
||||||
msgid "Web Push Notifications configuration. You can use the mix task mix web_push.gen.keypair to generate it."
|
msgid "Web Push Notifications configuration. You can use the mix task mix web_push.gen.keypair to generate it."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Configuration des notifications Web Push. Vous pouvez utiliser la tâche mix "
|
||||||
|
"web_push.gen.keypair pour le générer."
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :ex_aws-:s3"
|
msgctxt "config label at :ex_aws-:s3"
|
||||||
msgid "S3"
|
msgid "S3"
|
||||||
msgstr ""
|
msgstr "S3"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
|
|
@ -596,13 +611,13 @@ msgstr ""
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :logger-:ex_syslogger"
|
msgctxt "config label at :logger-:ex_syslogger"
|
||||||
msgid "ExSyslogger"
|
msgid "ExSyslogger"
|
||||||
msgstr ""
|
msgstr "ExSyslogger"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:activitypub"
|
msgctxt "config label at :pleroma-:activitypub"
|
||||||
msgid "ActivityPub"
|
msgid "ActivityPub"
|
||||||
msgstr ""
|
msgstr "ActivityPub"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
|
|
@ -620,151 +635,151 @@ msgstr ""
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:connections_pool"
|
msgctxt "config label at :pleroma-:connections_pool"
|
||||||
msgid "Connections pool"
|
msgid "Connections pool"
|
||||||
msgstr ""
|
msgstr "Pool de connexions"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:email_notifications"
|
msgctxt "config label at :pleroma-:email_notifications"
|
||||||
msgid "Email notifications"
|
msgid "Email notifications"
|
||||||
msgstr ""
|
msgstr "Notifications email"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:emoji"
|
msgctxt "config label at :pleroma-:emoji"
|
||||||
msgid "Emoji"
|
msgid "Emoji"
|
||||||
msgstr ""
|
msgstr "Emoji"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:features"
|
msgctxt "config label at :pleroma-:features"
|
||||||
msgid "Features"
|
msgid "Features"
|
||||||
msgstr ""
|
msgstr "Fonctionnalités"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:feed"
|
msgctxt "config label at :pleroma-:feed"
|
||||||
msgid "Feed"
|
msgid "Feed"
|
||||||
msgstr ""
|
msgstr "Flux"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:frontend_configurations"
|
msgctxt "config label at :pleroma-:frontend_configurations"
|
||||||
msgid "Frontend configurations"
|
msgid "Frontend configurations"
|
||||||
msgstr ""
|
msgstr "Configurations des frontends"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:frontends"
|
msgctxt "config label at :pleroma-:frontends"
|
||||||
msgid "Frontends"
|
msgid "Frontends"
|
||||||
msgstr ""
|
msgstr "Frontends"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:gopher"
|
msgctxt "config label at :pleroma-:gopher"
|
||||||
msgid "Gopher"
|
msgid "Gopher"
|
||||||
msgstr ""
|
msgstr "Gopher"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:hackney_pools"
|
msgctxt "config label at :pleroma-:hackney_pools"
|
||||||
msgid "Hackney pools"
|
msgid "Hackney pools"
|
||||||
msgstr ""
|
msgstr "Bacs (pools) d'Hackney"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:http"
|
msgctxt "config label at :pleroma-:http"
|
||||||
msgid "HTTP"
|
msgid "HTTP"
|
||||||
msgstr ""
|
msgstr "HTTP"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:http_security"
|
msgctxt "config label at :pleroma-:http_security"
|
||||||
msgid "HTTP security"
|
msgid "HTTP security"
|
||||||
msgstr ""
|
msgstr "Sécurité HTTP"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:instance"
|
msgctxt "config label at :pleroma-:instance"
|
||||||
msgid "Instance"
|
msgid "Instance"
|
||||||
msgstr ""
|
msgstr "Instance"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:instances_favicons"
|
msgctxt "config label at :pleroma-:instances_favicons"
|
||||||
msgid "Instances favicons"
|
msgid "Instances favicons"
|
||||||
msgstr ""
|
msgstr "Favicons des instances"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:ldap"
|
msgctxt "config label at :pleroma-:ldap"
|
||||||
msgid "LDAP"
|
msgid "LDAP"
|
||||||
msgstr ""
|
msgstr "LDAP"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:majic_pool"
|
msgctxt "config label at :pleroma-:majic_pool"
|
||||||
msgid "Majic pool"
|
msgid "Majic pool"
|
||||||
msgstr ""
|
msgstr "Bac (pool) de Majic"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:manifest"
|
msgctxt "config label at :pleroma-:manifest"
|
||||||
msgid "Manifest"
|
msgid "Manifest"
|
||||||
msgstr ""
|
msgstr "Manifeste"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:markup"
|
msgctxt "config label at :pleroma-:markup"
|
||||||
msgid "Markup Settings"
|
msgid "Markup Settings"
|
||||||
msgstr ""
|
msgstr "Paramètres des Balises"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:media_preview_proxy"
|
msgctxt "config label at :pleroma-:media_preview_proxy"
|
||||||
msgid "Media preview proxy"
|
msgid "Media preview proxy"
|
||||||
msgstr ""
|
msgstr "Proxy de prévisualisation média"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:media_proxy"
|
msgctxt "config label at :pleroma-:media_proxy"
|
||||||
msgid "Media proxy"
|
msgid "Media proxy"
|
||||||
msgstr ""
|
msgstr "Proxy média"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:modules"
|
msgctxt "config label at :pleroma-:modules"
|
||||||
msgid "Modules"
|
msgid "Modules"
|
||||||
msgstr ""
|
msgstr "Modules"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:mrf"
|
msgctxt "config label at :pleroma-:mrf"
|
||||||
msgid "MRF"
|
msgid "MRF"
|
||||||
msgstr ""
|
msgstr "MRF"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:mrf_activity_expiration"
|
msgctxt "config label at :pleroma-:mrf_activity_expiration"
|
||||||
msgid "MRF Activity Expiration Policy"
|
msgid "MRF Activity Expiration Policy"
|
||||||
msgstr ""
|
msgstr "Politique MRF d'Expiration des Activités"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:mrf_follow_bot"
|
msgctxt "config label at :pleroma-:mrf_follow_bot"
|
||||||
msgid "MRF FollowBot Policy"
|
msgid "MRF FollowBot Policy"
|
||||||
msgstr ""
|
msgstr "Politique MRF FollowBot"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:mrf_hashtag"
|
msgctxt "config label at :pleroma-:mrf_hashtag"
|
||||||
msgid "MRF Hashtag"
|
msgid "MRF Hashtag"
|
||||||
msgstr ""
|
msgstr "Politique MRF hashtag"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgctxt "config label at :pleroma-:mrf_hellthread"
|
msgctxt "config label at :pleroma-:mrf_hellthread"
|
||||||
msgid "MRF Hellthread"
|
msgid "MRF Hellthread"
|
||||||
msgstr ""
|
msgstr "MRF Hellthread"
|
||||||
|
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,15 @@
|
||||||
## to merge POT files into PO files.
|
## to merge POT files into PO files.
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"PO-Revision-Date: 2020-05-12 15:52+0000\n"
|
"PO-Revision-Date: 2025-12-27 07:08+0000\n"
|
||||||
"Last-Translator: Haelwenn (lanodan) Monnier "
|
"Last-Translator: Codimp <contact@lithio.fr>\n"
|
||||||
"<contact+translate.pleroma.social@hacktivis.me>\n"
|
|
||||||
"Language-Team: French <https://translate.pleroma.social/projects/pleroma/"
|
"Language-Team: French <https://translate.pleroma.social/projects/pleroma/"
|
||||||
"pleroma/fr/>\n"
|
"pleroma-backend-domain-errors/fr/>\n"
|
||||||
"Language: fr\n"
|
"Language: fr\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
|
||||||
"X-Generator: Weblate 4.0.4\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||||
|
"X-Generator: Weblate 4.13.1\n"
|
||||||
|
|
||||||
msgid "can't be blank"
|
msgid "can't be blank"
|
||||||
msgstr "ne peut être vide"
|
msgstr "ne peut être vide"
|
||||||
|
|
@ -357,7 +356,7 @@ msgstr "Ne peut poster dans la boite d'émission de %{nickname} en tant que %{as
|
||||||
#: lib/pleroma/web/common_api/common_api.ex:335
|
#: lib/pleroma/web/common_api/common_api.ex:335
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "conversation is already muted"
|
msgid "conversation is already muted"
|
||||||
msgstr "la conversation est déjà baillonée"
|
msgstr "la conversation est déjà silenciée"
|
||||||
|
|
||||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:192
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:192
|
||||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:317
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:317
|
||||||
|
|
@ -421,7 +420,7 @@ msgstr "Erreur interne"
|
||||||
#: lib/pleroma/web/oauth/fallback_controller.ex:29
|
#: lib/pleroma/web/oauth/fallback_controller.ex:29
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Invalid Username/Password"
|
msgid "Invalid Username/Password"
|
||||||
msgstr "Nom d'utilisateur/mot de passe invalide"
|
msgstr "Nom d'utilisateur·ice/mot de passe invalide"
|
||||||
|
|
||||||
#: lib/pleroma/captcha/captcha.ex:107
|
#: lib/pleroma/captcha/captcha.ex:107
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,16 @@ msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-08-15 15:40+0000\n"
|
"POT-Creation-Date: 2021-08-15 15:40+0000\n"
|
||||||
"PO-Revision-Date: 2021-09-03 06:45+0000\n"
|
"PO-Revision-Date: 2025-07-31 05:58+0000\n"
|
||||||
"Last-Translator: @liimee <alt3753.7@gmail.com>\n"
|
"Last-Translator: Neko Nekowazarashi <kodra@nekoweb.my.id>\n"
|
||||||
"Language-Team: Indonesian <https://translate.pleroma.social/projects/pleroma/"
|
"Language-Team: Indonesian <https://translate.pleroma.social/projects/pleroma/"
|
||||||
"pleroma/id/>\n"
|
"pleroma-backend-domain-errors/id/>\n"
|
||||||
"Language: id\n"
|
"Language: id\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
"X-Generator: Weblate 4.6.2\n"
|
"X-Generator: Weblate 4.13.1\n"
|
||||||
|
|
||||||
## This file is a PO Template file.
|
## This file is a PO Template file.
|
||||||
##
|
##
|
||||||
|
|
@ -41,7 +41,7 @@ msgstr "memiliki format yang tidak valid"
|
||||||
|
|
||||||
## From Ecto.Changeset.validate_subset/3
|
## From Ecto.Changeset.validate_subset/3
|
||||||
msgid "has an invalid entry"
|
msgid "has an invalid entry"
|
||||||
msgstr ""
|
msgstr "ada yang tidak valid"
|
||||||
|
|
||||||
## From Ecto.Changeset.validate_exclusion/3
|
## From Ecto.Changeset.validate_exclusion/3
|
||||||
msgid "is reserved"
|
msgid "is reserved"
|
||||||
|
|
@ -49,7 +49,7 @@ msgstr ""
|
||||||
|
|
||||||
## From Ecto.Changeset.validate_confirmation/3
|
## From Ecto.Changeset.validate_confirmation/3
|
||||||
msgid "does not match confirmation"
|
msgid "does not match confirmation"
|
||||||
msgstr ""
|
msgstr "tidak sama dengan konfirmasi"
|
||||||
|
|
||||||
## From Ecto.Changeset.no_assoc_constraint/3
|
## From Ecto.Changeset.no_assoc_constraint/3
|
||||||
msgid "is still associated with this entry"
|
msgid "is still associated with this entry"
|
||||||
|
|
@ -61,19 +61,19 @@ msgstr ""
|
||||||
## From Ecto.Changeset.validate_length/3
|
## From Ecto.Changeset.validate_length/3
|
||||||
msgid "should be %{count} character(s)"
|
msgid "should be %{count} character(s)"
|
||||||
msgid_plural "should be %{count} character(s)"
|
msgid_plural "should be %{count} character(s)"
|
||||||
msgstr[0] "harus memiliki %{count} karakter"
|
msgstr[0] "harus ada %{count} karakter"
|
||||||
|
|
||||||
msgid "should have %{count} item(s)"
|
msgid "should have %{count} item(s)"
|
||||||
msgid_plural "should have %{count} item(s)"
|
msgid_plural "should have %{count} item(s)"
|
||||||
msgstr[0] "harus memiliki %{count} item"
|
msgstr[0] "harus ada %{count} item"
|
||||||
|
|
||||||
msgid "should be at least %{count} character(s)"
|
msgid "should be at least %{count} character(s)"
|
||||||
msgid_plural "should be at least %{count} character(s)"
|
msgid_plural "should be at least %{count} character(s)"
|
||||||
msgstr[0] "harus memiliki sekurang-kurangnya %{count} karakter"
|
msgstr[0] "harus ada sekurang-kurangnya %{count} karakter"
|
||||||
|
|
||||||
msgid "should have at least %{count} item(s)"
|
msgid "should have at least %{count} item(s)"
|
||||||
msgid_plural "should have at least %{count} item(s)"
|
msgid_plural "should have at least %{count} item(s)"
|
||||||
msgstr[0] "harus memiliki sekurang-kurangnya %{count} item"
|
msgstr[0] "harus ada sekurang-kurangnya %{count} item"
|
||||||
|
|
||||||
msgid "should be at most %{count} character(s)"
|
msgid "should be at most %{count} character(s)"
|
||||||
msgid_plural "should be at most %{count} character(s)"
|
msgid_plural "should be at most %{count} character(s)"
|
||||||
|
|
@ -112,7 +112,7 @@ msgstr "Sudah memilih"
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:359
|
#: lib/pleroma/web/oauth/oauth_controller.ex:359
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Bad request"
|
msgid "Bad request"
|
||||||
msgstr "Permintaan buruk (bad request)"
|
msgstr "Permintaan buruk"
|
||||||
|
|
||||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:426
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:426
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
@ -133,7 +133,7 @@ msgstr "Tidak dapat mencari pengguna"
|
||||||
#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:61
|
#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:61
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Can't get favorites"
|
msgid "Can't get favorites"
|
||||||
msgstr "Tidak dapat mendapatkan favorit"
|
msgstr "Tidak dapat mengambil favorit"
|
||||||
|
|
||||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:438
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:438
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
@ -143,7 +143,7 @@ msgstr "Tidak dapat menyukai objek"
|
||||||
#: lib/pleroma/web/common_api/utils.ex:563
|
#: lib/pleroma/web/common_api/utils.ex:563
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Cannot post an empty status without attachments"
|
msgid "Cannot post an empty status without attachments"
|
||||||
msgstr "Tidak dapat memposting status kosong tanpa lampiran"
|
msgstr "Tidak dapat mempos status kosong tanpa lampiran"
|
||||||
|
|
||||||
#: lib/pleroma/web/common_api/utils.ex:511
|
#: lib/pleroma/web/common_api/utils.ex:511
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
@ -206,7 +206,7 @@ msgstr "CAPTCHA tidak valid"
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:568
|
#: lib/pleroma/web/oauth/oauth_controller.ex:568
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Invalid credentials"
|
msgid "Invalid credentials"
|
||||||
msgstr "Kredensian tidak valid"
|
msgstr "Kredensial tidak valid"
|
||||||
|
|
||||||
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:38
|
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:38
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
@ -279,12 +279,12 @@ msgstr ""
|
||||||
#: lib/pleroma/web/ostatus/ostatus_controller.ex:149
|
#: lib/pleroma/web/ostatus/ostatus_controller.ex:149
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Something went wrong"
|
msgid "Something went wrong"
|
||||||
msgstr "Sesuatu yang salah terjadi"
|
msgstr "Ada sesuatu yang salah"
|
||||||
|
|
||||||
#: lib/pleroma/web/common_api/activity_draft.ex:107
|
#: lib/pleroma/web/common_api/activity_draft.ex:107
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "The message visibility must be direct"
|
msgid "The message visibility must be direct"
|
||||||
msgstr "Visibilitas pesan harus langsung"
|
msgstr "Ketampakan pesan harus langsung"
|
||||||
|
|
||||||
#: lib/pleroma/web/common_api/utils.ex:573
|
#: lib/pleroma/web/common_api/utils.ex:573
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
@ -294,7 +294,7 @@ msgstr "Status lebih dari batas karakter"
|
||||||
#: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:31
|
#: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:31
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "This resource requires authentication."
|
msgid "This resource requires authentication."
|
||||||
msgstr ""
|
msgstr "Autentikasi diperlukan untuk hal ini."
|
||||||
|
|
||||||
#: lib/pleroma/plugs/rate_limiter/rate_limiter.ex:206
|
#: lib/pleroma/plugs/rate_limiter/rate_limiter.ex:206
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
@ -314,7 +314,7 @@ msgstr ""
|
||||||
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:485
|
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:485
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "You can't revoke your own admin status."
|
msgid "You can't revoke your own admin status."
|
||||||
msgstr ""
|
msgstr "Anda tidak dapat mencabut status admin Anda."
|
||||||
|
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:221
|
#: lib/pleroma/web/oauth/oauth_controller.ex:221
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:308
|
#: lib/pleroma/web/oauth/oauth_controller.ex:308
|
||||||
|
|
@ -382,7 +382,7 @@ msgstr "Gagal"
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:410
|
#: lib/pleroma/web/oauth/oauth_controller.ex:410
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Failed to authenticate: %{message}."
|
msgid "Failed to authenticate: %{message}."
|
||||||
msgstr "Gagal mengotentikasi: %{message}."
|
msgstr "Gagal mengautentikasi: %{message}."
|
||||||
|
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:441
|
#: lib/pleroma/web/oauth/oauth_controller.ex:441
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
@ -392,7 +392,7 @@ msgstr "Gagal menyiapkan akun pengguna."
|
||||||
#: lib/pleroma/plugs/oauth_scopes_plug.ex:38
|
#: lib/pleroma/plugs/oauth_scopes_plug.ex:38
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Insufficient permissions: %{permissions}."
|
msgid "Insufficient permissions: %{permissions}."
|
||||||
msgstr ""
|
msgstr "Izin tidak cukup: %{permissions}."
|
||||||
|
|
||||||
#: lib/pleroma/plugs/uploaded_media.ex:104
|
#: lib/pleroma/plugs/uploaded_media.ex:104
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
@ -418,12 +418,12 @@ msgstr ""
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:172
|
#: lib/pleroma/web/oauth/oauth_controller.ex:172
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "This action is outside the authorized scopes"
|
msgid "This action is outside the authorized scopes"
|
||||||
msgstr ""
|
msgstr "Tindakan ini diluar jangkauan yang terotorisasi"
|
||||||
|
|
||||||
#: lib/pleroma/web/oauth/fallback_controller.ex:14
|
#: lib/pleroma/web/oauth/fallback_controller.ex:14
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Unknown error, please check the details and try again."
|
msgid "Unknown error, please check the details and try again."
|
||||||
msgstr "Kesalahan tidak dikenal, harap periksa keterangannya dan coba lagi."
|
msgstr "Kesalahan tidak dikenal, harap periksa detailnya dan coba lagi."
|
||||||
|
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:119
|
#: lib/pleroma/web/oauth/oauth_controller.ex:119
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:158
|
#: lib/pleroma/web/oauth/oauth_controller.ex:158
|
||||||
|
|
@ -444,7 +444,7 @@ msgstr ""
|
||||||
#: lib/pleroma/web/uploader_controller.ex:23
|
#: lib/pleroma/web/uploader_controller.ex:23
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "bad request"
|
msgid "bad request"
|
||||||
msgstr "permintaan buruk (bad request)"
|
msgstr "permintaan buruk"
|
||||||
|
|
||||||
#: lib/pleroma/web/twitter_api/twitter_api.ex:103
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:103
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
@ -469,7 +469,7 @@ msgstr "CAPTCHA Tidak Valid (Parameter kurang: %{name})"
|
||||||
#: lib/pleroma/web/mastodon_api/controllers/list_controller.ex:92
|
#: lib/pleroma/web/mastodon_api/controllers/list_controller.ex:92
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "List not found"
|
msgid "List not found"
|
||||||
msgstr ""
|
msgstr "Daftar tidak ditemukan"
|
||||||
|
|
||||||
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:123
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:123
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
@ -480,7 +480,7 @@ msgstr "Parameter kurang: %{name}"
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:321
|
#: lib/pleroma/web/oauth/oauth_controller.ex:321
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Password reset is required"
|
msgid "Password reset is required"
|
||||||
msgstr ""
|
msgstr "Diperlukan atur ulang kata sandi"
|
||||||
|
|
||||||
#: lib/pleroma/tests/auth_test_controller.ex:9
|
#: lib/pleroma/tests/auth_test_controller.ex:9
|
||||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:6 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:6
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:6 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:6
|
||||||
|
|
@ -522,7 +522,7 @@ msgstr ""
|
||||||
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:28
|
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:28
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Two-factor authentication enabled, you must use a access token."
|
msgid "Two-factor authentication enabled, you must use a access token."
|
||||||
msgstr "Otentikasi dua-faktor diaktifkan, Anda harus menggunakan token akses."
|
msgstr "Autentikasi dua langkah diaktifkan, Anda harus menggunakan token akses."
|
||||||
|
|
||||||
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:210
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:210
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
@ -552,7 +552,7 @@ msgstr ""
|
||||||
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
|
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Web push subscription is disabled on this Pleroma instance"
|
msgid "Web push subscription is disabled on this Pleroma instance"
|
||||||
msgstr ""
|
msgstr "Langganan push web dinonaktifkan untuk peladen Pleroma ini"
|
||||||
|
|
||||||
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:451
|
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:451
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
@ -562,7 +562,7 @@ msgstr "Anda tidak bisa mencabut status admin/moderator Anda sendiri."
|
||||||
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:126
|
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:126
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "authorization required for timeline view"
|
msgid "authorization required for timeline view"
|
||||||
msgstr ""
|
msgstr "Otorisasi diperlukan untuk tampilan linimasa"
|
||||||
|
|
||||||
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:24
|
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:24
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
@ -572,7 +572,7 @@ msgstr "Akses ditolak"
|
||||||
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:282
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:282
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "This API requires an authenticated user"
|
msgid "This API requires an authenticated user"
|
||||||
msgstr ""
|
msgstr "API ini memerlukan pengguna terautentikasi"
|
||||||
|
|
||||||
#: lib/pleroma/plugs/user_is_admin_plug.ex:21
|
#: lib/pleroma/plugs/user_is_admin_plug.ex:21
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
|
||||||
163
priv/gettext/id/LC_MESSAGES/posix_errors.po
Normal file
163
priv/gettext/id/LC_MESSAGES/posix_errors.po
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2025-08-11 18:40+0300\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: Automatically generated\n"
|
||||||
|
"Language-Team: none\n"
|
||||||
|
"Language: id\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.
|
||||||
|
msgid "eperm"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "eacces"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "eagain"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ebadf"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ebadmsg"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ebusy"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "edeadlk"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "edeadlock"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "edquot"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "eexist"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "efault"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "efbig"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "eftype"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "eintr"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "einval"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "eio"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "eisdir"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "eloop"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "emfile"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "emlink"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "emultihop"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enametoolong"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enfile"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enobufs"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enodev"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enolck"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enolink"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enoent"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enomem"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enospc"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enosr"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enostr"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enosys"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enotblk"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enotdir"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enotsup"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "enxio"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "eopnotsupp"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "eoverflow"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "epipe"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "erange"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "erofs"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "espipe"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "esrch"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "estale"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "etxtbsy"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "exdev"
|
||||||
|
msgstr ""
|
||||||
574
priv/gettext/id/LC_MESSAGES/static_pages.po
Normal file
574
priv/gettext/id/LC_MESSAGES/static_pages.po
Normal file
|
|
@ -0,0 +1,574 @@
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2025-08-11 18:40+0300\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: Automatically generated\n"
|
||||||
|
"Language-Team: none\n"
|
||||||
|
"Language: id\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/templates/twitter_api/remote_follow/follow.html.eex:9
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "remote follow authorization button"
|
||||||
|
msgid "Authorize"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex:2
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "remote follow error"
|
||||||
|
msgid "Error fetching user"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex:4
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "remote follow header"
|
||||||
|
msgid "Remote follow"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex:8
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "placeholder text for auth code entry"
|
||||||
|
msgid "Authentication code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex:10
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "placeholder text for password entry"
|
||||||
|
msgid "Password"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex:8
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "placeholder text for username entry"
|
||||||
|
msgid "Username"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex:13
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "remote follow authorization button for login"
|
||||||
|
msgid "Authorize"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex:12
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "remote follow authorization button for mfa"
|
||||||
|
msgid "Authorize"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex:2
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "remote follow error"
|
||||||
|
msgid "Error following account"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex:4
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "remote follow header, need login"
|
||||||
|
msgid "Log in to follow"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex:4
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "remote follow mfa header"
|
||||||
|
msgid "Two-factor authentication"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex:4
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "remote follow success"
|
||||||
|
msgid "Account followed!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex:7
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex:7
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "placeholder text for account id"
|
||||||
|
msgid "Your account ID, e.g. lain@quitter.se"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex:8
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "remote follow authorization button for following with a remote account"
|
||||||
|
msgid "Follow"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex:2
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "remote follow error"
|
||||||
|
msgid "Error: %{error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex:4
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "remote follow header"
|
||||||
|
msgid "Remotely follow %{nickname}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/password/reset.html.eex:12
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "password reset button"
|
||||||
|
msgid "Reset"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex:4
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "password reset failed homepage link"
|
||||||
|
msgid "Homepage"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex:1
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "password reset failed message"
|
||||||
|
msgid "Password reset failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/password/reset.html.eex:8
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "password reset form confirm password prompt"
|
||||||
|
msgid "Confirmation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/password/reset.html.eex:4
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "password reset form password prompt"
|
||||||
|
msgid "Password"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/password/invalid_token.html.eex:1
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "password reset invalid token message"
|
||||||
|
msgid "Invalid Token"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex:2
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "password reset successful homepage link"
|
||||||
|
msgid "Homepage"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex:1
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "password reset successful message"
|
||||||
|
msgid "Password changed!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/feed/feed/tag.atom.eex:12
|
||||||
|
#: lib/pleroma/web/templates/feed/feed/tag.rss.eex:8
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
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 ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/oob_token_exists.html.eex:1
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth authorization exists page title"
|
||||||
|
msgid "Authorization exists"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:32
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth authorize approve button"
|
||||||
|
msgid "Approve"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:30
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth authorize cancel button"
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:23
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth authorize message"
|
||||||
|
msgid "Application <strong>%{client_name}</strong> is requesting access to your account."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/oob_authorization_created.html.eex:1
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth authorized page title"
|
||||||
|
msgid "Successfully authorized"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex:1
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth external provider page title"
|
||||||
|
msgid "Sign in with external provider"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex:13
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth external provider sign in button"
|
||||||
|
msgid "Sign in with %{strategy}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:54
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth login button"
|
||||||
|
msgid "Log In"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:51
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth login password prompt"
|
||||||
|
msgid "Password"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:47
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth login username prompt"
|
||||||
|
msgid "Username"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:39
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth register nickname prompt"
|
||||||
|
msgid "Pleroma Handle"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:37
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth register nickname unchangeable warning"
|
||||||
|
msgid "Choose carefully! You won't be able to change this later. You will be able to change your display name, though."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:18
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth register page email prompt"
|
||||||
|
msgid "Email"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:10
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth register page fill form prompt"
|
||||||
|
msgid "If you'd like to register a new account, please provide the details below."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:35
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth register page login button"
|
||||||
|
msgid "Proceed as existing user"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:31
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth register page login password prompt"
|
||||||
|
msgid "Password"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:24
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth register page login prompt"
|
||||||
|
msgid "Alternatively, sign in to connect to existing account."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:27
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth register page login username prompt"
|
||||||
|
msgid "Name or email"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:14
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth register page nickname prompt"
|
||||||
|
msgid "Nickname"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:22
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth register page register button"
|
||||||
|
msgid "Proceed as new user"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:8
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth register page title"
|
||||||
|
msgid "Registration Details"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:36
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth register page title"
|
||||||
|
msgid "This is the first time you visit! Please enter your Pleroma handle."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex:2
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth scopes message"
|
||||||
|
msgid "The following permissions will be granted"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/oob_authorization_created.html.eex:2
|
||||||
|
#: lib/pleroma/web/templates/o_auth/o_auth/oob_token_exists.html.eex:2
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "oauth token code message"
|
||||||
|
msgid "Token code is <br>%{token}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/mfa/totp.html.eex:12
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "mfa auth code prompt"
|
||||||
|
msgid "Authentication code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/mfa/totp.html.eex:8
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "mfa auth page title"
|
||||||
|
msgid "Two-factor authentication"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/mfa/totp.html.eex:23
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "mfa auth page use recovery code link"
|
||||||
|
msgid "Enter a two-factor recovery code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/mfa/totp.html.eex:20
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "mfa auth verify code button"
|
||||||
|
msgid "Verify"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex:8
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "mfa recover page title"
|
||||||
|
msgid "Two-factor recovery"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex:12
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "mfa recover recovery code prompt"
|
||||||
|
msgid "Recovery code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex:23
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "mfa recover use 2fa code link"
|
||||||
|
msgid "Enter a two-factor code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex:20
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "mfa recover verify recovery code button"
|
||||||
|
msgid "Verify"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex:8
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "static fe profile page remote follow button"
|
||||||
|
msgid "Remote follow"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/email/digest.html.eex:163
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "digest email header line"
|
||||||
|
msgid "Hey %{nickname}, here is what you've missed!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/email/digest.html.eex:544
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "digest email receiver address"
|
||||||
|
msgid "The email address you are subscribed as is <a href='mailto:%{@user.email}' style='color: %{color};text-decoration: none;'>%{email}</a>. "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/email/digest.html.eex:538
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "digest email sending reason"
|
||||||
|
msgid "You have received this email because you have signed up to receive digest emails from <b>%{instance}</b> Pleroma instance."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/email/digest.html.eex:547
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "digest email unsubscribe action"
|
||||||
|
msgid "To unsubscribe, please go %{here}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/email/digest.html.eex:547
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "digest email unsubscribe action link text"
|
||||||
|
msgid "here"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/mailer/subscription/unsubscribe_failure.html.eex:1
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "mailer unsubscribe failed message"
|
||||||
|
msgid "UNSUBSCRIBE FAILURE"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/mailer/subscription/unsubscribe_success.html.eex:1
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "mailer unsubscribe successful message"
|
||||||
|
msgid "UNSUBSCRIBE SUCCESSFUL"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/email/digest.html.eex:385
|
||||||
|
#, elixir-format
|
||||||
|
msgctxt "new followers count header"
|
||||||
|
msgid "%{count} New Follower"
|
||||||
|
msgid_plural "%{count} New Followers"
|
||||||
|
msgstr[0] ""
|
||||||
|
msgstr[1] ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:356
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "account archive email body - self-requested"
|
||||||
|
msgid "<p>You requested a full backup of your Pleroma account. It's ready for download:</p>\n<p><a href=\"%{download_url}\">%{download_url}</a></p>\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:384
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "account archive email subject"
|
||||||
|
msgid "Your account archive is ready"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:188
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "approval pending email body"
|
||||||
|
msgid "<h3>Awaiting Approval</h3>\n<p>Your account at %{instance_name} is being reviewed by staff. You will receive another email once your account is approved.</p>\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:202
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "approval pending email subject"
|
||||||
|
msgid "Your account is awaiting approval"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:158
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "confirmation email body"
|
||||||
|
msgid "<h3>Thank you for registering on %{instance_name}</h3>\n<p>Email confirmation is required to activate the account.</p>\n<p>Please click the following link to <a href=\"%{confirmation_url}\">activate your account</a>.</p>\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:174
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "confirmation email subject"
|
||||||
|
msgid "%{instance_name} account confirmation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:310
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "digest email subject"
|
||||||
|
msgid "Your digest from %{instance_name}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:81
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "password reset email body"
|
||||||
|
msgid "<h3>Reset your password at %{instance_name}</h3>\n<p>Someone has requested password change for your account at %{instance_name}.</p>\n<p>If it was you, visit the following link to proceed: <a href=\"%{password_reset_url}\">reset password</a>.</p>\n<p>If it was someone else, nothing to worry about: your data is secure and your password has not been changed.</p>\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:98
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "password reset email subject"
|
||||||
|
msgid "Password reset"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:215
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "successful registration email body"
|
||||||
|
msgid "<h3>Hello @%{nickname},</h3>\n<p>Your account at %{instance_name} has been registered successfully.</p>\n<p>No further action is required to activate your account.</p>\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:231
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "successful registration email subject"
|
||||||
|
msgid "Account registered on %{instance_name}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:119
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "user invitation email body"
|
||||||
|
msgid "<h3>You are invited to %{instance_name}</h3>\n<p>%{inviter_name} invites you to join %{instance_name}, an instance of Pleroma federated social networking platform.</p>\n<p>Click the following link to register: <a href=\"%{registration_url}\">accept invitation</a>.</p>\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:136
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "user invitation email subject"
|
||||||
|
msgid "Invitation to %{instance_name}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:53
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "welcome email html body"
|
||||||
|
msgid "Welcome to %{instance_name}!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:41
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "welcome email subject"
|
||||||
|
msgid "Welcome to %{instance_name}!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:65
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "welcome email text body"
|
||||||
|
msgid "Welcome to %{instance_name}!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/emails/user_email.ex:368
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "account archive email body - admin requested"
|
||||||
|
msgid "<p>Admin @%{admin_nickname} requested a full backup of your Pleroma account. It's ready for download:</p>\n<p><a href=\"%{download_url}\">%{download_url}</a></p>\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/controllers/util_controller.ex:123
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "remote follow error message - unknown error"
|
||||||
|
msgid "Something went wrong."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/controllers/util_controller.ex:67
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "remote follow error message - user not found"
|
||||||
|
msgid "Could not find user"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex:8
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "status interact authorization button"
|
||||||
|
msgid "Interact"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex:2
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "status interact error"
|
||||||
|
msgid "Error: %{error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/controllers/util_controller.ex:95
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "status interact error message - status not found"
|
||||||
|
msgid "Could not find status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/controllers/util_controller.ex:144
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "status interact error message - unknown error"
|
||||||
|
msgid "Something went wrong."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex:4
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "status interact header"
|
||||||
|
msgid "Interacting with %{nickname}'s %{status_link}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex:4
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgctxt "status interact header - status link text"
|
||||||
|
msgid "status"
|
||||||
|
msgstr ""
|
||||||
16
test/pleroma/dependency_version_test.exs
Normal file
16
test/pleroma/dependency_version_test.exs
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.DependencyVersionTest do
|
||||||
|
use ExUnit.Case, async: true
|
||||||
|
|
||||||
|
test "uses majic 1.2" do
|
||||||
|
majic_version =
|
||||||
|
:majic
|
||||||
|
|> Application.spec(:vsn)
|
||||||
|
|> to_string()
|
||||||
|
|
||||||
|
assert Version.match?(majic_version, "~> 1.2")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -11,6 +11,7 @@ defmodule Pleroma.SignatureTest do
|
||||||
import Mock
|
import Mock
|
||||||
|
|
||||||
alias Pleroma.Signature
|
alias Pleroma.Signature
|
||||||
|
alias Pleroma.StubbedHTTPSignaturesMock, as: HTTPSignaturesMock
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||||
|
|
@ -103,6 +104,18 @@ defmodule Pleroma.SignatureTest do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "validate_signature/1" do
|
||||||
|
test "treats HTTP signature errors as failed validation" do
|
||||||
|
conn = %Plug.Conn{method: "GET", request_path: "/inbox", req_headers: []}
|
||||||
|
|
||||||
|
Mox.expect(HTTPSignaturesMock, :validate_conn, fn _conn ->
|
||||||
|
{:error, :request_target_header}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert Signature.validate_signature(conn) == false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "key_id_to_actor_id/1" do
|
describe "key_id_to_actor_id/1" do
|
||||||
test "it properly deduces the actor id for misskey" do
|
test "it properly deduces the actor id for misskey" do
|
||||||
assert Signature.key_id_to_actor_id("https://example.com/users/1234/publickey") ==
|
assert Signature.key_id_to_actor_id("https://example.com/users/1234/publickey") ==
|
||||||
|
|
|
||||||
195
test/pleroma/user/search_test.exs
Normal file
195
test/pleroma/user/search_test.exs
Normal file
|
|
@ -0,0 +1,195 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.User.SearchTest do
|
||||||
|
use Pleroma.DataCase, async: false
|
||||||
|
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
alias Pleroma.Instances
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
|
describe "search/2 mention suggestions" do
|
||||||
|
test "prioritizes followed/follower users before others" do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
related =
|
||||||
|
insert(:user,
|
||||||
|
local: false,
|
||||||
|
nickname: "hj@real.example",
|
||||||
|
ap_id: "https://real.example/users/hj",
|
||||||
|
last_status_at: ~N[2020-01-01 00:00:00]
|
||||||
|
)
|
||||||
|
|
||||||
|
other = insert(:user, nickname: "hj", last_status_at: ~N[2020-01-02 00:00:00])
|
||||||
|
|
||||||
|
{:ok, _related, _user} = User.follow(related, user)
|
||||||
|
|
||||||
|
results = User.search("hj", for_user: user) |> Enum.map(& &1.id)
|
||||||
|
|
||||||
|
assert results == [related.id, other.id]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "orders followed/follower users by most recent activity" do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
older =
|
||||||
|
insert(:user,
|
||||||
|
local: false,
|
||||||
|
nickname: "ali@remote.example",
|
||||||
|
ap_id: "https://remote.example/users/ali",
|
||||||
|
last_status_at: ~N[2020-01-01 00:00:00]
|
||||||
|
)
|
||||||
|
|
||||||
|
newer =
|
||||||
|
insert(:user,
|
||||||
|
local: false,
|
||||||
|
nickname: "alia@remote.example",
|
||||||
|
ap_id: "https://remote.example/users/alia",
|
||||||
|
last_status_at: ~N[2020-01-02 00:00:00]
|
||||||
|
)
|
||||||
|
|
||||||
|
{:ok, _user, _older} = User.follow(user, older)
|
||||||
|
{:ok, _user, _newer} = User.follow(user, newer)
|
||||||
|
|
||||||
|
assert [newer.id, older.id] ==
|
||||||
|
User.search("ali", for_user: user)
|
||||||
|
|> Enum.map(& &1.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "groups followed/follower users first and sorts them by recency" do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
following_newest =
|
||||||
|
insert(:user,
|
||||||
|
local: false,
|
||||||
|
nickname: "mentiontesta@related.example",
|
||||||
|
ap_id: "https://related.example/users/mentiontesta",
|
||||||
|
last_status_at: ~N[2020-01-03 00:00:00]
|
||||||
|
)
|
||||||
|
|
||||||
|
follower_middle =
|
||||||
|
insert(:user,
|
||||||
|
local: false,
|
||||||
|
nickname: "mentiontestb@related.example",
|
||||||
|
ap_id: "https://related.example/users/mentiontestb",
|
||||||
|
last_status_at: ~N[2020-01-02 00:00:00]
|
||||||
|
)
|
||||||
|
|
||||||
|
mutual_oldest =
|
||||||
|
insert(:user,
|
||||||
|
local: false,
|
||||||
|
nickname: "mentiontestc@related.example",
|
||||||
|
ap_id: "https://related.example/users/mentiontestc",
|
||||||
|
last_status_at: ~N[2020-01-01 00:00:00]
|
||||||
|
)
|
||||||
|
|
||||||
|
unrelated_newer =
|
||||||
|
insert(:user,
|
||||||
|
local: false,
|
||||||
|
nickname: "mentiontestd@unrelated.example",
|
||||||
|
ap_id: "https://unrelated.example/users/mentiontestd",
|
||||||
|
last_status_at: ~N[2020-01-04 00:00:00]
|
||||||
|
)
|
||||||
|
|
||||||
|
{:ok, _user, _following_newest} = User.follow(user, following_newest)
|
||||||
|
{:ok, _follower_middle, _user} = User.follow(follower_middle, user)
|
||||||
|
|
||||||
|
{:ok, _user, _mutual_oldest} = User.follow(user, mutual_oldest)
|
||||||
|
{:ok, _mutual_oldest, _user} = User.follow(mutual_oldest, user)
|
||||||
|
|
||||||
|
results = User.search("mentiontest", for_user: user)
|
||||||
|
|
||||||
|
assert Enum.map(results, & &1.id) ==
|
||||||
|
[following_newest.id, follower_middle.id, mutual_oldest.id, unrelated_newer.id]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "uses last_active_at when last_status_at is missing" do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
older =
|
||||||
|
insert(:user,
|
||||||
|
local: false,
|
||||||
|
nickname: "activefallbacka@remote.example",
|
||||||
|
ap_id: "https://remote.example/users/activefallbacka",
|
||||||
|
last_status_at: nil,
|
||||||
|
last_active_at: ~N[2020-01-01 00:00:00]
|
||||||
|
)
|
||||||
|
|
||||||
|
newer =
|
||||||
|
insert(:user,
|
||||||
|
local: false,
|
||||||
|
nickname: "activefallbackb@remote.example",
|
||||||
|
ap_id: "https://remote.example/users/activefallbackb",
|
||||||
|
last_status_at: nil,
|
||||||
|
last_active_at: ~N[2020-01-02 00:00:00]
|
||||||
|
)
|
||||||
|
|
||||||
|
{:ok, _user, _older} = User.follow(user, older)
|
||||||
|
{:ok, _user, _newer} = User.follow(user, newer)
|
||||||
|
|
||||||
|
assert [newer.id, older.id] ==
|
||||||
|
User.search("activefallback", for_user: user)
|
||||||
|
|> Enum.map(& &1.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "does not return deactivated users even if related" do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
active =
|
||||||
|
insert(:user,
|
||||||
|
local: false,
|
||||||
|
nickname: "deactivatedtesta@remote.example",
|
||||||
|
ap_id: "https://remote.example/users/deactivatedtesta",
|
||||||
|
last_status_at: ~N[2020-01-02 00:00:00]
|
||||||
|
)
|
||||||
|
|
||||||
|
deactivated =
|
||||||
|
insert(:user,
|
||||||
|
local: false,
|
||||||
|
nickname: "deactivatedtestb@remote.example",
|
||||||
|
ap_id: "https://remote.example/users/deactivatedtestb",
|
||||||
|
last_status_at: ~N[2020-01-03 00:00:00]
|
||||||
|
)
|
||||||
|
|
||||||
|
{:ok, _user, _active} = User.follow(user, active)
|
||||||
|
{:ok, _user, _deactivated} = User.follow(user, deactivated)
|
||||||
|
Repo.update!(Ecto.Changeset.change(deactivated, is_active: false))
|
||||||
|
|
||||||
|
results = User.search("deactivatedtest", for_user: user) |> Enum.map(& &1.id)
|
||||||
|
|
||||||
|
assert results == [active.id]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "does not return users from unreachable instances" do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, _instance} = Instances.set_unreachable("dead.example")
|
||||||
|
|
||||||
|
dead =
|
||||||
|
insert(:user,
|
||||||
|
local: false,
|
||||||
|
nickname: "ali@dead.example",
|
||||||
|
ap_id: "https://dead.example/users/ali",
|
||||||
|
last_status_at: ~N[2020-01-02 00:00:00]
|
||||||
|
)
|
||||||
|
|
||||||
|
alive =
|
||||||
|
insert(:user,
|
||||||
|
local: false,
|
||||||
|
nickname: "ali@alive.example",
|
||||||
|
ap_id: "https://alive.example/users/ali",
|
||||||
|
last_status_at: ~N[2020-01-02 00:00:00]
|
||||||
|
)
|
||||||
|
|
||||||
|
{:ok, _user, _alive} = User.follow(user, alive)
|
||||||
|
{:ok, _user, _dead} = User.follow(user, dead)
|
||||||
|
|
||||||
|
results = User.search("ali", for_user: user) |> Enum.map(& &1.id)
|
||||||
|
|
||||||
|
assert results == [alive.id]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -950,6 +950,50 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|
||||||
refute Activity.get_by_ap_id(data["id"])
|
refute Activity.get_by_ap_id(data["id"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "does not process post with Host header not for us", %{conn: conn} do
|
||||||
|
alice = insert(:user, local: false, ap_id: "https://one.com/users/alice")
|
||||||
|
object_id = "https://one.com/objects/inbox-forged-note"
|
||||||
|
|
||||||
|
data = %{
|
||||||
|
"type" => "Create",
|
||||||
|
"actor" => alice.ap_id,
|
||||||
|
"id" => "https://one.com/activities/inbox-forged-create",
|
||||||
|
"context" => "https://one.com/contexts/inbox-forged-create",
|
||||||
|
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
|
"cc" => [],
|
||||||
|
"object" => %{
|
||||||
|
"type" => "Note",
|
||||||
|
"id" => object_id,
|
||||||
|
"actor" => alice.ap_id,
|
||||||
|
"attributedTo" => alice.ap_id,
|
||||||
|
"context" => "https://one.com/contexts/inbox-forged-create",
|
||||||
|
"content" => "forged post",
|
||||||
|
"published" => "2024-07-25T13:33:31Z",
|
||||||
|
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
|
"cc" => []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Plug will complain when replacing raw host header with put_req_header.
|
||||||
|
# The Plug way is updating conn.host, but that isn't the raw header
|
||||||
|
# and that isn't used in the EnsureHostMatchesPlug, because it doesn't include the port.
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> assign_valid_signature_for_actor(alice)
|
||||||
|
|> delete_req_header("host")
|
||||||
|
|> put_req_header("content-type", "application/activity+json")
|
||||||
|
|
||||||
|
conn = %{conn | req_headers: conn.req_headers ++ [{"host", "invalid.example.com"}]}
|
||||||
|
conn = post(conn, "/inbox", data)
|
||||||
|
|
||||||
|
assert "Host header does not match this instance" == conn.resp_body
|
||||||
|
assert 400 == conn.status
|
||||||
|
assert true == conn.halted
|
||||||
|
|
||||||
|
refute Activity.get_by_ap_id(data["id"])
|
||||||
|
refute Object.get_by_ap_id(object_id)
|
||||||
|
end
|
||||||
|
|
||||||
test "accept follow activity", %{conn: conn} do
|
test "accept follow activity", %{conn: conn} do
|
||||||
clear_config([:instance, :federating], true)
|
clear_config([:instance, :federating], true)
|
||||||
relay = Relay.get_actor()
|
relay = Relay.get_actor()
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,43 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
|
||||||
assert activity.data["cc"] == [user.ap_id]
|
assert activity.data["cc"] == [user.ap_id]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it rejects Flag activities when both reporter and reported account are remote" do
|
||||||
|
reporter = insert(:user, local: false, domain: "mastodon.cat")
|
||||||
|
reported = insert(:user, local: false, domain: "nicecrew.digital")
|
||||||
|
|
||||||
|
message = %{
|
||||||
|
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
"actor" => reporter.ap_id,
|
||||||
|
"content" => "blocked AND reported!!!",
|
||||||
|
"object" => [reported.ap_id, "https://nicecrew.digital/objects/report-status"],
|
||||||
|
"type" => "Flag"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {:reject, reason} = Transmogrifier.handle_incoming(message)
|
||||||
|
assert reason =~ "third-party report"
|
||||||
|
refute "Flag" |> Pleroma.Activity.Queries.by_type() |> Pleroma.Repo.one()
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it accepts Flag activities with just actor id as object" do
|
||||||
|
user = insert(:user)
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
message = %{
|
||||||
|
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
"cc" => [user.ap_id],
|
||||||
|
"object" => user.ap_id,
|
||||||
|
"type" => "Flag",
|
||||||
|
"content" => "blocked AND reported!!!",
|
||||||
|
"actor" => other_user.ap_id
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {:ok, activity} = Transmogrifier.handle_incoming(message)
|
||||||
|
|
||||||
|
assert activity.data["content"] == "blocked AND reported!!!"
|
||||||
|
assert activity.data["actor"] == other_user.ap_id
|
||||||
|
assert activity.data["cc"] == [user.ap_id]
|
||||||
|
end
|
||||||
|
|
||||||
test "it accepts Move activities" do
|
test "it accepts Move activities" do
|
||||||
old_user = insert(:user)
|
old_user = insert(:user)
|
||||||
new_user = insert(:user)
|
new_user = insert(:user)
|
||||||
|
|
|
||||||
121
test/pleroma/web/plugs/ensure_host_matches_plug_test.exs
Normal file
121
test/pleroma/web/plugs/ensure_host_matches_plug_test.exs
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2026 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.Plugs.EnsureHostMatchesPlugTest do
|
||||||
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
|
alias Pleroma.Web.Endpoint
|
||||||
|
alias Pleroma.Web.Plugs.EnsureHostMatchesPlug
|
||||||
|
|
||||||
|
import Plug.Conn
|
||||||
|
import Tesla.Mock
|
||||||
|
|
||||||
|
setup do
|
||||||
|
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
|
defp set_host(conn, host), do: %{conn | req_headers: conn.req_headers ++ [{"host", host}]}
|
||||||
|
|
||||||
|
describe "EnsureHostMatchesPlug" do
|
||||||
|
setup do
|
||||||
|
conn = build_conn(:post, "/cofe") |> assign(:valid_signature, true)
|
||||||
|
[conn: conn]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "gracefully handles no Host header", %{conn: conn} do
|
||||||
|
conn = EnsureHostMatchesPlug.call(conn, %{})
|
||||||
|
|
||||||
|
assert conn.status == 400
|
||||||
|
assert conn.halted == true
|
||||||
|
assert conn.resp_body == "Host header not provided"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "gracefully handles empty Host header", %{conn: conn} do
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> set_host("")
|
||||||
|
|> EnsureHostMatchesPlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.status == 400
|
||||||
|
assert conn.halted == true
|
||||||
|
assert conn.resp_body == "Host header not provided"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it rejects Host header not matching Endpoint URL", %{conn: conn} do
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> set_host("invalid.example.com")
|
||||||
|
|> EnsureHostMatchesPlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.status == 400
|
||||||
|
assert conn.halted == true
|
||||||
|
assert conn.resp_body == "Host header does not match this instance"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it rejects Host header not matching Endpoint with port", %{conn: conn} do
|
||||||
|
endpoint = URI.parse(Endpoint.url())
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> set_host("invalid.example.com:#{endpoint.port}")
|
||||||
|
|> EnsureHostMatchesPlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.status == 400
|
||||||
|
assert conn.halted == true
|
||||||
|
assert conn.resp_body == "Host header does not match this instance"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it rejects Host header not matching Endpoint port", %{conn: conn} do
|
||||||
|
endpoint = URI.parse(Endpoint.url())
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> set_host("#{endpoint.host}:25")
|
||||||
|
|> EnsureHostMatchesPlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.status == 400
|
||||||
|
assert conn.halted == true
|
||||||
|
assert conn.resp_body == "Host header does not match this instance"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it rejects multiple Host headers", %{conn: conn} do
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> set_host("host1.example.com")
|
||||||
|
|> set_host("host2.example.com")
|
||||||
|
|> EnsureHostMatchesPlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.status == 400
|
||||||
|
assert conn.halted == true
|
||||||
|
assert conn.resp_body == "More than one Host header provided"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it works for Host header without port", %{conn: conn} do
|
||||||
|
endpoint = URI.parse(Endpoint.url())
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> set_host("#{endpoint.host}")
|
||||||
|
|> EnsureHostMatchesPlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.halted == false
|
||||||
|
assert Map.get(conn.assigns, :valid_host_header, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it works for Host header with port same as Endpoint", %{
|
||||||
|
conn: conn
|
||||||
|
} do
|
||||||
|
endpoint = URI.parse(Endpoint.url())
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> set_host("#{endpoint.host}:#{endpoint.port}")
|
||||||
|
|> EnsureHostMatchesPlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.halted == false
|
||||||
|
assert Map.get(conn.assigns, :valid_host_header, nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -106,4 +106,38 @@ defmodule Pleroma.Web.Plugs.RemoteIpTest do
|
||||||
|
|
||||||
assert conn.remote_ip == {1, 1, 1, 1}
|
assert conn.remote_ip == {1, 1, 1, 1}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "reserved ranges are configurable" do
|
||||||
|
clear_config([RemoteIp, :reserved], [])
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn(:get, "/")
|
||||||
|
|> put_req_header("x-forwarded-for", "1.1.1.1, 10.0.0.3")
|
||||||
|
|> RemoteIp.call(nil)
|
||||||
|
|
||||||
|
assert conn.remote_ip == {10, 0, 0, 3}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "clients override reserved ranges" do
|
||||||
|
clear_config([RemoteIp, :clients], ["10.0.0.0/8"])
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn(:get, "/")
|
||||||
|
|> put_req_header("x-forwarded-for", "1.1.1.1, 10.0.0.3")
|
||||||
|
|> RemoteIp.call(nil)
|
||||||
|
|
||||||
|
assert conn.remote_ip == {10, 0, 0, 3}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "clients override proxies" do
|
||||||
|
clear_config([RemoteIp, :clients], ["10.0.0.3"])
|
||||||
|
clear_config([RemoteIp, :proxies], ["10.0.0.0/8"])
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn(:get, "/")
|
||||||
|
|> put_req_header("x-forwarded-for", "1.1.1.1, 10.0.0.3")
|
||||||
|
|> RemoteIp.call(nil)
|
||||||
|
|
||||||
|
assert conn.remote_ip == {10, 0, 0, 3}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,13 @@ defmodule Pleroma.Workers.SignatureRetryWorkerTest do
|
||||||
alias Pleroma.Signature
|
alias Pleroma.Signature
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.UserView
|
alias Pleroma.Web.ActivityPub.UserView
|
||||||
|
alias Pleroma.Web.Endpoint
|
||||||
alias Pleroma.Web.Federator
|
alias Pleroma.Web.Federator
|
||||||
alias Pleroma.Workers.SignatureRetryWorker
|
alias Pleroma.Workers.SignatureRetryWorker
|
||||||
|
|
||||||
defp signature_headers_for(%User{} = signer) do
|
defp signature_headers_for(%User{} = signer) do
|
||||||
[
|
[
|
||||||
{"host", "local.test"},
|
{"host", "#{URI.parse(Endpoint.url()).host}"},
|
||||||
{"date", "Thu, 25 Jul 2024 13:33:31 GMT"},
|
{"date", "Thu, 25 Jul 2024 13:33:31 GMT"},
|
||||||
{"digest", "SHA-256=fake-digest"},
|
{"digest", "SHA-256=fake-digest"},
|
||||||
{"content-type", "application/activity+json"},
|
{"content-type", "application/activity+json"},
|
||||||
|
|
@ -245,6 +246,66 @@ defmodule Pleroma.Workers.SignatureRetryWorkerTest do
|
||||||
refute Activity.get_by_ap_id(create["id"])
|
refute Activity.get_by_ap_id(create["id"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "cancels when the Host header does not match Endpoint" do
|
||||||
|
alice = insert(:user, local: false, ap_id: "https://one.com/users/alice")
|
||||||
|
|
||||||
|
create = %{
|
||||||
|
"type" => "Create",
|
||||||
|
"actor" => alice.ap_id,
|
||||||
|
"id" => "https://one.com/activities/invalid-signature-create",
|
||||||
|
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
|
"cc" => [],
|
||||||
|
"object" => %{
|
||||||
|
"type" => "Note",
|
||||||
|
"id" => "https://one.com/objects/invalid-signature-note",
|
||||||
|
"actor" => alice.ap_id,
|
||||||
|
"attributedTo" => alice.ap_id,
|
||||||
|
"content" => "forged post",
|
||||||
|
"published" => "2024-07-25T13:33:31Z",
|
||||||
|
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
|
"cc" => []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_signature_from(alice)
|
||||||
|
|
||||||
|
headers =
|
||||||
|
[
|
||||||
|
{"host", "invalid.example.com"},
|
||||||
|
{"date", "Thu, 25 Jul 2024 13:33:31 GMT"},
|
||||||
|
{"digest", "SHA-256=fake-digest"},
|
||||||
|
{"content-type", "application/activity+json"},
|
||||||
|
{
|
||||||
|
"signature",
|
||||||
|
"keyId=\"#{alice.ap_id}#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"fake-signature\""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
assert {:ok, oban_job} =
|
||||||
|
Federator.incoming_failed_signature_ap_doc(%{
|
||||||
|
method: "POST",
|
||||||
|
req_headers: headers,
|
||||||
|
request_path: "/inbox",
|
||||||
|
params: create,
|
||||||
|
query_string: ""
|
||||||
|
})
|
||||||
|
|
||||||
|
log =
|
||||||
|
capture_log([level: :warning], fn ->
|
||||||
|
assert {:cancel, :host_header_mismatch} = SignatureRetryWorker.perform(oban_job)
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert log =~ "Failed-signature inbox retry rejected"
|
||||||
|
assert log =~ "reason=:host_header_mismatch"
|
||||||
|
assert log =~ "payload_actor=\"https://one.com/users/alice\""
|
||||||
|
assert log =~ "signature_actor=\"https://one.com/users/alice\""
|
||||||
|
assert log =~ "activity_id=\"https://one.com/activities/invalid-signature-create\""
|
||||||
|
assert log =~ "type=\"Create\""
|
||||||
|
assert log =~ "request_path=\"/inbox\""
|
||||||
|
|
||||||
|
refute Activity.get_by_ap_id(create["id"])
|
||||||
|
end
|
||||||
|
|
||||||
test "processes the activity after refetching a valid matching signature" do
|
test "processes the activity after refetching a valid matching signature" do
|
||||||
alice = insert(:user, local: false, ap_id: "https://one.com/users/alice")
|
alice = insert(:user, local: false, ap_id: "https://one.com/users/alice")
|
||||||
|
|
||||||
|
|
@ -309,11 +370,11 @@ defmodule Pleroma.Workers.SignatureRetryWorkerTest do
|
||||||
"content-type" => "application/activity+json",
|
"content-type" => "application/activity+json",
|
||||||
date: date,
|
date: date,
|
||||||
digest: digest,
|
digest: digest,
|
||||||
host: "local.test"
|
host: "#{URI.parse(Endpoint.url()).host}"
|
||||||
})
|
})
|
||||||
|
|
||||||
req_headers = [
|
req_headers = [
|
||||||
["host", "local.test"],
|
["host", "#{URI.parse(Endpoint.url()).host}"],
|
||||||
["date", date],
|
["date", date],
|
||||||
["digest", digest],
|
["digest", digest],
|
||||||
["content-type", "application/activity+json"],
|
["content-type", "application/activity+json"],
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,10 @@ defmodule Pleroma.Web.ConnCase do
|
||||||
DataCase.stub_pipeline()
|
DataCase.stub_pipeline()
|
||||||
|
|
||||||
Mox.verify_on_exit!()
|
Mox.verify_on_exit!()
|
||||||
|
endpoint = URI.parse(Pleroma.Web.Endpoint.url())
|
||||||
|
conn = Phoenix.ConnTest.build_conn()
|
||||||
|
conn = %{conn | req_headers: [{"host", "#{endpoint.host}:#{endpoint.port}"}]}
|
||||||
|
|
||||||
{:ok, conn: Phoenix.ConnTest.build_conn()}
|
{:ok, conn: conn}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue