process_collection_service_spec.rb 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. require 'rails_helper'
  2. RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
  3. let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account') }
  4. let(:payload) do
  5. {
  6. '@context': 'https://www.w3.org/ns/activitystreams',
  7. id: 'foo',
  8. type: 'Create',
  9. actor: ActivityPub::TagManager.instance.uri_for(actor),
  10. object: {
  11. id: 'bar',
  12. type: 'Note',
  13. content: 'Lorem ipsum',
  14. },
  15. }
  16. end
  17. let(:json) { Oj.dump(payload) }
  18. subject { described_class.new }
  19. describe '#call' do
  20. context 'when actor is suspended' do
  21. before do
  22. actor.suspend!(origin: :remote)
  23. end
  24. %w(Accept Add Announce Block Create Flag Follow Like Move Remove).each do |activity_type|
  25. context "with #{activity_type} activity" do
  26. let(:payload) do
  27. {
  28. '@context': 'https://www.w3.org/ns/activitystreams',
  29. id: 'foo',
  30. type: activity_type,
  31. actor: ActivityPub::TagManager.instance.uri_for(actor),
  32. }
  33. end
  34. it 'does not process payload' do
  35. expect(ActivityPub::Activity).not_to receive(:factory)
  36. subject.call(json, actor)
  37. end
  38. end
  39. end
  40. %w(Delete Reject Undo Update).each do |activity_type|
  41. context "with #{activity_type} activity" do
  42. let(:payload) do
  43. {
  44. '@context': 'https://www.w3.org/ns/activitystreams',
  45. id: 'foo',
  46. type: activity_type,
  47. actor: ActivityPub::TagManager.instance.uri_for(actor),
  48. }
  49. end
  50. it 'processes the payload' do
  51. expect(ActivityPub::Activity).to receive(:factory)
  52. subject.call(json, actor)
  53. end
  54. end
  55. end
  56. end
  57. context 'when actor differs from sender' do
  58. let(:forwarder) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/other_account') }
  59. it 'does not process payload if no signature exists' do
  60. expect_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(nil)
  61. expect(ActivityPub::Activity).not_to receive(:factory)
  62. subject.call(json, forwarder)
  63. end
  64. it 'processes payload with actor if valid signature exists' do
  65. payload['signature'] = { 'type' => 'RsaSignature2017' }
  66. expect_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(actor)
  67. expect(ActivityPub::Activity).to receive(:factory).with(instance_of(Hash), actor, instance_of(Hash))
  68. subject.call(json, forwarder)
  69. end
  70. it 'does not process payload if invalid signature exists' do
  71. payload['signature'] = { 'type' => 'RsaSignature2017' }
  72. expect_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(nil)
  73. expect(ActivityPub::Activity).not_to receive(:factory)
  74. subject.call(json, forwarder)
  75. end
  76. context 'when receiving a fabricated status' do
  77. let!(:actor) do
  78. Fabricate(:account,
  79. username: 'bob',
  80. domain: 'example.com',
  81. uri: 'https://example.com/users/bob',
  82. public_key: "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuuYyoyfsRkYnXRotMsId\nW3euBDDfiv9oVqOxUVC7bhel8KednIMrMCRWFAkgJhbrlzbIkjVr68o1MP9qLcn7\nCmH/BXHp7yhuFTr4byjdJKpwB+/i2jNEsvDH5jR8WTAeTCe0x/QHg21V3F7dSI5m\nCCZ/1dSIyOXLRTWVlfDlm3rE4ntlCo+US3/7oSWbg/4/4qEnt1HC32kvklgScxua\n4LR5ATdoXa5bFoopPWhul7MJ6NyWCyQyScUuGdlj8EN4kmKQJvphKHrI9fvhgOuG\nTvhTR1S5InA4azSSchY0tXEEw/VNxraeX0KPjbgr6DPcwhPd/m0nhVDq0zVyVBBD\nMwIDAQAB\n-----END PUBLIC KEY-----\n",
  83. private_key: nil)
  84. end
  85. let(:payload) do
  86. {
  87. '@context': [
  88. 'https://www.w3.org/ns/activitystreams',
  89. nil,
  90. {'object': 'https://www.w3.org/ns/activitystreams#object'}
  91. ],
  92. 'id': 'https://example.com/users/bob/fake-status/activity',
  93. 'type': 'Create',
  94. 'actor': 'https://example.com/users/bob',
  95. 'published': '2022-01-22T15:00:00Z',
  96. 'to': [
  97. 'https://www.w3.org/ns/activitystreams#Public'
  98. ],
  99. 'cc': [
  100. 'https://example.com/users/bob/followers'
  101. ],
  102. 'signature': {
  103. 'type': 'RsaSignature2017',
  104. 'creator': 'https://example.com/users/bob#main-key',
  105. 'created': '2022-03-09T21:57:25Z',
  106. 'signatureValue': 'WculK0LelTQ0MvGwU9TPoq5pFzFfGYRDCJqjZ232/Udj4CHqDTGOSw5UTDLShqBOyycCkbZGrQwXG+dpyDpQLSe1UVPZ5TPQtc/9XtI57WlS2nMNpdvRuxGnnb2btPdesXZ7n3pCxo0zjaXrJMe0mqQh5QJO22mahb4bDwwmfTHgbD3nmkD+fBfGi+UV2qWwqr+jlV4L4JqNkh0gWljF5KTePLRRZCuWiQ/FAt7c67636cdIPf7fR+usjuZltTQyLZKEGuK8VUn2Gkfsx5qns7Vcjvlz1JqlAjyO8HPBbzTTHzUG2nUOIgC3PojCSWv6mNTmRGoLZzOscCAYQA6cKw=='
  107. },
  108. '@id': 'https://example.com/users/bob/statuses/107928807471117876/activity',
  109. '@type': 'https://www.w3.org/ns/activitystreams#Create',
  110. 'https://www.w3.org/ns/activitystreams#actor': {
  111. '@id': 'https://example.com/users/bob'
  112. },
  113. 'https://www.w3.org/ns/activitystreams#cc': {
  114. '@id': 'https://example.com/users/bob/followers'
  115. },
  116. 'object': {
  117. 'id': 'https://example.com/users/bob/fake-status',
  118. 'type': 'Note',
  119. 'published': '2022-01-22T15:00:00Z',
  120. 'url': 'https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=puck-was-here',
  121. 'attributedTo': 'https://example.com/users/bob',
  122. 'to': [
  123. 'https://www.w3.org/ns/activitystreams#Public'
  124. ],
  125. 'cc': [
  126. 'https://example.com/users/bob/followers'
  127. ],
  128. 'sensitive': false,
  129. 'atomUri': 'https://example.com/users/bob/fake-status',
  130. 'conversation': 'tag:example.com,2022-03-09:objectId=15:objectType=Conversation',
  131. 'content': '<p>puck was here</p>',
  132. '@id': 'https://example.com/users/bob/statuses/107928807471117876',
  133. '@type': 'https://www.w3.org/ns/activitystreams#Note',
  134. 'http://ostatus.org#atomUri': 'https://example.com/users/bob/statuses/107928807471117876',
  135. 'http://ostatus.org#conversation': 'tag:example.com,2022-03-09:objectId=15:objectType=Conversation',
  136. 'https://www.w3.org/ns/activitystreams#attachment': [],
  137. 'https://www.w3.org/ns/activitystreams#attributedTo': {
  138. '@id': 'https://example.com/users/bob'
  139. },
  140. 'https://www.w3.org/ns/activitystreams#cc': {
  141. '@id': 'https://example.com/users/bob/followers'
  142. },
  143. 'https://www.w3.org/ns/activitystreams#content': [
  144. '<p>hello world</p>',
  145. {
  146. '@value': '<p>hello world</p>',
  147. '@language': 'en'
  148. }
  149. ],
  150. 'https://www.w3.org/ns/activitystreams#published': {
  151. '@type': 'http://www.w3.org/2001/XMLSchema#dateTime',
  152. '@value': '2022-03-09T21:55:07Z'
  153. },
  154. 'https://www.w3.org/ns/activitystreams#replies': {
  155. '@id': 'https://example.com/users/bob/statuses/107928807471117876/replies',
  156. '@type': 'https://www.w3.org/ns/activitystreams#Collection',
  157. 'https://www.w3.org/ns/activitystreams#first': {
  158. '@type': 'https://www.w3.org/ns/activitystreams#CollectionPage',
  159. 'https://www.w3.org/ns/activitystreams#items': [],
  160. 'https://www.w3.org/ns/activitystreams#next': {
  161. '@id': 'https://example.com/users/bob/statuses/107928807471117876/replies?only_other_accounts=true&page=true'
  162. },
  163. 'https://www.w3.org/ns/activitystreams#partOf': {
  164. '@id': 'https://example.com/users/bob/statuses/107928807471117876/replies'
  165. }
  166. }
  167. },
  168. 'https://www.w3.org/ns/activitystreams#sensitive': false,
  169. 'https://www.w3.org/ns/activitystreams#tag': [],
  170. 'https://www.w3.org/ns/activitystreams#to': {
  171. '@id': 'https://www.w3.org/ns/activitystreams#Public'
  172. },
  173. 'https://www.w3.org/ns/activitystreams#url': {
  174. '@id': 'https://example.com/@bob/107928807471117876'
  175. }
  176. },
  177. 'https://www.w3.org/ns/activitystreams#published': {
  178. '@type': 'http://www.w3.org/2001/XMLSchema#dateTime',
  179. '@value': '2022-03-09T21:55:07Z'
  180. },
  181. 'https://www.w3.org/ns/activitystreams#to': {
  182. '@id': 'https://www.w3.org/ns/activitystreams#Public'
  183. }
  184. }
  185. end
  186. it 'does not process forged payload' do
  187. expect(ActivityPub::Activity).not_to receive(:factory).with(
  188. hash_including(
  189. 'object' => hash_including(
  190. 'id' => 'https://example.com/users/bob/fake-status'
  191. )
  192. ),
  193. anything(),
  194. anything()
  195. )
  196. expect(ActivityPub::Activity).not_to receive(:factory).with(
  197. hash_including(
  198. 'object' => hash_including(
  199. 'content' => '<p>puck was here</p>'
  200. )
  201. ),
  202. anything(),
  203. anything()
  204. )
  205. subject.call(json, forwarder)
  206. expect(Status.where(uri: 'https://example.com/users/bob/fake-status').exists?).to be false
  207. end
  208. end
  209. end
  210. end
  211. end