linked_data_signature_spec.rb 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. # frozen_string_literal: true
  2. require 'rails_helper'
  3. RSpec.describe ActivityPub::LinkedDataSignature do
  4. include JsonLdHelper
  5. subject { described_class.new(json) }
  6. let!(:sender) { Fabricate(:account, uri: 'http://example.com/alice', domain: 'example.com') }
  7. let(:raw_json) do
  8. {
  9. '@context' => 'https://www.w3.org/ns/activitystreams',
  10. 'id' => 'http://example.com/hello-world',
  11. }
  12. end
  13. let(:json) { raw_json.merge('signature' => signature) }
  14. before do
  15. stub_jsonld_contexts!
  16. end
  17. describe '#verify_actor!' do
  18. context 'when signature matches' do
  19. let(:raw_signature) do
  20. {
  21. 'creator' => 'http://example.com/alice',
  22. 'created' => '2017-09-23T20:21:34Z',
  23. }
  24. end
  25. let(:signature) { raw_signature.merge('type' => 'RsaSignature2017', 'signatureValue' => sign(sender, raw_signature, raw_json)) }
  26. it 'returns creator' do
  27. expect(subject.verify_actor!).to eq sender
  28. end
  29. end
  30. context 'when signature is missing' do
  31. let(:signature) { nil }
  32. it 'returns nil' do
  33. expect(subject.verify_actor!).to be_nil
  34. end
  35. end
  36. context 'when signature is tampered' do
  37. let(:raw_signature) do
  38. {
  39. 'creator' => 'http://example.com/alice',
  40. 'created' => '2017-09-23T20:21:34Z',
  41. }
  42. end
  43. let(:signature) { raw_signature.merge('type' => 'RsaSignature2017', 'signatureValue' => 's69F3mfddd99dGjmvjdjjs81e12jn121Gkm1') }
  44. it 'returns nil' do
  45. expect(subject.verify_actor!).to be_nil
  46. end
  47. end
  48. end
  49. describe '#sign!' do
  50. subject { described_class.new(raw_json).sign!(sender) }
  51. it 'returns a hash' do
  52. expect(subject).to be_a Hash
  53. end
  54. it 'contains signature' do
  55. expect(subject['signature']).to be_a Hash
  56. expect(subject['signature']['signatureValue']).to be_present
  57. end
  58. it 'can be verified again' do
  59. expect(described_class.new(subject).verify_actor!).to eq sender
  60. end
  61. end
  62. def sign(from_actor, options, document)
  63. options_hash = Digest::SHA256.hexdigest(canonicalize(options.merge('@context' => ActivityPub::LinkedDataSignature::CONTEXT)))
  64. document_hash = Digest::SHA256.hexdigest(canonicalize(document))
  65. to_be_verified = options_hash + document_hash
  66. Base64.strict_encode64(from_actor.keypair.sign(OpenSSL::Digest.new('SHA256'), to_be_verified))
  67. end
  68. end