Merge remote-tracking branch 'origin/develop' into fork
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
commit
9876411269
13 changed files with 225 additions and 5 deletions
1
changelog.d/fix-webfinger-spoofing.security
Normal file
1
changelog.d/fix-webfinger-spoofing.security
Normal file
|
@ -0,0 +1 @@
|
|||
Fix webfinger spoofing.
|
1
changelog.d/status-notification-type.add
Normal file
1
changelog.d/status-notification-type.add
Normal file
|
@ -0,0 +1 @@
|
|||
Add "status" notification type
|
1
changelog.d/webfinger-validation.fix
Normal file
1
changelog.d/webfinger-validation.fix
Normal file
|
@ -0,0 +1 @@
|
|||
Fix validate_webfinger when running a different domain for Webfinger
|
|
@ -165,10 +165,10 @@ defp cachex_children do
|
|||
expiration: chat_message_id_idempotency_key_expiration(),
|
||||
limit: 500_000
|
||||
),
|
||||
build_cachex("anti_duplication_mrf", limit: 5_000),
|
||||
build_cachex("translations", default_ttl: :timer.hours(24), limit: 5_000),
|
||||
build_cachex("rel_me", default_ttl: :timer.minutes(30), limit: 2_500),
|
||||
build_cachex("host_meta", default_ttl: :timer.minutes(120), limit: 5000),
|
||||
build_cachex("anti_duplication_mrf", limit: 5_000),
|
||||
build_cachex("translations", default_ttl: :timer.hours(24), limit: 5_000),
|
||||
build_cachex("domain", limit: 2500)
|
||||
]
|
||||
end
|
||||
|
|
|
@ -399,6 +399,8 @@ defp do_create_notifications(%Activity{} = activity) do
|
|||
get_notified_subscribers_from_activity(activity) --
|
||||
(enabled_participants ++ enabled_receivers)
|
||||
|
||||
enabled_subscribers = get_notified_subscribers_from_activity(activity)
|
||||
|
||||
notifications =
|
||||
(Enum.map(enabled_receivers, fn user ->
|
||||
create_notification(activity, user)
|
||||
|
@ -607,7 +609,7 @@ def get_notified_participants_from_activity(
|
|||
Enum.filter(potential_receivers, fn u -> u.ap_id in notification_enabled_ap_ids end)
|
||||
end
|
||||
|
||||
def get_notified_participants_from_activity(_, _), do: {[], []}
|
||||
def get_notified_participants_from_activity(_, _), do: []
|
||||
|
||||
# For some activities, only notify the author of the object
|
||||
def get_potential_receiver_ap_ids(%{data: %{"type" => type, "object" => object_id}})
|
||||
|
|
|
@ -108,6 +108,9 @@ def render(
|
|||
type when type in ["mention", "status", "poll", "pleroma:event_reminder"] ->
|
||||
put_status(response, activity, reading_user, status_render_opts)
|
||||
|
||||
"status" ->
|
||||
put_status(response, activity, reading_user, status_render_opts)
|
||||
|
||||
"favourite" ->
|
||||
put_status(response, parent_activity_fn.(), reading_user, status_render_opts)
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ def down do
|
|||
'reblog',
|
||||
'favourite',
|
||||
'pleroma:report',
|
||||
'poll
|
||||
'poll',
|
||||
)
|
||||
"""
|
||||
|> execute()
|
||||
|
|
|
@ -52,7 +52,8 @@ def down do
|
|||
'favourite',
|
||||
'pleroma:report',
|
||||
'poll',
|
||||
'status'
|
||||
'status',
|
||||
'update'
|
||||
)
|
||||
"""
|
||||
|> execute()
|
||||
|
|
41
test/fixtures/webfinger/graf-imposter-webfinger.json
vendored
Normal file
41
test/fixtures/webfinger/graf-imposter-webfinger.json
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"subject": "acct:graf@poa.st",
|
||||
"aliases": [
|
||||
"https://fba.ryona.agenc/webfingertest"
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"rel": "http://webfinger.net/rel/profile-page",
|
||||
"type": "text/html",
|
||||
"href": "https://fba.ryona.agenc/webfingertest"
|
||||
},
|
||||
{
|
||||
"rel": "self",
|
||||
"type": "application/activity+json",
|
||||
"href": "https://fba.ryona.agenc/webfingertest"
|
||||
},
|
||||
{
|
||||
"rel": "http://ostatus.org/schema/1.0/subscribe",
|
||||
"template": "https://fba.ryona.agenc/contact/follow?url={uri}"
|
||||
},
|
||||
{
|
||||
"rel": "http://schemas.google.com/g/2010#updates-from",
|
||||
"type": "application/atom+xml",
|
||||
"href": ""
|
||||
},
|
||||
{
|
||||
"rel": "salmon",
|
||||
"href": "https://fba.ryona.agenc/salmon/friendica"
|
||||
},
|
||||
{
|
||||
"rel": "http://microformats.org/profile/hcard",
|
||||
"type": "text/html",
|
||||
"href": "https://fba.ryona.agenc/hcard/friendica"
|
||||
},
|
||||
{
|
||||
"rel": "http://joindiaspora.com/seed_location",
|
||||
"type": "text/html",
|
||||
"href": "https://fba.ryona.agenc"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -204,6 +204,21 @@ test "doesn't create notification for events without participation approval" do
|
|||
assert length(user_notifications) == 0
|
||||
end
|
||||
|
||||
test "does not create subscriber notification if mentioned" do
|
||||
user = insert(:user)
|
||||
subscriber = insert(:user)
|
||||
|
||||
User.subscribe(subscriber, user)
|
||||
|
||||
{:ok, status} = CommonAPI.post(user, %{status: "mentioning @#{subscriber.nickname}"})
|
||||
{:ok, [notification] = notifications} = Notification.create_notifications(status)
|
||||
|
||||
assert length(notifications) == 1
|
||||
|
||||
assert notification.user_id == subscriber.id
|
||||
assert notification.type == "mention"
|
||||
end
|
||||
|
||||
test "it sends edited notifications to those who repeated a status" do
|
||||
user = insert(:user)
|
||||
repeated_user = insert(:user)
|
||||
|
|
|
@ -332,4 +332,31 @@ test "muted notification" do
|
|||
|
||||
test_notifications_rendering([notification], user, [expected])
|
||||
end
|
||||
|
||||
test "Subscribed status notification" do
|
||||
user = insert(:user)
|
||||
subscriber = insert(:user)
|
||||
|
||||
User.subscribe(subscriber, user)
|
||||
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "hi"})
|
||||
{:ok, [notification]} = Notification.create_notifications(activity)
|
||||
|
||||
user = User.get_cached_by_id(user.id)
|
||||
|
||||
expected = %{
|
||||
id: to_string(notification.id),
|
||||
pleroma: %{is_seen: false, is_muted: false},
|
||||
type: "status",
|
||||
account:
|
||||
AccountView.render("show.json", %{
|
||||
user: user,
|
||||
for: subscriber
|
||||
}),
|
||||
status: StatusView.render("show.json", %{activity: activity, for: subscriber}),
|
||||
created_at: Utils.to_masto_date(notification.inserted_at)
|
||||
}
|
||||
|
||||
test_notifications_rendering([notification], subscriber, [expected])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -226,4 +226,18 @@ test "prevents spoofing" do
|
|||
{:error, _data} = WebFinger.finger("alex@gleasonator.com")
|
||||
end
|
||||
end
|
||||
|
||||
@tag capture_log: true
|
||||
test "prevents forgeries" do
|
||||
Tesla.Mock.mock(fn
|
||||
%{url: "https://fba.ryona.agency/.well-known/webfinger?resource=acct:graf@fba.ryona.agency"} ->
|
||||
fake_webfinger =
|
||||
File.read!("test/fixtures/webfinger/graf-imposter-webfinger.json") |> Jason.decode!()
|
||||
|
||||
Tesla.Mock.json(fake_webfinger)
|
||||
|
||||
%{url: "https://fba.ryona.agency/.well-known/host-meta"} ->
|
||||
{:ok, %Tesla.Env{status: 404}}
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1693,6 +1693,120 @@ def get("https://friends.grishka.me/users/1", _, _, _) do
|
|||
}}
|
||||
end
|
||||
|
||||
def get("https://mastodon.example/.well-known/host-meta", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 302,
|
||||
headers: [{"location", "https://sub.mastodon.example/.well-known/host-meta"}]
|
||||
}}
|
||||
end
|
||||
|
||||
def get("https://sub.mastodon.example/.well-known/host-meta", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body:
|
||||
"test/fixtures/webfinger/masto-host-meta.xml"
|
||||
|> File.read!()
|
||||
|> String.replace("{{domain}}", "sub.mastodon.example")
|
||||
}}
|
||||
end
|
||||
|
||||
def get(
|
||||
"https://sub.mastodon.example/.well-known/webfinger?resource=acct:a@mastodon.example",
|
||||
_,
|
||||
_,
|
||||
_
|
||||
) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body:
|
||||
"test/fixtures/webfinger/masto-webfinger.json"
|
||||
|> File.read!()
|
||||
|> String.replace("{{nickname}}", "a")
|
||||
|> String.replace("{{domain}}", "mastodon.example")
|
||||
|> String.replace("{{subdomain}}", "sub.mastodon.example"),
|
||||
headers: [{"content-type", "application/jrd+json"}]
|
||||
}}
|
||||
end
|
||||
|
||||
def get("https://sub.mastodon.example/users/a", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body:
|
||||
"test/fixtures/webfinger/masto-user.json"
|
||||
|> File.read!()
|
||||
|> String.replace("{{nickname}}", "a")
|
||||
|> String.replace("{{domain}}", "sub.mastodon.example"),
|
||||
headers: [{"content-type", "application/activity+json"}]
|
||||
}}
|
||||
end
|
||||
|
||||
def get("https://sub.mastodon.example/users/a/collections/featured", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body:
|
||||
File.read!("test/fixtures/users_mock/masto_featured.json")
|
||||
|> String.replace("{{domain}}", "sub.mastodon.example")
|
||||
|> String.replace("{{nickname}}", "a"),
|
||||
headers: [{"content-type", "application/activity+json"}]
|
||||
}}
|
||||
end
|
||||
|
||||
def get("https://pleroma.example/.well-known/host-meta", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 302,
|
||||
headers: [{"location", "https://sub.pleroma.example/.well-known/host-meta"}]
|
||||
}}
|
||||
end
|
||||
|
||||
def get("https://sub.pleroma.example/.well-known/host-meta", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body:
|
||||
"test/fixtures/webfinger/pleroma-host-meta.xml"
|
||||
|> File.read!()
|
||||
|> String.replace("{{domain}}", "sub.pleroma.example")
|
||||
}}
|
||||
end
|
||||
|
||||
def get(
|
||||
"https://sub.pleroma.example/.well-known/webfinger?resource=acct:a@pleroma.example",
|
||||
_,
|
||||
_,
|
||||
_
|
||||
) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body:
|
||||
"test/fixtures/webfinger/pleroma-webfinger.json"
|
||||
|> File.read!()
|
||||
|> String.replace("{{nickname}}", "a")
|
||||
|> String.replace("{{domain}}", "pleroma.example")
|
||||
|> String.replace("{{subdomain}}", "sub.pleroma.example"),
|
||||
headers: [{"content-type", "application/jrd+json"}]
|
||||
}}
|
||||
end
|
||||
|
||||
def get("https://sub.pleroma.example/users/a", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body:
|
||||
"test/fixtures/webfinger/pleroma-user.json"
|
||||
|> File.read!()
|
||||
|> String.replace("{{nickname}}", "a")
|
||||
|> String.replace("{{domain}}", "sub.pleroma.example"),
|
||||
headers: [{"content-type", "application/activity+json"}]
|
||||
}}
|
||||
end
|
||||
|
||||
def get(url, query, body, headers) do
|
||||
{:error,
|
||||
"Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"}
|
||||
|
|
Loading…
Reference in a new issue