apps_spec.rb 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. # frozen_string_literal: true
  2. require 'rails_helper'
  3. RSpec.describe 'Apps' do
  4. describe 'POST /api/v1/apps' do
  5. subject do
  6. post '/api/v1/apps', params: params
  7. end
  8. let(:client_name) { 'Test app' }
  9. let(:scopes) { 'read write' }
  10. let(:redirect_uri) { 'urn:ietf:wg:oauth:2.0:oob' }
  11. let(:redirect_uris) { [redirect_uri] }
  12. let(:website) { nil }
  13. let(:params) do
  14. {
  15. client_name: client_name,
  16. redirect_uris: redirect_uris,
  17. scopes: scopes,
  18. website: website,
  19. }
  20. end
  21. context 'with valid params' do
  22. it 'creates an OAuth app', :aggregate_failures do
  23. subject
  24. expect(response).to have_http_status(200)
  25. expect(response.content_type)
  26. .to start_with('application/json')
  27. app = Doorkeeper::Application.find_by(name: client_name)
  28. expect(app).to be_present
  29. expect(app.scopes.to_s).to eq scopes
  30. expect(app.redirect_uris).to eq redirect_uris
  31. expect(response.parsed_body).to match(
  32. a_hash_including(
  33. id: app.id.to_s,
  34. client_id: app.uid,
  35. client_secret: app.secret,
  36. client_secret_expires_at: 0,
  37. name: client_name,
  38. website: website,
  39. scopes: ['read', 'write'],
  40. redirect_uris: redirect_uris,
  41. # Deprecated properties as of 4.3:
  42. redirect_uri: redirect_uri,
  43. vapid_key: Rails.configuration.x.vapid_public_key
  44. )
  45. )
  46. end
  47. end
  48. context 'without scopes being supplied' do
  49. let(:scopes) { nil }
  50. it 'creates an OAuth App with the default scope' do
  51. subject
  52. expect(response).to have_http_status(200)
  53. expect(response.content_type)
  54. .to start_with('application/json')
  55. expect(Doorkeeper::Application.find_by(name: client_name)).to be_present
  56. expect(response.parsed_body)
  57. .to include(
  58. scopes: Doorkeeper.config.default_scopes.to_a
  59. )
  60. end
  61. end
  62. # FIXME: This is a bug: https://github.com/mastodon/mastodon/issues/30152
  63. context 'with scopes as an array' do
  64. let(:scopes) { %w(read write follow) }
  65. it 'creates an OAuth App with the default scope' do
  66. subject
  67. expect(response).to have_http_status(200)
  68. expect(response.content_type)
  69. .to start_with('application/json')
  70. app = Doorkeeper::Application.find_by(name: client_name)
  71. expect(app).to be_present
  72. expect(app.scopes.to_s).to eq 'read'
  73. expect(response.parsed_body)
  74. .to include(
  75. scopes: %w(read)
  76. )
  77. end
  78. end
  79. context 'with an unsupported scope' do
  80. let(:scopes) { 'hoge' }
  81. it 'returns http unprocessable entity' do
  82. subject
  83. expect(response).to have_http_status(422)
  84. expect(response.content_type)
  85. .to start_with('application/json')
  86. end
  87. end
  88. context 'with many duplicate scopes' do
  89. let(:scopes) { (%w(read) * 40).join(' ') }
  90. it 'only saves the scope once', :aggregate_failures do
  91. subject
  92. expect(response).to have_http_status(200)
  93. expect(response.content_type)
  94. .to start_with('application/json')
  95. expect(Doorkeeper::Application.find_by(name: client_name).scopes.to_s).to eq 'read'
  96. end
  97. end
  98. context 'with a too-long name' do
  99. let(:client_name) { 'hoge' * 20 }
  100. it 'returns http unprocessable entity' do
  101. subject
  102. expect(response).to have_http_status(422)
  103. expect(response.content_type)
  104. .to start_with('application/json')
  105. end
  106. end
  107. context 'with a too-long website' do
  108. let(:website) { "https://foo.bar/#{'hoge' * 2_000}" }
  109. it 'returns http unprocessable entity' do
  110. subject
  111. expect(response).to have_http_status(422)
  112. expect(response.content_type)
  113. .to start_with('application/json')
  114. end
  115. end
  116. context 'with a too-long redirect_uri' do
  117. let(:redirect_uris) { "https://app.example/#{'hoge' * 2_000}" }
  118. it 'returns http unprocessable entity' do
  119. subject
  120. expect(response).to have_http_status(422)
  121. expect(response.content_type)
  122. .to start_with('application/json')
  123. end
  124. end
  125. # NOTE: This spec currently tests the same as the "with a too-long redirect_uri test case"
  126. context 'with too many redirect_uris' do
  127. let(:redirect_uris) { (0...500).map { |i| "https://app.example/#{i}/callback" } }
  128. it 'returns http unprocessable entity' do
  129. subject
  130. expect(response).to have_http_status(422)
  131. expect(response.content_type)
  132. .to start_with('application/json')
  133. end
  134. end
  135. context 'with multiple redirect_uris as a string' do
  136. let(:redirect_uris) { "https://redirect1.example/\napp://redirect2.example/" }
  137. it 'creates an OAuth application with multiple redirect URIs' do
  138. subject
  139. expect(response).to have_http_status(200)
  140. expect(response.content_type)
  141. .to start_with('application/json')
  142. app = Doorkeeper::Application.find_by(name: client_name)
  143. expect(app).to be_present
  144. expect(app.redirect_uri).to eq redirect_uris
  145. expect(app.redirect_uris).to eq redirect_uris.split
  146. expect(response.parsed_body)
  147. .to include(
  148. redirect_uri: redirect_uris,
  149. redirect_uris: redirect_uris.split
  150. )
  151. end
  152. end
  153. context 'with multiple redirect_uris as an array' do
  154. let(:redirect_uris) { ['https://redirect1.example/', 'app://redirect2.example/'] }
  155. it 'creates an OAuth application with multiple redirect URIs' do
  156. subject
  157. expect(response).to have_http_status(200)
  158. expect(response.content_type)
  159. .to start_with('application/json')
  160. app = Doorkeeper::Application.find_by(name: client_name)
  161. expect(app).to be_present
  162. expect(app.redirect_uri).to eq redirect_uris.join "\n"
  163. expect(app.redirect_uris).to eq redirect_uris
  164. expect(response.parsed_body)
  165. .to include(
  166. redirect_uri: redirect_uris.join("\n"),
  167. redirect_uris: redirect_uris
  168. )
  169. end
  170. end
  171. context 'with an empty redirect_uris array' do
  172. let(:redirect_uris) { [] }
  173. it 'returns http unprocessable entity' do
  174. subject
  175. expect(response).to have_http_status(422)
  176. expect(response.content_type)
  177. .to start_with('application/json')
  178. end
  179. end
  180. context 'with just a newline as the redirect_uris string' do
  181. let(:redirect_uris) { "\n" }
  182. it 'returns http unprocessable entity' do
  183. subject
  184. expect(response).to have_http_status(422)
  185. expect(response.content_type)
  186. .to start_with('application/json')
  187. end
  188. end
  189. context 'with an empty redirect_uris string' do
  190. let(:redirect_uris) { '' }
  191. it 'returns http unprocessable entity' do
  192. subject
  193. expect(response).to have_http_status(422)
  194. expect(response.content_type)
  195. .to start_with('application/json')
  196. end
  197. end
  198. context 'without a required param' do
  199. let(:client_name) { '' }
  200. it 'returns http unprocessable entity' do
  201. subject
  202. expect(response).to have_http_status(422)
  203. expect(response.content_type)
  204. .to start_with('application/json')
  205. end
  206. end
  207. context 'with a website' do
  208. let(:website) { 'https://app.example/' }
  209. it 'creates an OAuth application with the website specified' do
  210. subject
  211. expect(response).to have_http_status(200)
  212. expect(response.content_type)
  213. .to start_with('application/json')
  214. app = Doorkeeper::Application.find_by(name: client_name)
  215. expect(app).to be_present
  216. expect(app.website).to eq website
  217. end
  218. end
  219. end
  220. end