闭社主体 forked from https://github.com/tootsuite/mastodon
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

760 lines
21 KiB

  1. require 'rails_helper'
  2. RSpec.describe ActivityPub::Activity::Create do
  3. let(:sender) { Fabricate(:account, followers_url: 'http://example.com/followers', domain: 'example.com', uri: 'https://example.com/actor') }
  4. let(:json) do
  5. {
  6. '@context': 'https://www.w3.org/ns/activitystreams',
  7. id: [ActivityPub::TagManager.instance.uri_for(sender), '#foo'].join,
  8. type: 'Create',
  9. actor: ActivityPub::TagManager.instance.uri_for(sender),
  10. object: object_json,
  11. }.with_indifferent_access
  12. end
  13. before do
  14. sender.update(uri: ActivityPub::TagManager.instance.uri_for(sender))
  15. stub_request(:get, 'http://example.com/attachment.png').to_return(request_fixture('avatar.txt'))
  16. stub_request(:get, 'http://example.com/emoji.png').to_return(body: attachment_fixture('emojo.png'))
  17. end
  18. describe '#perform' do
  19. context 'when fetching' do
  20. subject { described_class.new(json, sender) }
  21. before do
  22. subject.perform
  23. end
  24. context 'unknown object type' do
  25. let(:object_json) do
  26. {
  27. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  28. type: 'Banana',
  29. content: 'Lorem ipsum',
  30. }
  31. end
  32. it 'does not create a status' do
  33. expect(sender.statuses.count).to be_zero
  34. end
  35. end
  36. context 'standalone' do
  37. let(:object_json) do
  38. {
  39. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  40. type: 'Note',
  41. content: 'Lorem ipsum',
  42. }
  43. end
  44. it 'creates status' do
  45. status = sender.statuses.first
  46. expect(status).to_not be_nil
  47. expect(status.text).to eq 'Lorem ipsum'
  48. end
  49. it 'missing to/cc defaults to direct privacy' do
  50. status = sender.statuses.first
  51. expect(status).to_not be_nil
  52. expect(status.visibility).to eq 'direct'
  53. end
  54. end
  55. context 'public' do
  56. let(:object_json) do
  57. {
  58. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  59. type: 'Note',
  60. content: 'Lorem ipsum',
  61. to: 'https://www.w3.org/ns/activitystreams#Public',
  62. }
  63. end
  64. it 'creates status' do
  65. status = sender.statuses.first
  66. expect(status).to_not be_nil
  67. expect(status.visibility).to eq 'public'
  68. end
  69. end
  70. context 'unlisted' do
  71. let(:object_json) do
  72. {
  73. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  74. type: 'Note',
  75. content: 'Lorem ipsum',
  76. cc: 'https://www.w3.org/ns/activitystreams#Public',
  77. }
  78. end
  79. it 'creates status' do
  80. status = sender.statuses.first
  81. expect(status).to_not be_nil
  82. expect(status.visibility).to eq 'unlisted'
  83. end
  84. end
  85. context 'private' do
  86. let(:object_json) do
  87. {
  88. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  89. type: 'Note',
  90. content: 'Lorem ipsum',
  91. to: 'http://example.com/followers',
  92. }
  93. end
  94. it 'creates status' do
  95. status = sender.statuses.first
  96. expect(status).to_not be_nil
  97. expect(status.visibility).to eq 'private'
  98. end
  99. end
  100. context 'limited' do
  101. let(:recipient) { Fabricate(:account) }
  102. let(:object_json) do
  103. {
  104. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  105. type: 'Note',
  106. content: 'Lorem ipsum',
  107. to: ActivityPub::TagManager.instance.uri_for(recipient),
  108. }
  109. end
  110. it 'creates status' do
  111. status = sender.statuses.first
  112. expect(status).to_not be_nil
  113. expect(status.visibility).to eq 'limited'
  114. end
  115. it 'creates silent mention' do
  116. status = sender.statuses.first
  117. expect(status.mentions.first).to be_silent
  118. end
  119. end
  120. context 'direct' do
  121. let(:recipient) { Fabricate(:account) }
  122. let(:object_json) do
  123. {
  124. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  125. type: 'Note',
  126. content: 'Lorem ipsum',
  127. to: ActivityPub::TagManager.instance.uri_for(recipient),
  128. tag: {
  129. type: 'Mention',
  130. href: ActivityPub::TagManager.instance.uri_for(recipient),
  131. },
  132. }
  133. end
  134. it 'creates status' do
  135. status = sender.statuses.first
  136. expect(status).to_not be_nil
  137. expect(status.visibility).to eq 'direct'
  138. end
  139. end
  140. context 'as a reply' do
  141. let(:original_status) { Fabricate(:status) }
  142. let(:object_json) do
  143. {
  144. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  145. type: 'Note',
  146. content: 'Lorem ipsum',
  147. inReplyTo: ActivityPub::TagManager.instance.uri_for(original_status),
  148. }
  149. end
  150. it 'creates status' do
  151. status = sender.statuses.first
  152. expect(status).to_not be_nil
  153. expect(status.thread).to eq original_status
  154. expect(status.reply?).to be true
  155. expect(status.in_reply_to_account).to eq original_status.account
  156. expect(status.conversation).to eq original_status.conversation
  157. end
  158. end
  159. context 'with mentions' do
  160. let(:recipient) { Fabricate(:account) }
  161. let(:object_json) do
  162. {
  163. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  164. type: 'Note',
  165. content: 'Lorem ipsum',
  166. tag: [
  167. {
  168. type: 'Mention',
  169. href: ActivityPub::TagManager.instance.uri_for(recipient),
  170. },
  171. ],
  172. }
  173. end
  174. it 'creates status' do
  175. status = sender.statuses.first
  176. expect(status).to_not be_nil
  177. expect(status.mentions.map(&:account)).to include(recipient)
  178. end
  179. end
  180. context 'with mentions missing href' do
  181. let(:object_json) do
  182. {
  183. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  184. type: 'Note',
  185. content: 'Lorem ipsum',
  186. tag: [
  187. {
  188. type: 'Mention',
  189. },
  190. ],
  191. }
  192. end
  193. it 'creates status' do
  194. status = sender.statuses.first
  195. expect(status).to_not be_nil
  196. end
  197. end
  198. context 'with media attachments' do
  199. let(:object_json) do
  200. {
  201. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  202. type: 'Note',
  203. content: 'Lorem ipsum',
  204. attachment: [
  205. {
  206. type: 'Document',
  207. mediaType: 'image/png',
  208. url: 'http://example.com/attachment.png',
  209. },
  210. ],
  211. }
  212. end
  213. it 'creates status' do
  214. status = sender.statuses.first
  215. expect(status).to_not be_nil
  216. expect(status.media_attachments.map(&:remote_url)).to include('http://example.com/attachment.png')
  217. end
  218. end
  219. context 'with media attachments with long description' do
  220. let(:object_json) do
  221. {
  222. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  223. type: 'Note',
  224. content: 'Lorem ipsum',
  225. attachment: [
  226. {
  227. type: 'Document',
  228. mediaType: 'image/png',
  229. url: 'http://example.com/attachment.png',
  230. name: '*' * 1500,
  231. },
  232. ],
  233. }
  234. end
  235. it 'creates status' do
  236. status = sender.statuses.first
  237. expect(status).to_not be_nil
  238. expect(status.media_attachments.map(&:description)).to include('*' * 1500)
  239. end
  240. end
  241. context 'with media attachments with long description as summary' do
  242. let(:object_json) do
  243. {
  244. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  245. type: 'Note',
  246. content: 'Lorem ipsum',
  247. attachment: [
  248. {
  249. type: 'Document',
  250. mediaType: 'image/png',
  251. url: 'http://example.com/attachment.png',
  252. summary: '*' * 1500,
  253. },
  254. ],
  255. }
  256. end
  257. it 'creates status' do
  258. status = sender.statuses.first
  259. expect(status).to_not be_nil
  260. expect(status.media_attachments.map(&:description)).to include('*' * 1500)
  261. end
  262. end
  263. context 'with media attachments with focal points' do
  264. let(:object_json) do
  265. {
  266. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  267. type: 'Note',
  268. content: 'Lorem ipsum',
  269. attachment: [
  270. {
  271. type: 'Document',
  272. mediaType: 'image/png',
  273. url: 'http://example.com/attachment.png',
  274. focalPoint: [0.5, -0.7],
  275. },
  276. ],
  277. }
  278. end
  279. it 'creates status' do
  280. status = sender.statuses.first
  281. expect(status).to_not be_nil
  282. expect(status.media_attachments.map(&:focus)).to include('0.5,-0.7')
  283. end
  284. end
  285. context 'with media attachments missing url' do
  286. let(:object_json) do
  287. {
  288. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  289. type: 'Note',
  290. content: 'Lorem ipsum',
  291. attachment: [
  292. {
  293. type: 'Document',
  294. mediaType: 'image/png',
  295. },
  296. ],
  297. }
  298. end
  299. it 'creates status' do
  300. status = sender.statuses.first
  301. expect(status).to_not be_nil
  302. end
  303. end
  304. context 'with hashtags' do
  305. let(:object_json) do
  306. {
  307. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  308. type: 'Note',
  309. content: 'Lorem ipsum',
  310. tag: [
  311. {
  312. type: 'Hashtag',
  313. href: 'http://example.com/blah',
  314. name: '#test',
  315. },
  316. ],
  317. }
  318. end
  319. it 'creates status' do
  320. status = sender.statuses.first
  321. expect(status).to_not be_nil
  322. expect(status.tags.map(&:name)).to include('test')
  323. end
  324. end
  325. context 'with hashtags missing name' do
  326. let(:object_json) do
  327. {
  328. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  329. type: 'Note',
  330. content: 'Lorem ipsum',
  331. tag: [
  332. {
  333. type: 'Hashtag',
  334. href: 'http://example.com/blah',
  335. },
  336. ],
  337. }
  338. end
  339. it 'creates status' do
  340. status = sender.statuses.first
  341. expect(status).to_not be_nil
  342. end
  343. end
  344. context 'with hashtags invalid name' do
  345. let(:object_json) do
  346. {
  347. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  348. type: 'Note',
  349. content: 'Lorem ipsum',
  350. tag: [
  351. {
  352. type: 'Hashtag',
  353. href: 'http://example.com/blah',
  354. name: 'foo, #eh !',
  355. },
  356. ],
  357. }
  358. end
  359. it 'creates status' do
  360. status = sender.statuses.first
  361. expect(status).to_not be_nil
  362. end
  363. end
  364. context 'with emojis' do
  365. let(:object_json) do
  366. {
  367. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  368. type: 'Note',
  369. content: 'Lorem ipsum :tinking:',
  370. tag: [
  371. {
  372. type: 'Emoji',
  373. icon: {
  374. url: 'http://example.com/emoji.png',
  375. },
  376. name: 'tinking',
  377. },
  378. ],
  379. }
  380. end
  381. it 'creates status' do
  382. status = sender.statuses.first
  383. expect(status).to_not be_nil
  384. expect(status.emojis.map(&:shortcode)).to include('tinking')
  385. end
  386. end
  387. context 'with emojis missing name' do
  388. let(:object_json) do
  389. {
  390. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  391. type: 'Note',
  392. content: 'Lorem ipsum :tinking:',
  393. tag: [
  394. {
  395. type: 'Emoji',
  396. icon: {
  397. url: 'http://example.com/emoji.png',
  398. },
  399. },
  400. ],
  401. }
  402. end
  403. it 'creates status' do
  404. status = sender.statuses.first
  405. expect(status).to_not be_nil
  406. end
  407. end
  408. context 'with emojis missing icon' do
  409. let(:object_json) do
  410. {
  411. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  412. type: 'Note',
  413. content: 'Lorem ipsum :tinking:',
  414. tag: [
  415. {
  416. type: 'Emoji',
  417. name: 'tinking',
  418. },
  419. ],
  420. }
  421. end
  422. it 'creates status' do
  423. status = sender.statuses.first
  424. expect(status).to_not be_nil
  425. end
  426. end
  427. context 'with poll' do
  428. let(:object_json) do
  429. {
  430. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  431. type: 'Question',
  432. content: 'Which color was the submarine?',
  433. oneOf: [
  434. {
  435. name: 'Yellow',
  436. replies: {
  437. type: 'Collection',
  438. totalItems: 10,
  439. },
  440. },
  441. {
  442. name: 'Blue',
  443. replies: {
  444. type: 'Collection',
  445. totalItems: 3,
  446. }
  447. },
  448. ],
  449. }
  450. end
  451. it 'creates status' do
  452. status = sender.statuses.first
  453. expect(status).to_not be_nil
  454. expect(status.poll).to_not be_nil
  455. end
  456. it 'creates a poll' do
  457. poll = sender.polls.first
  458. expect(poll).to_not be_nil
  459. expect(poll.status).to_not be_nil
  460. expect(poll.options).to eq %w(Yellow Blue)
  461. expect(poll.cached_tallies).to eq [10, 3]
  462. end
  463. end
  464. context 'when a vote to a local poll' do
  465. let(:poll) { Fabricate(:poll, options: %w(Yellow Blue)) }
  466. let!(:local_status) { Fabricate(:status, poll: poll) }
  467. let(:object_json) do
  468. {
  469. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  470. type: 'Note',
  471. name: 'Yellow',
  472. inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status)
  473. }
  474. end
  475. it 'adds a vote to the poll with correct uri' do
  476. vote = poll.votes.first
  477. expect(vote).to_not be_nil
  478. expect(vote.uri).to eq object_json[:id]
  479. expect(poll.reload.cached_tallies).to eq [1, 0]
  480. end
  481. end
  482. context 'when a vote to an expired local poll' do
  483. let(:poll) do
  484. poll = Fabricate.build(:poll, options: %w(Yellow Blue), expires_at: 1.day.ago)
  485. poll.save(validate: false)
  486. poll
  487. end
  488. let!(:local_status) { Fabricate(:status, poll: poll) }
  489. let(:object_json) do
  490. {
  491. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  492. type: 'Note',
  493. name: 'Yellow',
  494. inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status)
  495. }
  496. end
  497. it 'does not add a vote to the poll' do
  498. expect(poll.votes.first).to be_nil
  499. end
  500. end
  501. end
  502. context 'with an encrypted message' do
  503. let(:recipient) { Fabricate(:account) }
  504. let(:target_device) { Fabricate(:device, account: recipient) }
  505. subject { described_class.new(json, sender, delivery: true, delivered_to_account_id: recipient.id) }
  506. let(:object_json) do
  507. {
  508. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  509. type: 'EncryptedMessage',
  510. attributedTo: {
  511. type: 'Device',
  512. deviceId: '1234',
  513. },
  514. to: {
  515. type: 'Device',
  516. deviceId: target_device.device_id,
  517. },
  518. messageType: 1,
  519. cipherText: 'Foo',
  520. messageFranking: 'Baz678',
  521. digest: {
  522. digestAlgorithm: 'Bar456',
  523. digestValue: 'Foo123',
  524. },
  525. }
  526. end
  527. before do
  528. subject.perform
  529. end
  530. it 'creates an encrypted message' do
  531. encrypted_message = target_device.encrypted_messages.reload.first
  532. expect(encrypted_message).to_not be_nil
  533. expect(encrypted_message.from_device_id).to eq '1234'
  534. expect(encrypted_message.from_account).to eq sender
  535. expect(encrypted_message.type).to eq 1
  536. expect(encrypted_message.body).to eq 'Foo'
  537. expect(encrypted_message.digest).to eq 'Foo123'
  538. end
  539. it 'creates a message franking' do
  540. encrypted_message = target_device.encrypted_messages.reload.first
  541. message_franking = encrypted_message.message_franking
  542. crypt = ActiveSupport::MessageEncryptor.new(SystemKey.current_key, serializer: Oj)
  543. json = crypt.decrypt_and_verify(message_franking)
  544. expect(json['source_account_id']).to eq sender.id
  545. expect(json['target_account_id']).to eq recipient.id
  546. expect(json['original_franking']).to eq 'Baz678'
  547. end
  548. end
  549. context 'when sender is followed by local users' do
  550. subject { described_class.new(json, sender, delivery: true) }
  551. before do
  552. Fabricate(:account).follow!(sender)
  553. subject.perform
  554. end
  555. let(:object_json) do
  556. {
  557. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  558. type: 'Note',
  559. content: 'Lorem ipsum',
  560. }
  561. end
  562. it 'creates status' do
  563. status = sender.statuses.first
  564. expect(status).to_not be_nil
  565. expect(status.text).to eq 'Lorem ipsum'
  566. end
  567. end
  568. context 'when sender replies to local status' do
  569. let!(:local_status) { Fabricate(:status) }
  570. subject { described_class.new(json, sender, delivery: true) }
  571. before do
  572. subject.perform
  573. end
  574. let(:object_json) do
  575. {
  576. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  577. type: 'Note',
  578. content: 'Lorem ipsum',
  579. inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status),
  580. }
  581. end
  582. it 'creates status' do
  583. status = sender.statuses.first
  584. expect(status).to_not be_nil
  585. expect(status.text).to eq 'Lorem ipsum'
  586. end
  587. end
  588. context 'when sender targets a local user' do
  589. let!(:local_account) { Fabricate(:account) }
  590. subject { described_class.new(json, sender, delivery: true) }
  591. before do
  592. subject.perform
  593. end
  594. let(:object_json) do
  595. {
  596. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  597. type: 'Note',
  598. content: 'Lorem ipsum',
  599. to: ActivityPub::TagManager.instance.uri_for(local_account),
  600. }
  601. end
  602. it 'creates status' do
  603. status = sender.statuses.first
  604. expect(status).to_not be_nil
  605. expect(status.text).to eq 'Lorem ipsum'
  606. end
  607. end
  608. context 'when sender cc\'s a local user' do
  609. let!(:local_account) { Fabricate(:account) }
  610. subject { described_class.new(json, sender, delivery: true) }
  611. before do
  612. subject.perform
  613. end
  614. let(:object_json) do
  615. {
  616. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  617. type: 'Note',
  618. content: 'Lorem ipsum',
  619. cc: ActivityPub::TagManager.instance.uri_for(local_account),
  620. }
  621. end
  622. it 'creates status' do
  623. status = sender.statuses.first
  624. expect(status).to_not be_nil
  625. expect(status.text).to eq 'Lorem ipsum'
  626. end
  627. end
  628. context 'when the sender has no relevance to local activity' do
  629. subject { described_class.new(json, sender, delivery: true) }
  630. before do
  631. subject.perform
  632. end
  633. let(:object_json) do
  634. {
  635. id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
  636. type: 'Note',
  637. content: 'Lorem ipsum',
  638. }
  639. end
  640. it 'does not create anything' do
  641. expect(sender.statuses.count).to eq 0
  642. end
  643. end
  644. end
  645. end