Merge remote-tracking branch 'remotes/origin/develop' into feature/object-hashtags-rework
This commit is contained in:
commit
92526e0230
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- The `application` metadata returned with statuses is no longer hardcoded. Apps that want to display these details will now have valid data for new posts after this change.
|
||||||
|
|
||||||
|
## Unreleased (Patch)
|
||||||
|
|
||||||
|
## [2.3.0] - 2020-03-01
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- Fixed client user agent leaking through MediaProxy
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- `:auth, :enforce_oauth_admin_scope_usage` configuration option.
|
- `:auth, :enforce_oauth_admin_scope_usage` configuration option.
|
||||||
|
@ -60,7 +70,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Ability to define custom HTTP headers per each frontend
|
- Ability to define custom HTTP headers per each frontend
|
||||||
- MRF (`NoEmptyPolicy`): New MRF Policy which will deny empty statuses or statuses of only mentions from being created by local users
|
- MRF (`NoEmptyPolicy`): New MRF Policy which will deny empty statuses or statuses of only mentions from being created by local users
|
||||||
- New users will receive a simple email confirming their registration if no other emails will be dispatched. (e.g., Welcome, Confirmation, or Approval Required)
|
- New users will receive a simple email confirming their registration if no other emails will be dispatched. (e.g., Welcome, Confirmation, or Approval Required)
|
||||||
- The `application` metadata returned with statuses is no longer hardcoded. Apps that want to display these details will now have valid data for new posts after this change.
|
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>API Changes</summary>
|
<summary>API Changes</summary>
|
||||||
|
@ -100,9 +109,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Mastodon API: Support for expires_in/expires_at in the Filters.
|
- Mastodon API: Support for expires_in/expires_at in the Filters.
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## Unreleased (Patch)
|
|
||||||
|
|
||||||
|
|
||||||
## [2.2.2] - 2020-01-18
|
## [2.2.2] - 2020-01-18
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.ReverseProxy do
|
defmodule Pleroma.ReverseProxy do
|
||||||
@range_headers ~w(range if-range)
|
@range_headers ~w(range if-range)
|
||||||
@keep_req_headers ~w(accept user-agent accept-encoding cache-control if-modified-since) ++
|
@keep_req_headers ~w(accept accept-encoding cache-control if-modified-since) ++
|
||||||
~w(if-unmodified-since if-none-match) ++ @range_headers
|
~w(if-unmodified-since if-none-match) ++ @range_headers
|
||||||
@resp_cache_headers ~w(etag date last-modified)
|
@resp_cache_headers ~w(etag date last-modified)
|
||||||
@keep_resp_headers @resp_cache_headers ++
|
@keep_resp_headers @resp_cache_headers ++
|
||||||
|
@ -57,9 +57,6 @@ def default_cache_control_header, do: @default_cache_control_header
|
||||||
* `false` will add `content-disposition: attachment` to any request,
|
* `false` will add `content-disposition: attachment` to any request,
|
||||||
* a list of whitelisted content types
|
* a list of whitelisted content types
|
||||||
|
|
||||||
* `keep_user_agent` will forward the client's user-agent to the upstream. This may be useful if the upstream is
|
|
||||||
doing content transformation (encoding, …) depending on the request.
|
|
||||||
|
|
||||||
* `req_headers`, `resp_headers` additional headers.
|
* `req_headers`, `resp_headers` additional headers.
|
||||||
|
|
||||||
* `http`: options for [hackney](https://github.com/benoitc/hackney) or [gun](https://github.com/ninenines/gun).
|
* `http`: options for [hackney](https://github.com/benoitc/hackney) or [gun](https://github.com/ninenines/gun).
|
||||||
|
@ -84,8 +81,7 @@ def default_cache_control_header, do: @default_cache_control_header
|
||||||
import Plug.Conn
|
import Plug.Conn
|
||||||
|
|
||||||
@type option() ::
|
@type option() ::
|
||||||
{:keep_user_agent, boolean}
|
{:max_read_duration, :timer.time() | :infinity}
|
||||||
| {:max_read_duration, :timer.time() | :infinity}
|
|
||||||
| {:max_body_length, non_neg_integer() | :infinity}
|
| {:max_body_length, non_neg_integer() | :infinity}
|
||||||
| {:failed_request_ttl, :timer.time() | :infinity}
|
| {:failed_request_ttl, :timer.time() | :infinity}
|
||||||
| {:http, []}
|
| {:http, []}
|
||||||
|
@ -291,17 +287,13 @@ defp build_req_range_or_encoding_header(headers, _opts) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp build_req_user_agent_header(headers, opts) do
|
defp build_req_user_agent_header(headers, _opts) do
|
||||||
if Keyword.get(opts, :keep_user_agent, false) do
|
List.keystore(
|
||||||
List.keystore(
|
headers,
|
||||||
headers,
|
"user-agent",
|
||||||
"user-agent",
|
0,
|
||||||
0,
|
{"user-agent", Pleroma.Application.user_agent()}
|
||||||
{"user-agent", Pleroma.Application.user_agent()}
|
)
|
||||||
)
|
|
||||||
else
|
|
||||||
headers
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp build_resp_headers(headers, opts) do
|
defp build_resp_headers(headers, opts) do
|
||||||
|
|
|
@ -124,16 +124,16 @@ def render(
|
||||||
) do
|
) do
|
||||||
user = CommonAPI.get_user(activity.data["actor"])
|
user = CommonAPI.get_user(activity.data["actor"])
|
||||||
created_at = Utils.to_masto_date(activity.data["published"])
|
created_at = Utils.to_masto_date(activity.data["published"])
|
||||||
activity_object = Object.normalize(activity, fetch: false)
|
object = Object.normalize(activity, fetch: false)
|
||||||
|
|
||||||
reblogged_parent_activity =
|
reblogged_parent_activity =
|
||||||
if opts[:parent_activities] do
|
if opts[:parent_activities] do
|
||||||
Activity.Queries.find_by_object_ap_id(
|
Activity.Queries.find_by_object_ap_id(
|
||||||
opts[:parent_activities],
|
opts[:parent_activities],
|
||||||
activity_object.data["id"]
|
object.data["id"]
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
Activity.create_by_object_ap_id(activity_object.data["id"])
|
Activity.create_by_object_ap_id(object.data["id"])
|
||||||
|> Activity.with_preloaded_bookmark(opts[:for])
|
|> Activity.with_preloaded_bookmark(opts[:for])
|
||||||
|> Activity.with_set_thread_muted_field(opts[:for])
|
|> Activity.with_set_thread_muted_field(opts[:for])
|
||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
|
@ -142,7 +142,7 @@ def render(
|
||||||
reblog_rendering_opts = Map.put(opts, :activity, reblogged_parent_activity)
|
reblog_rendering_opts = Map.put(opts, :activity, reblogged_parent_activity)
|
||||||
reblogged = render("show.json", reblog_rendering_opts)
|
reblogged = render("show.json", reblog_rendering_opts)
|
||||||
|
|
||||||
favorited = opts[:for] && opts[:for].ap_id in (activity_object.data["likes"] || [])
|
favorited = opts[:for] && opts[:for].ap_id in (object.data["likes"] || [])
|
||||||
|
|
||||||
bookmarked = Activity.get_bookmark(reblogged_parent_activity, opts[:for]) != nil
|
bookmarked = Activity.get_bookmark(reblogged_parent_activity, opts[:for]) != nil
|
||||||
|
|
||||||
|
@ -154,8 +154,8 @@ def render(
|
||||||
|
|
||||||
%{
|
%{
|
||||||
id: to_string(activity.id),
|
id: to_string(activity.id),
|
||||||
uri: activity_object.data["id"],
|
uri: object.data["id"],
|
||||||
url: activity_object.data["id"],
|
url: object.data["id"],
|
||||||
account:
|
account:
|
||||||
AccountView.render("show.json", %{
|
AccountView.render("show.json", %{
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -180,7 +180,7 @@ def render(
|
||||||
media_attachments: reblogged[:media_attachments] || [],
|
media_attachments: reblogged[:media_attachments] || [],
|
||||||
mentions: mentions,
|
mentions: mentions,
|
||||||
tags: reblogged[:tags] || [],
|
tags: reblogged[:tags] || [],
|
||||||
application: build_application(activity_object.data["generator"]),
|
application: build_application(object.data["generator"]),
|
||||||
language: nil,
|
language: nil,
|
||||||
emojis: [],
|
emojis: [],
|
||||||
pleroma: %{
|
pleroma: %{
|
||||||
|
@ -538,6 +538,8 @@ defp build_emoji_map(emoji, users, current_user) do
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec build_application(map() | nil) :: map() | nil
|
@spec build_application(map() | nil) :: map() | nil
|
||||||
defp build_application(%{type: _type, name: name, url: url}), do: %{name: name, website: url}
|
defp build_application(%{"type" => _type, "name" => name, "url" => url}),
|
||||||
|
do: %{name: name, website: url}
|
||||||
|
|
||||||
defp build_application(_), do: nil
|
defp build_application(_), do: nil
|
||||||
end
|
end
|
||||||
|
|
4
mix.exs
4
mix.exs
|
@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
|
||||||
def project do
|
def project do
|
||||||
[
|
[
|
||||||
app: :pleroma,
|
app: :pleroma,
|
||||||
version: version("2.2.50"),
|
version: version("2.3.50"),
|
||||||
elixir: "~> 1.9",
|
elixir: "~> 1.9",
|
||||||
elixirc_paths: elixirc_paths(Mix.env()),
|
elixirc_paths: elixirc_paths(Mix.env()),
|
||||||
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
|
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
|
||||||
|
@ -158,7 +158,7 @@ defp deps do
|
||||||
{:floki, "~> 0.27"},
|
{:floki, "~> 0.27"},
|
||||||
{:timex, "~> 3.6"},
|
{:timex, "~> 3.6"},
|
||||||
{:ueberauth, "~> 0.4"},
|
{:ueberauth, "~> 0.4"},
|
||||||
{:linkify, "~> 0.4.1"},
|
{:linkify, "~> 0.5.0"},
|
||||||
{:http_signatures, "~> 0.1.0"},
|
{:http_signatures, "~> 0.1.0"},
|
||||||
{:telemetry, "~> 0.3"},
|
{:telemetry, "~> 0.3"},
|
||||||
{:poolboy, "~> 1.5"},
|
{:poolboy, "~> 1.5"},
|
||||||
|
|
2
mix.lock
2
mix.lock
|
@ -66,7 +66,7 @@
|
||||||
"jose": {:hex, :jose, "1.10.1", "16d8e460dae7203c6d1efa3f277e25b5af8b659febfc2f2eb4bacf87f128b80a", [:mix, :rebar3], [], "hexpm", "3c7ddc8a9394b92891db7c2771da94bf819834a1a4c92e30857b7d582e2f8257"},
|
"jose": {:hex, :jose, "1.10.1", "16d8e460dae7203c6d1efa3f277e25b5af8b659febfc2f2eb4bacf87f128b80a", [:mix, :rebar3], [], "hexpm", "3c7ddc8a9394b92891db7c2771da94bf819834a1a4c92e30857b7d582e2f8257"},
|
||||||
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},
|
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},
|
||||||
"libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"},
|
"libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"},
|
||||||
"linkify": {:hex, :linkify, "0.4.1", "f881eb3429ae88010cf736e6fb3eed406c187bcdd544902ec937496636b7c7b3", [:mix], [], "hexpm", "ce98693f54ae9ace59f2f7a8aed3de2ef311381a8ce7794804bd75484c371dda"},
|
"linkify": {:hex, :linkify, "0.5.0", "e0ea8de73ff44742d6a889721221f4c4eccaad5284957ee9832ffeb347602d54", [:mix], [], "hexpm", "4ccd958350aee7c51c89e21f05b15d30596ebbba707e051d21766be1809df2d7"},
|
||||||
"majic": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/majic.git", "289cda1b6d0d70ccb2ba508a2b0bd24638db2880", [ref: "289cda1b6d0d70ccb2ba508a2b0bd24638db2880"]},
|
"majic": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/majic.git", "289cda1b6d0d70ccb2ba508a2b0bd24638db2880", [ref: "289cda1b6d0d70ccb2ba508a2b0bd24638db2880"]},
|
||||||
"makeup": {:hex, :makeup, "1.0.3", "e339e2f766d12e7260e6672dd4047405963c5ec99661abdc432e6ec67d29ef95", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "2e9b4996d11832947731f7608fed7ad2f9443011b3b479ae288011265cdd3dad"},
|
"makeup": {:hex, :makeup, "1.0.3", "e339e2f766d12e7260e6672dd4047405963c5ec99661abdc432e6ec67d29ef95", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "2e9b4996d11832947731f7608fed7ad2f9443011b3b479ae288011265cdd3dad"},
|
||||||
"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"},
|
||||||
|
|
|
@ -4,7 +4,7 @@ defmodule Pleroma.Repo.Migrations.AddDefaultTextSearchConfig do
|
||||||
def change do
|
def change do
|
||||||
execute("DO $$
|
execute("DO $$
|
||||||
BEGIN
|
BEGIN
|
||||||
execute 'ALTER DATABASE '||current_database()||' SET default_text_search_config = ''english'' ';
|
execute 'ALTER DATABASE \"'||current_database()||'\" SET default_text_search_config = ''english'' ';
|
||||||
END
|
END
|
||||||
$$;")
|
$$;")
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,24 +18,23 @@ defmodule Pleroma.ReverseProxyTest do
|
||||||
|
|
||||||
setup :verify_on_exit!
|
setup :verify_on_exit!
|
||||||
|
|
||||||
defp user_agent_mock(user_agent, invokes) do
|
defp request_mock(invokes) do
|
||||||
json = Jason.encode!(%{"user-agent": user_agent})
|
|
||||||
|
|
||||||
ClientMock
|
ClientMock
|
||||||
|> expect(:request, fn :get, url, _, _, _ ->
|
|> expect(:request, fn :get, url, headers, _body, _opts ->
|
||||||
Registry.register(ClientMock, url, 0)
|
Registry.register(ClientMock, url, 0)
|
||||||
|
body = headers |> Enum.into(%{}) |> Jason.encode!()
|
||||||
|
|
||||||
{:ok, 200,
|
{:ok, 200,
|
||||||
[
|
[
|
||||||
{"content-type", "application/json"},
|
{"content-type", "application/json"},
|
||||||
{"content-length", byte_size(json) |> to_string()}
|
{"content-length", byte_size(body) |> to_string()}
|
||||||
], %{url: url}}
|
], %{url: url, body: body}}
|
||||||
end)
|
end)
|
||||||
|> expect(:stream_body, invokes, fn %{url: url} = client ->
|
|> expect(:stream_body, invokes, fn %{url: url, body: body} = client ->
|
||||||
case Registry.lookup(ClientMock, url) do
|
case Registry.lookup(ClientMock, url) do
|
||||||
[{_, 0}] ->
|
[{_, 0}] ->
|
||||||
Registry.update_value(ClientMock, url, &(&1 + 1))
|
Registry.update_value(ClientMock, url, &(&1 + 1))
|
||||||
{:ok, json, client}
|
{:ok, body, client}
|
||||||
|
|
||||||
[{_, 1}] ->
|
[{_, 1}] ->
|
||||||
Registry.unregister(ClientMock, url)
|
Registry.unregister(ClientMock, url)
|
||||||
|
@ -46,7 +45,7 @@ defp user_agent_mock(user_agent, invokes) do
|
||||||
|
|
||||||
describe "reverse proxy" do
|
describe "reverse proxy" do
|
||||||
test "do not track successful request", %{conn: conn} do
|
test "do not track successful request", %{conn: conn} do
|
||||||
user_agent_mock("hackney/1.15.1", 2)
|
request_mock(2)
|
||||||
url = "/success"
|
url = "/success"
|
||||||
|
|
||||||
conn = ReverseProxy.call(conn, url)
|
conn = ReverseProxy.call(conn, url)
|
||||||
|
@ -56,18 +55,15 @@ test "do not track successful request", %{conn: conn} do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "user-agent" do
|
test "use Pleroma's user agent in the request; don't pass the client's", %{conn: conn} do
|
||||||
test "don't keep", %{conn: conn} do
|
request_mock(2)
|
||||||
user_agent_mock("hackney/1.15.1", 2)
|
|
||||||
conn = ReverseProxy.call(conn, "/user-agent")
|
|
||||||
assert json_response(conn, 200) == %{"user-agent" => "hackney/1.15.1"}
|
|
||||||
end
|
|
||||||
|
|
||||||
test "keep", %{conn: conn} do
|
conn =
|
||||||
user_agent_mock(Pleroma.Application.user_agent(), 2)
|
conn
|
||||||
conn = ReverseProxy.call(conn, "/user-agent-keep", keep_user_agent: true)
|
|> Plug.Conn.put_req_header("user-agent", "fake/1.0")
|
||||||
assert json_response(conn, 200) == %{"user-agent" => Pleroma.Application.user_agent()}
|
|> ReverseProxy.call("/user-agent")
|
||||||
end
|
|
||||||
|
assert json_response(conn, 200) == %{"user-agent" => Pleroma.Application.user_agent()}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "closed connection", %{conn: conn} do
|
test "closed connection", %{conn: conn} do
|
||||||
|
@ -114,7 +110,7 @@ defp stream_mock(invokes, with_close? \\ false) do
|
||||||
|
|
||||||
describe "max_body" do
|
describe "max_body" do
|
||||||
test "length returns error if content-length more than option", %{conn: conn} do
|
test "length returns error if content-length more than option", %{conn: conn} do
|
||||||
user_agent_mock("hackney/1.15.1", 0)
|
request_mock(0)
|
||||||
|
|
||||||
assert capture_log(fn ->
|
assert capture_log(fn ->
|
||||||
ReverseProxy.call(conn, "/huge-file", max_body_length: 4)
|
ReverseProxy.call(conn, "/huge-file", max_body_length: 4)
|
||||||
|
|
|
@ -376,6 +376,16 @@ test "discloses application metadata when enabled" do
|
||||||
"status" => "cofe is my copilot"
|
"status" => "cofe is my copilot"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
assert %{
|
||||||
|
"content" => "cofe is my copilot"
|
||||||
|
} = json_response_and_validate_schema(result, 200)
|
||||||
|
|
||||||
|
activity = result.assigns.activity.id
|
||||||
|
|
||||||
|
result =
|
||||||
|
conn
|
||||||
|
|> get("api/v1/statuses/#{activity}")
|
||||||
|
|
||||||
assert %{
|
assert %{
|
||||||
"content" => "cofe is my copilot",
|
"content" => "cofe is my copilot",
|
||||||
"application" => %{
|
"application" => %{
|
||||||
|
@ -396,6 +406,15 @@ test "hides application metadata when disabled" do
|
||||||
"status" => "club mate is my wingman"
|
"status" => "club mate is my wingman"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
assert %{"content" => "club mate is my wingman"} =
|
||||||
|
json_response_and_validate_schema(result, 200)
|
||||||
|
|
||||||
|
activity = result.assigns.activity.id
|
||||||
|
|
||||||
|
result =
|
||||||
|
conn
|
||||||
|
|> get("api/v1/statuses/#{activity}")
|
||||||
|
|
||||||
assert %{
|
assert %{
|
||||||
"content" => "club mate is my wingman",
|
"content" => "club mate is my wingman",
|
||||||
"application" => nil
|
"application" => nil
|
||||||
|
|
Loading…
Reference in a new issue