Merge branch 'release/2.0.4' into 'stable'
Release/2.0.4 See merge request pleroma/pleroma!2503
This commit is contained in:
commit
a6283bbae1
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -3,6 +3,31 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
|
## [2.0.4] - 2020-05-10
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- AP C2S: Fix a potential DoS by creating nonsensical objects that break timelines
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Peertube user lookups not working
|
||||||
|
- `InsertSkeletonsForDeletedUsers` migration failing on some instances
|
||||||
|
- Healthcheck reporting the number of memory currently used, rather than allocated in total
|
||||||
|
- LDAP not being usable in OTP releases
|
||||||
|
- Default apache configuration having tls chain issues
|
||||||
|
|
||||||
|
### Upgrade notes
|
||||||
|
|
||||||
|
#### Apache only
|
||||||
|
|
||||||
|
1. Remove the following line from your config:
|
||||||
|
```
|
||||||
|
SSLCertificateFile /etc/letsencrypt/live/${servername}/cert.pem
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Everyone
|
||||||
|
|
||||||
|
1. Restart Pleroma
|
||||||
|
|
||||||
## [2.0.3] - 2020-05-02
|
## [2.0.3] - 2020-05-02
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
|
@ -2260,6 +2260,7 @@
|
||||||
children: [
|
children: [
|
||||||
%{
|
%{
|
||||||
key: :active,
|
key: :active,
|
||||||
|
label: "Enabled",
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Globally enable or disable digest emails"
|
description: "Globally enable or disable digest emails"
|
||||||
},
|
},
|
||||||
|
|
|
@ -32,9 +32,8 @@ CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||||
|
|
||||||
<VirtualHost *:443>
|
<VirtualHost *:443>
|
||||||
SSLEngine on
|
SSLEngine on
|
||||||
SSLCertificateFile /etc/letsencrypt/live/${servername}/cert.pem
|
SSLCertificateFile /etc/letsencrypt/live/${servername}/fullchain.pem
|
||||||
SSLCertificateKeyFile /etc/letsencrypt/live/${servername}/privkey.pem
|
SSLCertificateKeyFile /etc/letsencrypt/live/${servername}/privkey.pem
|
||||||
SSLCertificateChainFile /etc/letsencrypt/live/${servername}/fullchain.pem
|
|
||||||
|
|
||||||
# Mozilla modern configuration, tweak to your needs
|
# Mozilla modern configuration, tweak to your needs
|
||||||
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
|
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
|
||||||
|
|
|
@ -29,7 +29,7 @@ defmodule Pleroma.Healthcheck do
|
||||||
@spec system_info() :: t()
|
@spec system_info() :: t()
|
||||||
def system_info do
|
def system_info do
|
||||||
%Healthcheck{
|
%Healthcheck{
|
||||||
memory_used: Float.round(:erlang.memory(:total) / 1024 / 1024, 2)
|
memory_used: Float.round(:recon_alloc.memory(:allocated) / 1024 / 1024, 2)
|
||||||
}
|
}
|
||||||
|> assign_db_info()
|
|> assign_db_info()
|
||||||
|> assign_job_queue_stats()
|
|> assign_job_queue_stats()
|
||||||
|
|
|
@ -370,7 +370,10 @@ def read_inbox(%{assigns: %{user: %{nickname: as_nickname}}} = conn, %{
|
||||||
|> json(err)
|
|> json(err)
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_user_activity(user, %{"type" => "Create"} = params) do
|
defp handle_user_activity(
|
||||||
|
%User{} = user,
|
||||||
|
%{"type" => "Create", "object" => %{"type" => "Note"}} = params
|
||||||
|
) do
|
||||||
object =
|
object =
|
||||||
params["object"]
|
params["object"]
|
||||||
|> Map.merge(Map.take(params, ["to", "cc"]))
|
|> Map.merge(Map.take(params, ["to", "cc"]))
|
||||||
|
@ -386,7 +389,7 @@ def handle_user_activity(user, %{"type" => "Create"} = params) do
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_user_activity(user, %{"type" => "Delete"} = params) do
|
defp handle_user_activity(user, %{"type" => "Delete"} = params) do
|
||||||
with %Object{} = object <- Object.normalize(params["object"]),
|
with %Object{} = object <- Object.normalize(params["object"]),
|
||||||
true <- user.is_moderator || user.ap_id == object.data["actor"],
|
true <- user.is_moderator || user.ap_id == object.data["actor"],
|
||||||
{:ok, delete} <- ActivityPub.delete(object) do
|
{:ok, delete} <- ActivityPub.delete(object) do
|
||||||
|
@ -396,7 +399,7 @@ def handle_user_activity(user, %{"type" => "Delete"} = params) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_user_activity(user, %{"type" => "Like"} = params) do
|
defp handle_user_activity(user, %{"type" => "Like"} = params) do
|
||||||
with %Object{} = object <- Object.normalize(params["object"]),
|
with %Object{} = object <- Object.normalize(params["object"]),
|
||||||
{:ok, activity, _object} <- ActivityPub.like(user, object) do
|
{:ok, activity, _object} <- ActivityPub.like(user, object) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
|
@ -405,7 +408,7 @@ def handle_user_activity(user, %{"type" => "Like"} = params) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_user_activity(_, _) do
|
defp handle_user_activity(_, _) do
|
||||||
{:error, dgettext("errors", "Unhandled activity type")}
|
{:error, dgettext("errors", "Unhandled activity type")}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -193,13 +193,15 @@ def finger(account) do
|
||||||
URI.parse(account).host
|
URI.parse(account).host
|
||||||
end
|
end
|
||||||
|
|
||||||
|
encoded_account = URI.encode("acct:#{account}")
|
||||||
|
|
||||||
address =
|
address =
|
||||||
case find_lrdd_template(domain) do
|
case find_lrdd_template(domain) do
|
||||||
{:ok, template} ->
|
{:ok, template} ->
|
||||||
String.replace(template, "{uri}", URI.encode(account))
|
String.replace(template, "{uri}", encoded_account)
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
"https://#{domain}/.well-known/webfinger?resource=acct:#{account}"
|
"https://#{domain}/.well-known/webfinger?resource=#{encoded_account}"
|
||||||
end
|
end
|
||||||
|
|
||||||
with response <-
|
with response <-
|
||||||
|
|
12
mix.exs
12
mix.exs
|
@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
|
||||||
def project do
|
def project do
|
||||||
[
|
[
|
||||||
app: :pleroma,
|
app: :pleroma,
|
||||||
version: version("2.0.3"),
|
version: version("2.0.4"),
|
||||||
elixir: "~> 1.8",
|
elixir: "~> 1.8",
|
||||||
elixirc_paths: elixirc_paths(Mix.env()),
|
elixirc_paths: elixirc_paths(Mix.env()),
|
||||||
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
|
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
|
||||||
|
@ -63,7 +63,15 @@ def copy_nginx_config(%{path: target_path} = release) do
|
||||||
def application do
|
def application do
|
||||||
[
|
[
|
||||||
mod: {Pleroma.Application, []},
|
mod: {Pleroma.Application, []},
|
||||||
extra_applications: [:logger, :runtime_tools, :comeonin, :quack, :fast_sanitize, :ssl],
|
extra_applications: [
|
||||||
|
:logger,
|
||||||
|
:runtime_tools,
|
||||||
|
:comeonin,
|
||||||
|
:quack,
|
||||||
|
:fast_sanitize,
|
||||||
|
:ssl,
|
||||||
|
:eldap
|
||||||
|
],
|
||||||
included_applications: [:ex_syslogger]
|
included_applications: [:ex_syslogger]
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,7 +30,7 @@ def change do
|
||||||
Repo,
|
Repo,
|
||||||
"select distinct unnest(nonexistent_locals.recipients) from activities, lateral (select array_agg(recipient) as recipients from unnest(activities.recipients) as recipient where recipient similar to '#{
|
"select distinct unnest(nonexistent_locals.recipients) from activities, lateral (select array_agg(recipient) as recipients from unnest(activities.recipients) as recipient where recipient similar to '#{
|
||||||
instance_uri
|
instance_uri
|
||||||
}/users/[A-Za-z0-9]*' and not(recipient in (select ap_id from users where local = true))) nonexistent_locals;",
|
}/users/[A-Za-z0-9]*' and not(recipient in (select ap_id from users))) nonexistent_locals;",
|
||||||
[],
|
[],
|
||||||
timeout: :infinity
|
timeout: :infinity
|
||||||
)
|
)
|
||||||
|
|
|
@ -211,7 +211,7 @@ def get(
|
||||||
end
|
end
|
||||||
|
|
||||||
def get(
|
def get(
|
||||||
"https://squeet.me/xrd/?uri=lain@squeet.me",
|
"https://squeet.me/xrd/?uri=acct:lain@squeet.me",
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
Accept: "application/xrd+xml,application/jrd+json"
|
Accept: "application/xrd+xml,application/jrd+json"
|
||||||
|
@ -850,7 +850,7 @@ def get(
|
||||||
end
|
end
|
||||||
|
|
||||||
def get(
|
def get(
|
||||||
"https://social.heldscal.la/.well-known/webfinger?resource=shp@social.heldscal.la",
|
"https://social.heldscal.la/.well-known/webfinger?resource=acct:shp@social.heldscal.la",
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
Accept: "application/xrd+xml,application/jrd+json"
|
Accept: "application/xrd+xml,application/jrd+json"
|
||||||
|
@ -863,7 +863,7 @@ def get(
|
||||||
end
|
end
|
||||||
|
|
||||||
def get(
|
def get(
|
||||||
"https://social.heldscal.la/.well-known/webfinger?resource=invalid_content@social.heldscal.la",
|
"https://social.heldscal.la/.well-known/webfinger?resource=acct:invalid_content@social.heldscal.la",
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
Accept: "application/xrd+xml,application/jrd+json"
|
Accept: "application/xrd+xml,application/jrd+json"
|
||||||
|
@ -880,7 +880,7 @@ def get("http://framatube.org/.well-known/host-meta", _, _, _) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def get(
|
def get(
|
||||||
"http://framatube.org/main/xrd?uri=framasoft@framatube.org",
|
"http://framatube.org/main/xrd?uri=acct:framasoft@framatube.org",
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
Accept: "application/xrd+xml,application/jrd+json"
|
Accept: "application/xrd+xml,application/jrd+json"
|
||||||
|
@ -939,7 +939,7 @@ def get("http://gerzilla.de/.well-known/host-meta", _, _, _) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def get(
|
def get(
|
||||||
"https://gerzilla.de/xrd/?uri=kaniini@gerzilla.de",
|
"https://gerzilla.de/xrd/?uri=acct:kaniini@gerzilla.de",
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
Accept: "application/xrd+xml,application/jrd+json"
|
Accept: "application/xrd+xml,application/jrd+json"
|
||||||
|
@ -1135,7 +1135,7 @@ def get("http://404.site" <> _, _, _, _) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def get(
|
def get(
|
||||||
"https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=lain@zetsubou.xn--q9jyb4c",
|
"https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=acct:lain@zetsubou.xn--q9jyb4c",
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
Accept: "application/xrd+xml,application/jrd+json"
|
Accept: "application/xrd+xml,application/jrd+json"
|
||||||
|
@ -1148,7 +1148,7 @@ def get(
|
||||||
end
|
end
|
||||||
|
|
||||||
def get(
|
def get(
|
||||||
"https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=https://zetsubou.xn--q9jyb4c/users/lain",
|
"https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=acct:https://zetsubou.xn--q9jyb4c/users/lain",
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
Accept: "application/xrd+xml,application/jrd+json"
|
Accept: "application/xrd+xml,application/jrd+json"
|
||||||
|
|
|
@ -652,9 +652,25 @@ test "it returns an announce activity in a collection", %{conn: conn} do
|
||||||
|
|
||||||
assert response(conn, 200) =~ announce_activity.data["object"]
|
assert response(conn, 200) =~ announce_activity.data["object"]
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test "it rejects posts from other users", %{conn: conn} do
|
describe "POST /users/:nickname/outbox (C2S)" do
|
||||||
data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
|
setup do
|
||||||
|
[
|
||||||
|
activity: %{
|
||||||
|
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type" => "Create",
|
||||||
|
"object" => %{"type" => "Note", "content" => "AP C2S test"},
|
||||||
|
"to" => "https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"cc" => []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it rejects posts from other users / unauthenticated users", %{
|
||||||
|
conn: conn,
|
||||||
|
activity: activity
|
||||||
|
} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
otheruser = insert(:user)
|
otheruser = insert(:user)
|
||||||
|
|
||||||
|
@ -662,39 +678,76 @@ test "it rejects posts from other users", %{conn: conn} do
|
||||||
conn
|
conn
|
||||||
|> assign(:user, otheruser)
|
|> assign(:user, otheruser)
|
||||||
|> put_req_header("content-type", "application/activity+json")
|
|> put_req_header("content-type", "application/activity+json")
|
||||||
|> post("/users/#{user.nickname}/outbox", data)
|
|> post("/users/#{user.nickname}/outbox", activity)
|
||||||
|
|
||||||
assert json_response(conn, 403)
|
assert json_response(conn, 403)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it inserts an incoming create activity into the database", %{conn: conn} do
|
test "it inserts an incoming create activity into the database", %{
|
||||||
data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
|
conn: conn,
|
||||||
|
activity: activity
|
||||||
|
} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
conn =
|
result =
|
||||||
conn
|
conn
|
||||||
|> assign(:user, user)
|
|> assign(:user, user)
|
||||||
|> put_req_header("content-type", "application/activity+json")
|
|> put_req_header("content-type", "application/activity+json")
|
||||||
|> post("/users/#{user.nickname}/outbox", data)
|
|> post("/users/#{user.nickname}/outbox", activity)
|
||||||
|
|> json_response(201)
|
||||||
result = json_response(conn, 201)
|
|
||||||
|
|
||||||
assert Activity.get_by_ap_id(result["id"])
|
assert Activity.get_by_ap_id(result["id"])
|
||||||
|
assert result["object"]
|
||||||
|
assert %Object{data: object} = Object.normalize(result["object"])
|
||||||
|
assert object["content"] == activity["object"]["content"]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it rejects an incoming activity with bogus type", %{conn: conn} do
|
test "it rejects anything beyond 'Note' creations", %{conn: conn, activity: activity} do
|
||||||
data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
|
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
data =
|
activity =
|
||||||
data
|
activity
|
||||||
|> Map.put("type", "BadType")
|
|> put_in(["object", "type"], "Benis")
|
||||||
|
|
||||||
|
_result =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> put_req_header("content-type", "application/activity+json")
|
||||||
|
|> post("/users/#{user.nickname}/outbox", activity)
|
||||||
|
|> json_response(400)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it inserts an incoming sensitive activity into the database", %{
|
||||||
|
conn: conn,
|
||||||
|
activity: activity
|
||||||
|
} do
|
||||||
|
user = insert(:user)
|
||||||
|
object = Map.put(activity["object"], "sensitive", true)
|
||||||
|
activity = Map.put(activity, "object", object)
|
||||||
|
|
||||||
|
result =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> put_req_header("content-type", "application/activity+json")
|
||||||
|
|> post("/users/#{user.nickname}/outbox", activity)
|
||||||
|
|> json_response(201)
|
||||||
|
|
||||||
|
assert Activity.get_by_ap_id(result["id"])
|
||||||
|
assert result["object"]
|
||||||
|
assert %Object{data: object} = Object.normalize(result["object"])
|
||||||
|
assert object["sensitive"] == activity["object"]["sensitive"]
|
||||||
|
assert object["content"] == activity["object"]["content"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it rejects an incoming activity with bogus type", %{conn: conn, activity: activity} do
|
||||||
|
user = insert(:user)
|
||||||
|
activity = Map.put(activity, "type", "BadType")
|
||||||
|
|
||||||
conn =
|
conn =
|
||||||
conn
|
conn
|
||||||
|> assign(:user, user)
|
|> assign(:user, user)
|
||||||
|> put_req_header("content-type", "application/activity+json")
|
|> put_req_header("content-type", "application/activity+json")
|
||||||
|> post("/users/#{user.nickname}/outbox", data)
|
|> post("/users/#{user.nickname}/outbox", activity)
|
||||||
|
|
||||||
assert json_response(conn, 400)
|
assert json_response(conn, 400)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue