ip_blocks_spec.rb 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. # frozen_string_literal: true
  2. require 'rails_helper'
  3. RSpec.describe 'IP Blocks' do
  4. let(:role) { UserRole.find_by(name: 'Admin') }
  5. let(:user) { Fabricate(:user, role: role) }
  6. let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
  7. let(:scopes) { 'admin:read:ip_blocks admin:write:ip_blocks' }
  8. let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
  9. describe 'GET /api/v1/admin/ip_blocks' do
  10. subject do
  11. get '/api/v1/admin/ip_blocks', headers: headers, params: params
  12. end
  13. let(:params) { {} }
  14. it_behaves_like 'forbidden for wrong scope', 'admin:write:ip_blocks'
  15. it_behaves_like 'forbidden for wrong role', ''
  16. it_behaves_like 'forbidden for wrong role', 'Moderator'
  17. context 'when there is no ip block' do
  18. it 'returns an empty body' do
  19. subject
  20. expect(response)
  21. .to have_http_status(200)
  22. expect(response.content_type)
  23. .to start_with('application/json')
  24. expect(response.parsed_body)
  25. .to be_empty
  26. end
  27. end
  28. context 'when there are ip blocks' do
  29. let!(:ip_blocks) do
  30. [
  31. IpBlock.create(ip: '192.0.2.0/24', severity: :no_access),
  32. IpBlock.create(ip: '172.16.0.1', severity: :sign_up_requires_approval, comment: 'Spam'),
  33. IpBlock.create(ip: '2001:0db8::/32', severity: :sign_up_block, expires_in: 10.days),
  34. ]
  35. end
  36. let(:expected_response) do
  37. ip_blocks.map do |ip_block|
  38. {
  39. id: ip_block.id.to_s,
  40. ip: ip_block.ip,
  41. severity: ip_block.severity.to_s,
  42. comment: ip_block.comment,
  43. created_at: ip_block.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'),
  44. expires_at: ip_block.expires_at&.strftime('%Y-%m-%dT%H:%M:%S.%LZ'),
  45. }
  46. end
  47. end
  48. it 'returns the correct blocked ips' do
  49. subject
  50. expect(response)
  51. .to have_http_status(200)
  52. expect(response.content_type)
  53. .to start_with('application/json')
  54. expect(response.parsed_body)
  55. .to match_array(expected_response)
  56. end
  57. context 'with limit param' do
  58. let(:params) { { limit: 2 } }
  59. it 'returns only the requested number of ip blocks' do
  60. subject
  61. expect(response.parsed_body.size).to eq(params[:limit])
  62. end
  63. end
  64. end
  65. end
  66. describe 'GET /api/v1/admin/ip_blocks/:id' do
  67. subject do
  68. get "/api/v1/admin/ip_blocks/#{ip_block.id}", headers: headers
  69. end
  70. let!(:ip_block) { IpBlock.create(ip: '192.0.2.0/24', severity: :no_access) }
  71. it_behaves_like 'forbidden for wrong scope', 'admin:write:ip_blocks'
  72. it_behaves_like 'forbidden for wrong role', ''
  73. it_behaves_like 'forbidden for wrong role', 'Moderator'
  74. it 'returns the correct ip block', :aggregate_failures do
  75. subject
  76. expect(response).to have_http_status(200)
  77. expect(response.content_type)
  78. .to start_with('application/json')
  79. expect(response.parsed_body)
  80. .to include(
  81. ip: eq("#{ip_block.ip}/#{ip_block.ip.prefix}"),
  82. severity: eq(ip_block.severity.to_s)
  83. )
  84. end
  85. context 'when ip block does not exist' do
  86. it 'returns http not found' do
  87. get '/api/v1/admin/ip_blocks/-1', headers: headers
  88. expect(response).to have_http_status(404)
  89. expect(response.content_type)
  90. .to start_with('application/json')
  91. end
  92. end
  93. end
  94. describe 'POST /api/v1/admin/ip_blocks' do
  95. subject do
  96. post '/api/v1/admin/ip_blocks', headers: headers, params: params
  97. end
  98. let(:params) { { ip: '151.0.32.55', severity: 'no_access', comment: 'Spam' } }
  99. it_behaves_like 'forbidden for wrong scope', 'admin:read:ip_blocks'
  100. it_behaves_like 'forbidden for wrong role', ''
  101. it_behaves_like 'forbidden for wrong role', 'Moderator'
  102. it 'returns the correct ip block', :aggregate_failures do
  103. subject
  104. expect(response).to have_http_status(200)
  105. expect(response.content_type)
  106. .to start_with('application/json')
  107. expect(response.parsed_body)
  108. .to include(
  109. ip: eq("#{params[:ip]}/32"),
  110. severity: eq(params[:severity]),
  111. comment: eq(params[:comment])
  112. )
  113. end
  114. context 'when the required ip param is not provided' do
  115. let(:params) { { ip: '', severity: 'no_access' } }
  116. it 'returns http unprocessable entity' do
  117. subject
  118. expect(response).to have_http_status(422)
  119. expect(response.content_type)
  120. .to start_with('application/json')
  121. end
  122. end
  123. context 'when the required severity param is not provided' do
  124. let(:params) { { ip: '173.65.23.1', severity: '' } }
  125. it 'returns http unprocessable entity' do
  126. subject
  127. expect(response).to have_http_status(422)
  128. expect(response.content_type)
  129. .to start_with('application/json')
  130. end
  131. end
  132. context 'when the given ip address is already blocked' do
  133. before do
  134. IpBlock.create(params)
  135. end
  136. it 'returns http unprocessable entity' do
  137. subject
  138. expect(response).to have_http_status(422)
  139. expect(response.content_type)
  140. .to start_with('application/json')
  141. end
  142. end
  143. context 'when the given ip address is invalid' do
  144. let(:params) { { ip: '520.13.54.120', severity: 'no_access' } }
  145. it 'returns http unprocessable entity' do
  146. subject
  147. expect(response).to have_http_status(422)
  148. expect(response.content_type)
  149. .to start_with('application/json')
  150. end
  151. end
  152. end
  153. describe 'PUT /api/v1/admin/ip_blocks/:id' do
  154. subject do
  155. put "/api/v1/admin/ip_blocks/#{ip_block.id}", headers: headers, params: params
  156. end
  157. let!(:ip_block) { IpBlock.create(ip: '185.200.13.3', severity: 'no_access', comment: 'Spam', expires_in: 48.hours) }
  158. let(:params) { { severity: 'sign_up_requires_approval', comment: 'Decreasing severity' } }
  159. it 'returns the correct ip block', :aggregate_failures do
  160. expect { subject }
  161. .to change_severity_level
  162. .and change_comment_value
  163. expect(response).to have_http_status(200)
  164. expect(response.content_type)
  165. .to start_with('application/json')
  166. expect(response.parsed_body).to match(hash_including({
  167. ip: "#{ip_block.ip}/#{ip_block.ip.prefix}",
  168. severity: 'sign_up_requires_approval',
  169. comment: 'Decreasing severity',
  170. }))
  171. end
  172. def change_severity_level
  173. change { ip_block.reload.severity }.from('no_access').to('sign_up_requires_approval')
  174. end
  175. def change_comment_value
  176. change { ip_block.reload.comment }.from('Spam').to('Decreasing severity')
  177. end
  178. context 'when ip block does not exist' do
  179. it 'returns http not found' do
  180. put '/api/v1/admin/ip_blocks/-1', headers: headers, params: params
  181. expect(response).to have_http_status(404)
  182. expect(response.content_type)
  183. .to start_with('application/json')
  184. end
  185. end
  186. end
  187. describe 'DELETE /api/v1/admin/ip_blocks/:id' do
  188. subject do
  189. delete "/api/v1/admin/ip_blocks/#{ip_block.id}", headers: headers
  190. end
  191. let!(:ip_block) { IpBlock.create(ip: '185.200.13.3', severity: 'no_access') }
  192. it 'deletes the ip block', :aggregate_failures do
  193. subject
  194. expect(response).to have_http_status(200)
  195. expect(response.content_type)
  196. .to start_with('application/json')
  197. expect(response.parsed_body).to be_empty
  198. expect(IpBlock.find_by(id: ip_block.id)).to be_nil
  199. end
  200. context 'when ip block does not exist' do
  201. it 'returns http not found' do
  202. delete '/api/v1/admin/ip_blocks/-1', headers: headers
  203. expect(response).to have_http_status(404)
  204. expect(response.content_type)
  205. .to start_with('application/json')
  206. end
  207. end
  208. end
  209. end