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.

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