Add logging for rejected ActivityPub payloads and add tests (#10062)
This commit is contained in:
		
							parent
							
								
									3547e3e59e
								
							
						
					
					
						commit
						397f180493
					
				
					 5 changed files with 539 additions and 327 deletions
				
			
		|  | @ -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 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue