signature_verification_spec.rb 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. # frozen_string_literal: true
  2. require 'rails_helper'
  3. describe ApplicationController, type: :controller do
  4. class WrappedActor
  5. attr_reader :wrapped_account
  6. def initialize(wrapped_account)
  7. @wrapped_account = wrapped_account
  8. end
  9. delegate :uri, :keypair, to: :wrapped_account
  10. end
  11. controller do
  12. include SignatureVerification
  13. def success
  14. head 200
  15. end
  16. def alternative_success
  17. head 200
  18. end
  19. end
  20. before do
  21. routes.draw { match via: [:get, :post], 'success' => 'anonymous#success' }
  22. end
  23. context 'without signature header' do
  24. before do
  25. get :success
  26. end
  27. describe '#signed_request?' do
  28. it 'returns false' do
  29. expect(controller.signed_request?).to be false
  30. end
  31. end
  32. describe '#signed_request_account' do
  33. it 'returns nil' do
  34. expect(controller.signed_request_account).to be_nil
  35. end
  36. end
  37. end
  38. context 'with signature header' do
  39. let!(:author) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
  40. context 'without body' do
  41. before do
  42. get :success
  43. fake_request = Request.new(:get, request.url)
  44. fake_request.on_behalf_of(author)
  45. request.headers.merge!(fake_request.headers)
  46. end
  47. describe '#signed_request?' do
  48. it 'returns true' do
  49. expect(controller.signed_request?).to be true
  50. end
  51. end
  52. describe '#signed_request_account' do
  53. it 'returns an account' do
  54. expect(controller.signed_request_account).to eq author
  55. end
  56. it 'returns nil when path does not match' do
  57. request.path = '/alternative-path'
  58. expect(controller.signed_request_account).to be_nil
  59. end
  60. it 'returns nil when method does not match' do
  61. post :success
  62. expect(controller.signed_request_account).to be_nil
  63. end
  64. end
  65. end
  66. context 'with a valid actor that is not an Account' do
  67. let(:actor) { WrappedActor.new(author) }
  68. before do
  69. get :success
  70. fake_request = Request.new(:get, request.url)
  71. fake_request.on_behalf_of(author)
  72. request.headers.merge!(fake_request.headers)
  73. allow(ActivityPub::TagManager.instance).to receive(:uri_to_actor).with(anything) do
  74. actor
  75. end
  76. end
  77. describe '#signed_request?' do
  78. it 'returns true' do
  79. expect(controller.signed_request?).to be true
  80. end
  81. end
  82. describe '#signed_request_account' do
  83. it 'returns nil' do
  84. expect(controller.signed_request_account).to be_nil
  85. end
  86. end
  87. describe '#signed_request_actor' do
  88. it 'returns the expected actor' do
  89. expect(controller.signed_request_actor).to eq actor
  90. end
  91. end
  92. end
  93. context 'with request older than a day' do
  94. before do
  95. get :success
  96. fake_request = Request.new(:get, request.url)
  97. fake_request.add_headers({ 'Date' => 2.days.ago.utc.httpdate })
  98. fake_request.on_behalf_of(author)
  99. request.headers.merge!(fake_request.headers)
  100. end
  101. describe '#signed_request?' do
  102. it 'returns true' do
  103. expect(controller.signed_request?).to be true
  104. end
  105. end
  106. describe '#signed_request_account' do
  107. it 'returns nil' do
  108. expect(controller.signed_request_account).to be_nil
  109. end
  110. end
  111. end
  112. context 'with inaccessible key' do
  113. before do
  114. get :success
  115. author = Fabricate(:account, domain: 'localhost:5000', uri: 'http://localhost:5000/actor')
  116. fake_request = Request.new(:get, request.url)
  117. fake_request.on_behalf_of(author)
  118. author.destroy
  119. request.headers.merge!(fake_request.headers)
  120. stub_request(:get, 'http://localhost:5000/actor#main-key').to_raise(Mastodon::HostValidationError)
  121. end
  122. describe '#signed_request?' do
  123. it 'returns true' do
  124. expect(controller.signed_request?).to be true
  125. end
  126. end
  127. describe '#signed_request_account' do
  128. it 'returns nil' do
  129. expect(controller.signed_request_account).to be_nil
  130. end
  131. end
  132. end
  133. context 'with body' do
  134. before do
  135. post :success, body: 'Hello world'
  136. fake_request = Request.new(:post, request.url, body: 'Hello world')
  137. fake_request.on_behalf_of(author)
  138. request.headers.merge!(fake_request.headers)
  139. end
  140. describe '#signed_request?' do
  141. it 'returns true' do
  142. expect(controller.signed_request?).to be true
  143. end
  144. end
  145. describe '#signed_request_account' do
  146. it 'returns an account' do
  147. expect(controller.signed_request_account).to eq author
  148. end
  149. it 'returns nil when path does not match' do
  150. request.path = '/alternative-path'
  151. expect(controller.signed_request_account).to be_nil
  152. end
  153. it 'returns nil when method does not match' do
  154. get :success
  155. expect(controller.signed_request_account).to be_nil
  156. end
  157. it 'returns nil when body has been tampered' do
  158. post :success, body: 'doo doo doo'
  159. expect(controller.signed_request_account).to be_nil
  160. end
  161. end
  162. end
  163. end
  164. end