Add logging for rejected ActivityPub payloads and add tests (#10062)
This commit is contained in:
		
							parent
							
								
									041ff5fa9a
								
							
						
					
					
						commit
						147b4c2c3a
					
				
					 5 changed files with 539 additions and 327 deletions
				
			
		|  | @ -180,4 +180,9 @@ class ActivityPub::Activity | |||
|   def requested_through_relay? | ||||
|     @options[:relayed_through_account] && Relay.find_by(inbox_url: @options[:relayed_through_account].inbox_url)&.enabled? | ||||
|   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 | ||||
|  |  | |||
|  | @ -2,9 +2,11 @@ | |||
| 
 | ||||
| class ActivityPub::Activity::Announce < ActivityPub::Activity | ||||
|   def perform | ||||
|     return reject_payload! if delete_arrived_first?(@json['id']) || !related_to_local_activity? | ||||
| 
 | ||||
|     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) | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| class ActivityPub::Activity::Create < ActivityPub::Activity | ||||
|   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| | ||||
|       if lock.acquired? | ||||
|  |  | |||
|  | @ -18,16 +18,63 @@ RSpec.describe ActivityPub::Activity::Announce do | |||
|   subject { described_class.new(json, sender) } | ||||
| 
 | ||||
|   before do | ||||
|     Fabricate(:account).follow!(sender) | ||||
|     sender.update(uri: ActivityPub::TagManager.instance.uri_for(sender)) | ||||
|   end | ||||
| 
 | ||||
|   describe '#perform' do | ||||
|     before do | ||||
|       subject.perform | ||||
|     context 'when sender is followed by a local account' do | ||||
|       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 | ||||
| 
 | ||||
|     context 'a known status' do | ||||
|     context 'when the status belongs to a local user' do | ||||
|       before do | ||||
|         subject.perform | ||||
|       end | ||||
| 
 | ||||
|       let(:object_json) do | ||||
|         ActivityPub::TagManager.instance.uri_for(status) | ||||
|       end | ||||
|  | @ -37,34 +84,68 @@ RSpec.describe ActivityPub::Activity::Announce do | |||
|       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', | ||||
|         } | ||||
|     context 'when the sender is relayed' do | ||||
|       let!(:relay_account) { Fabricate(:account, inbox_url: 'https://relay.example.com/inbox') } | ||||
|       let!(:relay) { Fabricate(:relay, inbox_url: 'https://relay.example.com/inbox') } | ||||
| 
 | ||||
|       subject { described_class.new(json, sender, relayed_through_account: relay_account) } | ||||
| 
 | ||||
|       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 | ||||
| 
 | ||||
|       it 'creates a reblog by sender of status' do | ||||
|         expect(sender.reblogged?(sender.statuses.first)).to be true | ||||
|       context 'and the relay is disabled' do | ||||
|         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 | ||||
| 
 | ||||
|     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 | ||||
|         { | ||||
|           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 | ||||
|       it 'does not create anything' do | ||||
|         expect(sender.statuses.count).to eq 0 | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  |  | |||
|  | @ -13,8 +13,6 @@ RSpec.describe ActivityPub::Activity::Create do | |||
|     }.with_indifferent_access | ||||
|   end | ||||
| 
 | ||||
|   subject { described_class.new(json, sender) } | ||||
| 
 | ||||
|   before do | ||||
|     sender.update(uri: ActivityPub::TagManager.instance.uri_for(sender)) | ||||
| 
 | ||||
|  | @ -23,11 +21,402 @@ RSpec.describe ActivityPub::Activity::Create do | |||
|   end | ||||
| 
 | ||||
|   describe '#perform' do | ||||
|     before do | ||||
|       subject.perform | ||||
|     context 'when fetching' do | ||||
|       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 | ||||
| 
 | ||||
|     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 | ||||
|         { | ||||
|           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.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', | ||||
|         } | ||||
|     context 'when sender replies to local status' do | ||||
|       let!(:local_status) { Fabricate(:status) } | ||||
| 
 | ||||
|       subject { described_class.new(json, sender, delivery: true) } | ||||
| 
 | ||||
|       before do | ||||
|         subject.perform | ||||
|       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), | ||||
|           inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status), | ||||
|         } | ||||
|       end | ||||
| 
 | ||||
|  | @ -121,28 +455,25 @@ RSpec.describe ActivityPub::Activity::Create 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 | ||||
|         expect(status.text).to eq 'Lorem ipsum' | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context 'direct' do | ||||
|       let(:recipient) { Fabricate(:account) } | ||||
|     context 'when sender targets a local user' do | ||||
|       let!(:local_account) { Fabricate(:account) } | ||||
| 
 | ||||
|       subject { described_class.new(json, sender, delivery: 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: ActivityPub::TagManager.instance.uri_for(recipient), | ||||
|           tag: { | ||||
|             type: 'Mention', | ||||
|             href: ActivityPub::TagManager.instance.uri_for(recipient), | ||||
|           }, | ||||
|           to: ActivityPub::TagManager.instance.uri_for(local_account), | ||||
|         } | ||||
|       end | ||||
| 
 | ||||
|  | @ -150,19 +481,25 @@ RSpec.describe ActivityPub::Activity::Create do | |||
|         status = sender.statuses.first | ||||
| 
 | ||||
|         expect(status).to_not be_nil | ||||
|         expect(status.visibility).to eq 'direct' | ||||
|         expect(status.text).to eq 'Lorem ipsum' | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context 'as a reply' do | ||||
|       let(:original_status) { Fabricate(:status) } | ||||
|     context 'when sender cc\'s a local user' do | ||||
|       let!(:local_account) { Fabricate(:account) } | ||||
| 
 | ||||
|       subject { described_class.new(json, sender, delivery: true) } | ||||
| 
 | ||||
|       before do | ||||
|         subject.perform | ||||
|       end | ||||
| 
 | ||||
|       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), | ||||
|           cc: ActivityPub::TagManager.instance.uri_for(local_account), | ||||
|         } | ||||
|       end | ||||
| 
 | ||||
|  | @ -170,240 +507,27 @@ RSpec.describe ActivityPub::Activity::Create 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 | ||||
|         expect(status.text).to eq 'Lorem ipsum' | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context 'with mentions' do | ||||
|       let(:recipient) { Fabricate(:account) } | ||||
|     context 'when the sender has no relevance to local activity' do | ||||
|       subject { described_class.new(json, sender, delivery: true) } | ||||
| 
 | ||||
|       before do | ||||
|         subject.perform | ||||
|       end | ||||
| 
 | ||||
|       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 | ||||
|       it 'does not create anything' do | ||||
|         expect(sender.statuses.count).to eq 0 | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  |  | |||
		Reference in a new issue