json_ld_helper_spec.rb 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. # frozen_string_literal: true
  2. require 'rails_helper'
  3. RSpec.describe JsonLdHelper do
  4. describe '#equals_or_includes?' do
  5. it 'returns true when value equals' do
  6. expect(helper.equals_or_includes?('foo', 'foo')).to be true
  7. end
  8. it 'returns false when value does not equal' do
  9. expect(helper.equals_or_includes?('foo', 'bar')).to be false
  10. end
  11. it 'returns true when value is included' do
  12. expect(helper.equals_or_includes?(%w(foo baz), 'foo')).to be true
  13. end
  14. it 'returns false when value is not included' do
  15. expect(helper.equals_or_includes?(%w(foo baz), 'bar')).to be false
  16. end
  17. end
  18. describe '#uri_from_bearcap' do
  19. subject { helper.uri_from_bearcap(string) }
  20. context 'when a bear string has a u param' do
  21. let(:string) { 'bear:?t=TOKEN&u=https://example.com/foo' }
  22. it 'returns the value from the u query param' do
  23. expect(subject).to eq('https://example.com/foo')
  24. end
  25. end
  26. context 'when a bear string does not have a u param' do
  27. let(:string) { 'bear:?t=TOKEN&h=https://example.com/foo' }
  28. it 'returns nil' do
  29. expect(subject).to be_nil
  30. end
  31. end
  32. context 'when a non-bear string' do
  33. let(:string) { 'http://example.com' }
  34. it 'returns the string' do
  35. expect(subject).to eq('http://example.com')
  36. end
  37. end
  38. end
  39. describe '#first_of_value' do
  40. context 'when value.is_a?(Array)' do
  41. it 'returns value.first' do
  42. value = ['a']
  43. expect(helper.first_of_value(value)).to be 'a'
  44. end
  45. end
  46. context 'with !value.is_a?(Array)' do
  47. it 'returns value' do
  48. value = 'a'
  49. expect(helper.first_of_value(value)).to be 'a'
  50. end
  51. end
  52. end
  53. describe '#supported_context?' do
  54. context 'when json is present and in an activitypub tagmanager context' do
  55. it 'returns true' do
  56. json = { '@context' => ActivityPub::TagManager::CONTEXT }.as_json
  57. expect(helper.supported_context?(json)).to be true
  58. end
  59. end
  60. context 'when not in activitypub tagmanager context' do
  61. it 'returns false' do
  62. json = nil
  63. expect(helper.supported_context?(json)).to be false
  64. end
  65. end
  66. end
  67. describe '#fetch_resource' do
  68. context 'when the second argument is false' do
  69. it 'returns resource even if the retrieved ID and the given URI does not match' do
  70. stub_request(:get, 'https://bob.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' })
  71. stub_request(:get, 'https://alice.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' })
  72. expect(fetch_resource('https://bob.test/', false)).to eq({ 'id' => 'https://alice.test/' })
  73. end
  74. it 'returns nil if the object identified by the given URI and the object identified by the retrieved ID does not match' do
  75. stub_request(:get, 'https://mallory.test/').to_return(body: '{"id": "https://marvin.test/"}', headers: { 'Content-Type': 'application/activity+json' })
  76. stub_request(:get, 'https://marvin.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' })
  77. expect(fetch_resource('https://mallory.test/', false)).to be_nil
  78. end
  79. end
  80. context 'when the second argument is true' do
  81. it 'returns nil if the retrieved ID and the given URI does not match' do
  82. stub_request(:get, 'https://mallory.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' })
  83. expect(fetch_resource('https://mallory.test/', true)).to be_nil
  84. end
  85. end
  86. end
  87. describe '#fetch_resource_without_id_validation' do
  88. it 'returns nil if the status code is not 200' do
  89. stub_request(:get, 'https://host.test/').to_return(status: 400, body: '{}', headers: { 'Content-Type': 'application/activity+json' })
  90. expect(fetch_resource_without_id_validation('https://host.test/')).to be_nil
  91. end
  92. it 'returns hash' do
  93. stub_request(:get, 'https://host.test/').to_return(status: 200, body: '{}', headers: { 'Content-Type': 'application/activity+json' })
  94. expect(fetch_resource_without_id_validation('https://host.test/')).to eq({})
  95. end
  96. end
  97. context 'with compaction and forwarding' do
  98. let(:json) do
  99. {
  100. '@context' => [
  101. 'https://www.w3.org/ns/activitystreams',
  102. 'https://w3id.org/security/v1',
  103. {
  104. 'obsolete' => 'http://ostatus.org#',
  105. 'convo' => 'obsolete:conversation',
  106. 'new' => 'https://obscure-unreleased-test.joinmastodon.org/#',
  107. },
  108. ],
  109. 'type' => 'Create',
  110. 'to' => ['https://www.w3.org/ns/activitystreams#Public'],
  111. 'object' => {
  112. 'id' => 'https://example.com/status',
  113. 'type' => 'Note',
  114. 'inReplyTo' => nil,
  115. 'convo' => 'https://example.com/conversation',
  116. 'tag' => [
  117. {
  118. 'type' => 'Mention',
  119. 'href' => ['foo'],
  120. },
  121. ],
  122. },
  123. 'signature' => {
  124. 'type' => 'RsaSignature2017',
  125. 'created' => '2022-02-02T12:00:00Z',
  126. 'creator' => 'https://example.com/actor#main-key',
  127. 'signatureValue' => 'some-sig',
  128. },
  129. }
  130. end
  131. describe '#compact' do
  132. it 'properly compacts JSON-LD with alternative context definitions' do
  133. expect(compact(json).dig('object', 'conversation')).to eq 'https://example.com/conversation'
  134. end
  135. it 'compacts single-item arrays' do
  136. expect(compact(json).dig('object', 'tag', 'href')).to eq 'foo'
  137. end
  138. it 'compacts the activitystreams Public collection' do
  139. expect(compact(json)['to']).to eq 'as:Public'
  140. end
  141. it 'properly copies signature' do
  142. expect(compact(json)['signature']).to eq json['signature']
  143. end
  144. end
  145. describe 'patch_for_forwarding!' do
  146. it 'properly patches incompatibilities' do
  147. json['object'].delete('convo')
  148. compacted = compact(json)
  149. patch_for_forwarding!(json, compacted)
  150. expect(compacted['to']).to eq ['https://www.w3.org/ns/activitystreams#Public']
  151. expect(compacted.dig('object', 'tag', 0, 'href')).to eq ['foo']
  152. expect(safe_for_forwarding?(json, compacted)).to be true
  153. end
  154. end
  155. describe 'safe_for_forwarding?' do
  156. it 'deems a safe compacting as such' do
  157. json['object'].delete('convo')
  158. compacted = compact(json)
  159. patch_for_forwarding!(json, compacted)
  160. expect(compacted['to']).to eq ['https://www.w3.org/ns/activitystreams#Public']
  161. expect(safe_for_forwarding?(json, compacted)).to be true
  162. end
  163. it 'deems an unsafe compacting as such' do
  164. compacted = compact(json)
  165. patch_for_forwarding!(json, compacted)
  166. expect(compacted['to']).to eq ['https://www.w3.org/ns/activitystreams#Public']
  167. expect(safe_for_forwarding?(json, compacted)).to be false
  168. end
  169. end
  170. end
  171. end