Add logging for rejected ActivityPub payloads and add tests (#10062)
parent
041ff5fa9a
commit
147b4c2c3a
|
@ -180,4 +180,9 @@ class ActivityPub::Activity
|
||||||
def requested_through_relay?
|
def requested_through_relay?
|
||||||
@options[:relayed_through_account] && Relay.find_by(inbox_url: @options[:relayed_through_account].inbox_url)&.enabled?
|
@options[:relayed_through_account] && Relay.find_by(inbox_url: @options[:relayed_through_account].inbox_url)&.enabled?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reject_payload!
|
||||||
|
Rails.logger.info("Rejected #{@json['type']} activity #{@json['id']} from #{@account.uri}#{@options[:relayed_through_account] && "via #{@options[:relayed_through_account].uri}"}")
|
||||||
|
nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
|
|
||||||
class ActivityPub::Activity::Announce < ActivityPub::Activity
|
class ActivityPub::Activity::Announce < ActivityPub::Activity
|
||||||
def perform
|
def perform
|
||||||
|
return reject_payload! if delete_arrived_first?(@json['id']) || !related_to_local_activity?
|
||||||
|
|
||||||
original_status = status_from_object
|
original_status = status_from_object
|
||||||
|
|
||||||
return if original_status.nil? || delete_arrived_first?(@json['id']) || !announceable?(original_status) || !related_to_local_activity?
|
return reject_payload! if original_status.nil? || !announceable?(original_status)
|
||||||
|
|
||||||
status = Status.find_by(account: @account, reblog: original_status)
|
status = Status.find_by(account: @account, reblog: original_status)
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
class ActivityPub::Activity::Create < ActivityPub::Activity
|
class ActivityPub::Activity::Create < ActivityPub::Activity
|
||||||
def perform
|
def perform
|
||||||
return if unsupported_object_type? || invalid_origin?(@object['id']) || Tombstone.exists?(uri: @object['id']) || !related_to_local_activity?
|
return reject_payload! if unsupported_object_type? || invalid_origin?(@object['id']) || Tombstone.exists?(uri: @object['id']) || !related_to_local_activity?
|
||||||
|
|
||||||
RedisLock.acquire(lock_options) do |lock|
|
RedisLock.acquire(lock_options) do |lock|
|
||||||
if lock.acquired?
|
if lock.acquired?
|
||||||
|
|
|
@ -18,16 +18,63 @@ RSpec.describe ActivityPub::Activity::Announce do
|
||||||
subject { described_class.new(json, sender) }
|
subject { described_class.new(json, sender) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
Fabricate(:account).follow!(sender)
|
|
||||||
sender.update(uri: ActivityPub::TagManager.instance.uri_for(sender))
|
sender.update(uri: ActivityPub::TagManager.instance.uri_for(sender))
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#perform' do
|
describe '#perform' do
|
||||||
before do
|
context 'when sender is followed by a local account' do
|
||||||
subject.perform
|
before do
|
||||||
|
Fabricate(:account).follow!(sender)
|
||||||
|
subject.perform
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'a known status' do
|
||||||
|
let(:object_json) do
|
||||||
|
ActivityPub::TagManager.instance.uri_for(status)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates a reblog by sender of status' do
|
||||||
|
expect(sender.reblogged?(status)).to be true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'self-boost of a previously unknown status with missing attributedTo' do
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
to: 'http://example.com/followers',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates a reblog by sender of status' do
|
||||||
|
expect(sender.reblogged?(sender.statuses.first)).to be true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'self-boost of a previously unknown status with correct attributedTo' do
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
|
||||||
|
to: 'http://example.com/followers',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates a reblog by sender of status' do
|
||||||
|
expect(sender.reblogged?(sender.statuses.first)).to be true
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'a known status' do
|
context 'when the status belongs to a local user' do
|
||||||
|
before do
|
||||||
|
subject.perform
|
||||||
|
end
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
ActivityPub::TagManager.instance.uri_for(status)
|
ActivityPub::TagManager.instance.uri_for(status)
|
||||||
end
|
end
|
||||||
|
@ -37,34 +84,68 @@ RSpec.describe ActivityPub::Activity::Announce do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'self-boost of a previously unknown status with missing attributedTo' do
|
context 'when the sender is relayed' do
|
||||||
let(:object_json) do
|
let!(:relay_account) { Fabricate(:account, inbox_url: 'https://relay.example.com/inbox') }
|
||||||
{
|
let!(:relay) { Fabricate(:relay, inbox_url: 'https://relay.example.com/inbox') }
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
subject { described_class.new(json, sender, relayed_through_account: relay_account) }
|
||||||
content: 'Lorem ipsum',
|
|
||||||
to: 'http://example.com/followers',
|
context 'and the relay is enabled' do
|
||||||
}
|
before do
|
||||||
|
relay.update(state: :accepted)
|
||||||
|
subject.perform
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
to: 'http://example.com/followers',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates a reblog by sender of status' do
|
||||||
|
expect(sender.statuses.count).to eq 2
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates a reblog by sender of status' do
|
context 'and the relay is disabled' do
|
||||||
expect(sender.reblogged?(sender.statuses.first)).to be true
|
before do
|
||||||
|
subject.perform
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
to: 'http://example.com/followers',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not create anything' do
|
||||||
|
expect(sender.statuses.count).to eq 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'self-boost of a previously unknown status with correct attributedTo' do
|
context 'when the sender has no relevance to local activity' do
|
||||||
|
before do
|
||||||
|
subject.perform
|
||||||
|
end
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
{
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
type: 'Note',
|
type: 'Note',
|
||||||
content: 'Lorem ipsum',
|
content: 'Lorem ipsum',
|
||||||
attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
|
|
||||||
to: 'http://example.com/followers',
|
to: 'http://example.com/followers',
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates a reblog by sender of status' do
|
it 'does not create anything' do
|
||||||
expect(sender.reblogged?(sender.statuses.first)).to be true
|
expect(sender.statuses.count).to eq 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,8 +13,6 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
}.with_indifferent_access
|
}.with_indifferent_access
|
||||||
end
|
end
|
||||||
|
|
||||||
subject { described_class.new(json, sender) }
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
sender.update(uri: ActivityPub::TagManager.instance.uri_for(sender))
|
sender.update(uri: ActivityPub::TagManager.instance.uri_for(sender))
|
||||||
|
|
||||||
|
@ -23,11 +21,402 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#perform' do
|
describe '#perform' do
|
||||||
before do
|
context 'when fetching' do
|
||||||
subject.perform
|
subject { described_class.new(json, sender) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
subject.perform
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'standalone' do
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
expect(status.text).to eq 'Lorem ipsum'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'missing to/cc defaults to direct privacy' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
expect(status.visibility).to eq 'direct'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'public' do
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
to: 'https://www.w3.org/ns/activitystreams#Public',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
expect(status.visibility).to eq 'public'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'unlisted' do
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
cc: 'https://www.w3.org/ns/activitystreams#Public',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
expect(status.visibility).to eq 'unlisted'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'private' do
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
to: 'http://example.com/followers',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
expect(status.visibility).to eq 'private'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'limited' do
|
||||||
|
let(:recipient) { Fabricate(:account) }
|
||||||
|
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
to: ActivityPub::TagManager.instance.uri_for(recipient),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
expect(status.visibility).to eq 'limited'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates silent mention' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
expect(status.mentions.first).to be_silent
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'direct' do
|
||||||
|
let(:recipient) { Fabricate(:account) }
|
||||||
|
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
to: ActivityPub::TagManager.instance.uri_for(recipient),
|
||||||
|
tag: {
|
||||||
|
type: 'Mention',
|
||||||
|
href: ActivityPub::TagManager.instance.uri_for(recipient),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
expect(status.visibility).to eq 'direct'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as a reply' do
|
||||||
|
let(:original_status) { Fabricate(:status) }
|
||||||
|
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
inReplyTo: ActivityPub::TagManager.instance.uri_for(original_status),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
expect(status.thread).to eq original_status
|
||||||
|
expect(status.reply?).to be true
|
||||||
|
expect(status.in_reply_to_account).to eq original_status.account
|
||||||
|
expect(status.conversation).to eq original_status.conversation
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with mentions' do
|
||||||
|
let(:recipient) { Fabricate(:account) }
|
||||||
|
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
tag: [
|
||||||
|
{
|
||||||
|
type: 'Mention',
|
||||||
|
href: ActivityPub::TagManager.instance.uri_for(recipient),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
expect(status.mentions.map(&:account)).to include(recipient)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with mentions missing href' do
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
tag: [
|
||||||
|
{
|
||||||
|
type: 'Mention',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with media attachments' do
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
attachment: [
|
||||||
|
{
|
||||||
|
type: 'Document',
|
||||||
|
mediaType: 'image/png',
|
||||||
|
url: 'http://example.com/attachment.png',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
expect(status.media_attachments.map(&:remote_url)).to include('http://example.com/attachment.png')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with media attachments with focal points' do
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
attachment: [
|
||||||
|
{
|
||||||
|
type: 'Document',
|
||||||
|
mediaType: 'image/png',
|
||||||
|
url: 'http://example.com/attachment.png',
|
||||||
|
focalPoint: [0.5, -0.7],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
expect(status.media_attachments.map(&:focus)).to include('0.5,-0.7')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with media attachments missing url' do
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
attachment: [
|
||||||
|
{
|
||||||
|
type: 'Document',
|
||||||
|
mediaType: 'image/png',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with hashtags' do
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
tag: [
|
||||||
|
{
|
||||||
|
type: 'Hashtag',
|
||||||
|
href: 'http://example.com/blah',
|
||||||
|
name: '#test',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
expect(status.tags.map(&:name)).to include('test')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with hashtags missing name' do
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
tag: [
|
||||||
|
{
|
||||||
|
type: 'Hashtag',
|
||||||
|
href: 'http://example.com/blah',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with emojis' do
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum :tinking:',
|
||||||
|
tag: [
|
||||||
|
{
|
||||||
|
type: 'Emoji',
|
||||||
|
icon: {
|
||||||
|
url: 'http://example.com/emoji.png',
|
||||||
|
},
|
||||||
|
name: 'tinking',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
expect(status.emojis.map(&:shortcode)).to include('tinking')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with emojis missing name' do
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum :tinking:',
|
||||||
|
tag: [
|
||||||
|
{
|
||||||
|
type: 'Emoji',
|
||||||
|
icon: {
|
||||||
|
url: 'http://example.com/emoji.png',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with emojis missing icon' do
|
||||||
|
let(:object_json) do
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum :tinking:',
|
||||||
|
tag: [
|
||||||
|
{
|
||||||
|
type: 'Emoji',
|
||||||
|
name: 'tinking',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates status' do
|
||||||
|
status = sender.statuses.first
|
||||||
|
expect(status).to_not be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'standalone' do
|
context 'when sender is followed by local users' do
|
||||||
|
subject { described_class.new(json, sender, delivery: true) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
Fabricate(:account).follow!(sender)
|
||||||
|
subject.perform
|
||||||
|
end
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
{
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
@ -42,78 +431,23 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
expect(status).to_not be_nil
|
expect(status).to_not be_nil
|
||||||
expect(status.text).to eq 'Lorem ipsum'
|
expect(status.text).to eq 'Lorem ipsum'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'missing to/cc defaults to direct privacy' do
|
|
||||||
status = sender.statuses.first
|
|
||||||
|
|
||||||
expect(status).to_not be_nil
|
|
||||||
expect(status.visibility).to eq 'direct'
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'public' do
|
context 'when sender replies to local status' do
|
||||||
let(:object_json) do
|
let!(:local_status) { Fabricate(:status) }
|
||||||
{
|
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
subject { described_class.new(json, sender, delivery: true) }
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
before do
|
||||||
to: 'https://www.w3.org/ns/activitystreams#Public',
|
subject.perform
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
|
||||||
status = sender.statuses.first
|
|
||||||
|
|
||||||
expect(status).to_not be_nil
|
|
||||||
expect(status.visibility).to eq 'public'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'unlisted' do
|
|
||||||
let(:object_json) do
|
|
||||||
{
|
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
cc: 'https://www.w3.org/ns/activitystreams#Public',
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates status' do
|
|
||||||
status = sender.statuses.first
|
|
||||||
|
|
||||||
expect(status).to_not be_nil
|
|
||||||
expect(status.visibility).to eq 'unlisted'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'private' do
|
|
||||||
let(:object_json) do
|
|
||||||
{
|
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
to: 'http://example.com/followers',
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates status' do
|
|
||||||
status = sender.statuses.first
|
|
||||||
|
|
||||||
expect(status).to_not be_nil
|
|
||||||
expect(status.visibility).to eq 'private'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'limited' do
|
|
||||||
let(:recipient) { Fabricate(:account) }
|
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
{
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
type: 'Note',
|
type: 'Note',
|
||||||
content: 'Lorem ipsum',
|
content: 'Lorem ipsum',
|
||||||
to: ActivityPub::TagManager.instance.uri_for(recipient),
|
inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status),
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -121,28 +455,25 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
status = sender.statuses.first
|
status = sender.statuses.first
|
||||||
|
|
||||||
expect(status).to_not be_nil
|
expect(status).to_not be_nil
|
||||||
expect(status.visibility).to eq 'limited'
|
expect(status.text).to eq 'Lorem ipsum'
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates silent mention' do
|
|
||||||
status = sender.statuses.first
|
|
||||||
expect(status.mentions.first).to be_silent
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'direct' do
|
context 'when sender targets a local user' do
|
||||||
let(:recipient) { Fabricate(:account) }
|
let!(:local_account) { Fabricate(:account) }
|
||||||
|
|
||||||
|
subject { described_class.new(json, sender, delivery: true) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
subject.perform
|
||||||
|
end
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
{
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
type: 'Note',
|
type: 'Note',
|
||||||
content: 'Lorem ipsum',
|
content: 'Lorem ipsum',
|
||||||
to: ActivityPub::TagManager.instance.uri_for(recipient),
|
to: ActivityPub::TagManager.instance.uri_for(local_account),
|
||||||
tag: {
|
|
||||||
type: 'Mention',
|
|
||||||
href: ActivityPub::TagManager.instance.uri_for(recipient),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -150,19 +481,25 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
status = sender.statuses.first
|
status = sender.statuses.first
|
||||||
|
|
||||||
expect(status).to_not be_nil
|
expect(status).to_not be_nil
|
||||||
expect(status.visibility).to eq 'direct'
|
expect(status.text).to eq 'Lorem ipsum'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'as a reply' do
|
context 'when sender cc\'s a local user' do
|
||||||
let(:original_status) { Fabricate(:status) }
|
let!(:local_account) { Fabricate(:account) }
|
||||||
|
|
||||||
|
subject { described_class.new(json, sender, delivery: true) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
subject.perform
|
||||||
|
end
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
{
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
type: 'Note',
|
type: 'Note',
|
||||||
content: 'Lorem ipsum',
|
content: 'Lorem ipsum',
|
||||||
inReplyTo: ActivityPub::TagManager.instance.uri_for(original_status),
|
cc: ActivityPub::TagManager.instance.uri_for(local_account),
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -170,240 +507,27 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
status = sender.statuses.first
|
status = sender.statuses.first
|
||||||
|
|
||||||
expect(status).to_not be_nil
|
expect(status).to_not be_nil
|
||||||
expect(status.thread).to eq original_status
|
expect(status.text).to eq 'Lorem ipsum'
|
||||||
expect(status.reply?).to be true
|
|
||||||
expect(status.in_reply_to_account).to eq original_status.account
|
|
||||||
expect(status.conversation).to eq original_status.conversation
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with mentions' do
|
context 'when the sender has no relevance to local activity' do
|
||||||
let(:recipient) { Fabricate(:account) }
|
subject { described_class.new(json, sender, delivery: true) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
subject.perform
|
||||||
|
end
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
{
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
type: 'Note',
|
type: 'Note',
|
||||||
content: 'Lorem ipsum',
|
content: 'Lorem ipsum',
|
||||||
tag: [
|
|
||||||
{
|
|
||||||
type: 'Mention',
|
|
||||||
href: ActivityPub::TagManager.instance.uri_for(recipient),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'does not create anything' do
|
||||||
status = sender.statuses.first
|
expect(sender.statuses.count).to eq 0
|
||||||
|
|
||||||
expect(status).to_not be_nil
|
|
||||||
expect(status.mentions.map(&:account)).to include(recipient)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with mentions missing href' do
|
|
||||||
let(:object_json) do
|
|
||||||
{
|
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
tag: [
|
|
||||||
{
|
|
||||||
type: 'Mention',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates status' do
|
|
||||||
status = sender.statuses.first
|
|
||||||
expect(status).to_not be_nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with media attachments' do
|
|
||||||
let(:object_json) do
|
|
||||||
{
|
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
attachment: [
|
|
||||||
{
|
|
||||||
type: 'Document',
|
|
||||||
mediaType: 'image/png',
|
|
||||||
url: 'http://example.com/attachment.png',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates status' do
|
|
||||||
status = sender.statuses.first
|
|
||||||
|
|
||||||
expect(status).to_not be_nil
|
|
||||||
expect(status.media_attachments.map(&:remote_url)).to include('http://example.com/attachment.png')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with media attachments with focal points' do
|
|
||||||
let(:object_json) do
|
|
||||||
{
|
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
attachment: [
|
|
||||||
{
|
|
||||||
type: 'Document',
|
|
||||||
mediaType: 'image/png',
|
|
||||||
url: 'http://example.com/attachment.png',
|
|
||||||
focalPoint: [0.5, -0.7],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates status' do
|
|
||||||
status = sender.statuses.first
|
|
||||||
|
|
||||||
expect(status).to_not be_nil
|
|
||||||
expect(status.media_attachments.map(&:focus)).to include('0.5,-0.7')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with media attachments missing url' do
|
|
||||||
let(:object_json) do
|
|
||||||
{
|
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
attachment: [
|
|
||||||
{
|
|
||||||
type: 'Document',
|
|
||||||
mediaType: 'image/png',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates status' do
|
|
||||||
status = sender.statuses.first
|
|
||||||
expect(status).to_not be_nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with hashtags' do
|
|
||||||
let(:object_json) do
|
|
||||||
{
|
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
tag: [
|
|
||||||
{
|
|
||||||
type: 'Hashtag',
|
|
||||||
href: 'http://example.com/blah',
|
|
||||||
name: '#test',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates status' do
|
|
||||||
status = sender.statuses.first
|
|
||||||
|
|
||||||
expect(status).to_not be_nil
|
|
||||||
expect(status.tags.map(&:name)).to include('test')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with hashtags missing name' do
|
|
||||||
let(:object_json) do
|
|
||||||
{
|
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
tag: [
|
|
||||||
{
|
|
||||||
type: 'Hashtag',
|
|
||||||
href: 'http://example.com/blah',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates status' do
|
|
||||||
status = sender.statuses.first
|
|
||||||
expect(status).to_not be_nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with emojis' do
|
|
||||||
let(:object_json) do
|
|
||||||
{
|
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum :tinking:',
|
|
||||||
tag: [
|
|
||||||
{
|
|
||||||
type: 'Emoji',
|
|
||||||
icon: {
|
|
||||||
url: 'http://example.com/emoji.png',
|
|
||||||
},
|
|
||||||
name: 'tinking',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates status' do
|
|
||||||
status = sender.statuses.first
|
|
||||||
|
|
||||||
expect(status).to_not be_nil
|
|
||||||
expect(status.emojis.map(&:shortcode)).to include('tinking')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with emojis missing name' do
|
|
||||||
let(:object_json) do
|
|
||||||
{
|
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum :tinking:',
|
|
||||||
tag: [
|
|
||||||
{
|
|
||||||
type: 'Emoji',
|
|
||||||
icon: {
|
|
||||||
url: 'http://example.com/emoji.png',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates status' do
|
|
||||||
status = sender.statuses.first
|
|
||||||
expect(status).to_not be_nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with emojis missing icon' do
|
|
||||||
let(:object_json) do
|
|
||||||
{
|
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum :tinking:',
|
|
||||||
tag: [
|
|
||||||
{
|
|
||||||
type: 'Emoji',
|
|
||||||
name: 'tinking',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates status' do
|
|
||||||
status = sender.statuses.first
|
|
||||||
expect(status).to_not be_nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Reference in New Issue