doorkeeper-mongodb 5.5.0 → 5.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/lib/doorkeeper-mongodb/mixins/mongoid/application_mixin.rb +7 -1
  3. data/lib/doorkeeper-mongodb/mixins/mongoid/base_mixin.rb +8 -0
  4. data/lib/doorkeeper-mongodb/version.rb +1 -1
  5. data/spec/controllers/application_metal_controller_spec.rb +66 -0
  6. data/spec/controllers/applications_controller_spec.rb +270 -0
  7. data/spec/controllers/authorizations_controller_spec.rb +1453 -0
  8. data/spec/controllers/protected_resources_controller_spec.rb +363 -0
  9. data/spec/controllers/token_info_controller_spec.rb +52 -0
  10. data/spec/controllers/tokens_controller_spec.rb +661 -0
  11. data/spec/doorkeeper/redirect_uri_validator_spec.rb +189 -0
  12. data/spec/doorkeeper/server_spec.rb +52 -0
  13. data/spec/doorkeeper/stale_records_cleaner_spec.rb +99 -0
  14. data/spec/doorkeeper/version_spec.rb +17 -0
  15. data/spec/dummy/config/environments/test.rb +4 -1
  16. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +1 -1
  17. data/spec/dummy/db/schema.rb +1 -1
  18. data/spec/dummy/log/test.log +0 -39440
  19. data/spec/factories.rb +30 -0
  20. data/spec/grape/grape_integration_spec.rb +137 -0
  21. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +26 -0
  22. data/spec/lib/config_spec.rb +901 -0
  23. data/spec/lib/doorkeeper_spec.rb +27 -0
  24. data/spec/lib/grant_flow/flow_spec.rb +83 -0
  25. data/spec/lib/grant_flow_spec.rb +81 -0
  26. data/spec/lib/models/concerns/write_to_primary_spec.rb +107 -0
  27. data/spec/lib/models/expirable_spec.rb +61 -0
  28. data/spec/lib/models/reusable_spec.rb +40 -0
  29. data/spec/lib/models/revocable_spec.rb +69 -0
  30. data/spec/lib/models/scopes_spec.rb +61 -0
  31. data/spec/lib/models/secret_storable_spec.rb +136 -0
  32. data/spec/lib/oauth/authorization/code_spec.rb +55 -0
  33. data/spec/lib/oauth/authorization/uri_builder_spec.rb +35 -0
  34. data/spec/lib/oauth/authorization_code_request_spec.rb +315 -0
  35. data/spec/lib/oauth/base_request_spec.rb +214 -0
  36. data/spec/lib/oauth/base_response_spec.rb +45 -0
  37. data/spec/lib/oauth/client/credentials_spec.rb +106 -0
  38. data/spec/lib/oauth/client_credentials/creator_spec.rb +131 -0
  39. data/spec/lib/oauth/client_credentials/issuer_spec.rb +122 -0
  40. data/spec/lib/oauth/client_credentials/validation_spec.rb +92 -0
  41. data/spec/lib/oauth/client_credentials_integration_spec.rb +27 -0
  42. data/spec/lib/oauth/client_credentials_request_spec.rb +120 -0
  43. data/spec/lib/oauth/client_spec.rb +38 -0
  44. data/spec/lib/oauth/code_request_spec.rb +56 -0
  45. data/spec/lib/oauth/code_response_spec.rb +94 -0
  46. data/spec/lib/oauth/error_response_spec.rb +110 -0
  47. data/spec/lib/oauth/error_spec.rb +39 -0
  48. data/spec/lib/oauth/forbidden_token_response_spec.rb +31 -0
  49. data/spec/lib/oauth/helpers/scope_checker_spec.rb +86 -0
  50. data/spec/lib/oauth/helpers/unique_token_spec.rb +21 -0
  51. data/spec/lib/oauth/helpers/uri_checker_spec.rb +274 -0
  52. data/spec/lib/oauth/invalid_request_response_spec.rb +75 -0
  53. data/spec/lib/oauth/invalid_token_response_spec.rb +55 -0
  54. data/spec/lib/oauth/password_access_token_request_spec.rb +221 -0
  55. data/spec/lib/oauth/pre_authorization_spec.rb +442 -0
  56. data/spec/lib/oauth/refresh_token_request_spec.rb +244 -0
  57. data/spec/lib/oauth/scopes_spec.rb +279 -0
  58. data/spec/lib/oauth/token_request_spec.rb +191 -0
  59. data/spec/lib/oauth/token_response_spec.rb +106 -0
  60. data/spec/lib/oauth/token_spec.rb +156 -0
  61. data/spec/lib/option_spec.rb +51 -0
  62. data/spec/lib/request/strategy_spec.rb +51 -0
  63. data/spec/lib/secret_storing/base_spec.rb +62 -0
  64. data/spec/lib/secret_storing/bcrypt_spec.rb +49 -0
  65. data/spec/lib/secret_storing/plain_spec.rb +44 -0
  66. data/spec/lib/secret_storing/sha256_hash_spec.rb +47 -0
  67. data/spec/models/doorkeeper/access_grant_spec.rb +197 -0
  68. data/spec/models/doorkeeper/access_token_spec.rb +830 -0
  69. data/spec/requests/applications/applications_request_spec.rb +257 -0
  70. data/spec/requests/applications/authorized_applications_spec.rb +32 -0
  71. data/spec/requests/endpoints/authorization_spec.rb +97 -0
  72. data/spec/requests/endpoints/token_spec.rb +79 -0
  73. data/spec/requests/flows/authorization_code_errors_spec.rb +86 -0
  74. data/spec/requests/flows/authorization_code_spec.rb +582 -0
  75. data/spec/requests/flows/client_credentials_spec.rb +233 -0
  76. data/spec/requests/flows/implicit_grant_errors_spec.rb +54 -0
  77. data/spec/requests/flows/implicit_grant_spec.rb +91 -0
  78. data/spec/requests/flows/password_spec.rb +415 -0
  79. data/spec/requests/flows/refresh_token_spec.rb +282 -0
  80. data/spec/requests/flows/revoke_token_spec.rb +231 -0
  81. data/spec/requests/flows/skip_authorization_spec.rb +66 -0
  82. data/spec/requests/protected_resources/metal_spec.rb +16 -0
  83. data/spec/requests/protected_resources/private_api_spec.rb +83 -0
  84. data/spec/routing/custom_controller_routes_spec.rb +133 -0
  85. data/spec/routing/default_routes_spec.rb +41 -0
  86. data/spec/routing/scoped_routes_spec.rb +56 -0
  87. data/spec/spec_helper.rb +63 -0
  88. data/spec/spec_helper_integration.rb +4 -0
  89. data/spec/support/dependencies/factory_bot.rb +4 -0
  90. data/spec/support/helpers/access_token_request_helper.rb +14 -0
  91. data/spec/support/helpers/authorization_request_helper.rb +43 -0
  92. data/spec/support/helpers/config_helper.rb +11 -0
  93. data/spec/support/helpers/model_helper.rb +75 -0
  94. data/spec/support/helpers/request_spec_helper.rb +94 -0
  95. data/spec/support/helpers/url_helper.rb +63 -0
  96. data/spec/support/orm/active_record.rb +5 -0
  97. data/spec/support/shared/controllers_shared_context.rb +100 -0
  98. data/spec/support/shared/hashing_shared_context.rb +40 -0
  99. data/spec/support/shared/models_shared_examples.rb +56 -0
  100. metadata +184 -58
  101. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/2L/2LdlR-88TqZc8vSU7Z58xiNpCGRZj0CIlOxSN4Vx2i4.cache +0 -1
  102. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/2r/2r0L9eNOmETsg4Tm1IgBdw3J4ahcko41NpILRXu19_A.cache +0 -1
  103. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/5y/5ywocFQgpSY36nyF_xDKPExhDRo-eqeiqfDvQee1K9k.cache +0 -2
  104. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/8r/8rW0CpDDUJZ7xvg86t6jZ6WmyvaVZ0uTPEPRjghFIKo.cache +0 -2
  105. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Cs/CsfBL8Dls9-jhjFsNYt4DZxu5LWChDMB-xXKjsEFSsU.cache +0 -0
  106. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Cv/Cv9WXE_0OqtPUZBXfTWaE8uKx9oFIzqO18ZkwVaBLSg.cache +0 -1
  107. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Mf/MfB2-0nbsmC548XBSLftafi6BZ9nAquBA-6eu7mAmdE.cache +0 -2
  108. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/N2/N2cUP-Um_nQ5ZTCQr_H0bKIjOSIyV7Ry5sT6-DB9e4A.cache +0 -1
  109. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Ot/OtNAnT3d-csAKBtJ8UBLOSwUDyfmOdCWpS08RaSCGsQ.cache +0 -1
  110. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/P3/P33RwiTMGEu2wZySBEUmf5U7hnfBhdL49wzdUWXYNRs.cache +0 -1
  111. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/RZ/RZAL9gIt4aD731Ikf7UZZNPSZXzhPqtDskLB7nQcWH4.cache +0 -1
  112. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/SQ/SQVJeYO2bM0qgQiOaeVBjYo3SWQZmvixa3tXUjsmuUs.cache +0 -0
  113. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/V2/V2JApVhUSYhvWnNVIbpe58U4xheVkpi0gCStqjDN6-A.cache +0 -1
  114. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/VA/VADOUaZFukufOb44ts4KoyQZumPcVJET0bi9RvC7c-o.cache +0 -3
  115. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Vz/VzdPLfWn16XbpHNJdkDMamAf3QutM29cvvPkDNyy5nE.cache +0 -1
  116. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/W9/W9QfraySVwoRt-SgGOIS0e-iP8R1qP_URwXZw1l6M5E.cache +0 -0
  117. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Wy/Wyiw07ngOzgV6RPis_Lo2hhSRkwo2YSqKTEDAF0crhA.cache +0 -0
  118. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Z6/Z6rAtdVt3OXS26vLVCtdO3vmMlttI3ajdpbC2FHk7iQ.cache +0 -0
  119. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/b6/b6QRH6ZdCc0e6bUWu4qni_kZmptaMgWciO8Jl9q6_p8.cache +0 -2
  120. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/fP/fPihom3hnc1rQQxpviTvZPRJB_IghWYWP3dDcsGrcLk.cache +0 -1
  121. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/gD/gDU38plXvosMgFK47_PBI9xGVsmsE2tShWEZzxiek3k.cache +0 -1
  122. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/gR/gRqL5_jaFW7eA3d2frJmOzw_vFLuvfhwMhotAlsO8J4.cache +0 -2
  123. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/jC/jCTZ1jAldKBn4OTANBBmCKzxLrDgok1ur4meoTqlDNg.cache +0 -3
  124. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/jc/jcB8w1gBT7JP10DW4OOvvYpW1ZFeMyedngmMy3QbRLQ.cache +0 -0
  125. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/jg/jgxXkkkXf1NPOPrpNdEJzhDt-2xHGzd_-mLkIHWrOr4.cache +0 -2
  126. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/nx/nxzZnvk5YyBhTUloQSZZ5zRuaqlsLiHy_AbOzQ3d788.cache +0 -0
  127. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/wr/wrlf8nUW2yftpcIA97qImyECR8f8o3OiOdHLdfkmw8c.cache +0 -1
  128. data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/xd/xdD4KJ55W3jy5PIrwT0UnDp1toKpUfgrjJBgB4WaPIc.cache +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31397e2cb87670cde0c3c5eb8bd487a864e14c11dfcedc868c5fd1e2b4683e87
4
- data.tar.gz: 534a2ce1dd42bc361839b31e96a54491b2142b1366a46590a719ee071b835b36
3
+ metadata.gz: 2831ead15c9f00179162bc0910a5f9a5fea4cd0644c2f81aa201f3d6d2d4363e
4
+ data.tar.gz: 230f38a7299782c778763e3524230b4678cf175a7a5a19e7f65d8caed861a84a
5
5
  SHA512:
6
- metadata.gz: 2debfbe47ca1743bae09ae241245438a56454b4850cf6d833c337fe8e1e79a21e396fbaaafd52ec7eb14c49a7342c573f45d4e2feac4ca8ebdb2cddb285dfadb
7
- data.tar.gz: 5a74a5c8666980b4af1c88427ab692d2aecb049fe918605558223eee48a3b9df1403ab13a3b3448c8645804ec46c67966f0e07e0925bb99ce92fb9ca1cf4830d
6
+ metadata.gz: 7bc1982e16ab6ff9e76116fa67070fd86b4e61bba9e50cce7bdaccb4c2e197f5bcd83ad929f43d8cc7c63f253b0265d3d90b97dd1862a22d06a0e2b5336349d4
7
+ data.tar.gz: e2153799788547fef7eed3982889e3b06f55fad4bfa0af23546b3e9da2f437bd161356e6f3b9604c43650ccc000b271b5a766c88d10183f49a319e73b8c15fba
@@ -36,7 +36,8 @@ module DoorkeeperMongodb
36
36
  has_many :access_grants, has_many_options.merge(class_name: access_grants_class_name)
37
37
  has_many :access_tokens, has_many_options.merge(class_name: access_tokens_class_name)
38
38
 
39
- validates_presence_of :name, :secret, :uid
39
+ validates_presence_of :name, :uid
40
+ validates_presence_of :secret, if: :secret_required?
40
41
  validates_uniqueness_of :uid
41
42
 
42
43
  # Before Doorkeeper 5.2.3
@@ -243,11 +244,16 @@ module DoorkeeperMongodb
243
244
 
244
245
  def generate_secret
245
246
  return if secret.present?
247
+ return unless secret_required?
246
248
 
247
249
  @raw_secret = UniqueToken.generate
248
250
  secret_strategy.store_secret(self, :secret, @raw_secret)
249
251
  end
250
252
 
253
+ def secret_required?
254
+ confidential?
255
+ end
256
+
251
257
  def scopes_match_configured
252
258
  if scopes.present? &&
253
259
  !ScopeChecker.valid?(scope_str: scopes.to_s,
@@ -7,6 +7,14 @@ module DoorkeeperMongodb
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  module ClassMethods
10
+ # No-op for Mongoid. Doorkeeper 5.9+ uses with_primary_role to
11
+ # ensure writes go to the primary database when ActiveRecord read
12
+ # replicas are configured. Mongoid doesn't have this concept, so
13
+ # we simply yield.
14
+ def with_primary_role
15
+ yield
16
+ end
17
+
10
18
  def ordered_by(attribute, direction = :asc)
11
19
  order_by(attribute => direction.to_sym)
12
20
  end
@@ -9,7 +9,7 @@ module DoorkeeperMongodb
9
9
  # Semver
10
10
  MAJOR = 5
11
11
  MINOR = 5
12
- TINY = 0
12
+ TINY = 1
13
13
 
14
14
  # Full version number
15
15
  STRING = [MAJOR, MINOR, TINY].compact.join(".")
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper_integration"
4
+
5
+ RSpec.describe Doorkeeper::ApplicationMetalController, type: :controller do
6
+ render_views
7
+
8
+ controller(described_class) do
9
+ def index
10
+ render json: {}, status: 200
11
+ end
12
+
13
+ def create
14
+ render json: {}, status: 200
15
+ end
16
+ end
17
+
18
+ it "lazy run hooks" do
19
+ i = 0
20
+ ActiveSupport.on_load(:doorkeeper_metal_controller) { i += 1 }
21
+
22
+ expect(i).to eq 1
23
+ end
24
+
25
+ describe "enforce_content_type" do
26
+ before { allow(Doorkeeper.config).to receive(:enforce_content_type).and_return(flag) }
27
+
28
+ context "when enabled" do
29
+ let(:flag) { true }
30
+
31
+ it "returns a 200 for the requests without body" do
32
+ get :index, params: {}
33
+ expect(response).to have_http_status 200
34
+ end
35
+
36
+ it "returns a 200 for the requests with body and correct media type" do
37
+ post :create, params: {}, as: :url_encoded_form
38
+ expect(response).to have_http_status 200
39
+ end
40
+
41
+ it "returns a 415 for the requests with body and incorrect media type" do
42
+ post :create, params: {}, as: :json
43
+ expect(response).to have_http_status 415
44
+ end
45
+ end
46
+
47
+ context "when disabled" do
48
+ let(:flag) { false }
49
+
50
+ it "returns a 200 for the correct media type" do
51
+ get :index, as: :url_encoded_form
52
+ expect(response).to have_http_status 200
53
+ end
54
+
55
+ it "returns a 200 for an incorrect media type" do
56
+ get :index, as: :json
57
+ expect(response).to have_http_status 200
58
+ end
59
+
60
+ it "returns a 200 for the requests with body and incorrect media type" do
61
+ post :create, params: {}, as: :json
62
+ expect(response).to have_http_status 200
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,270 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Doorkeeper::ApplicationsController, type: :controller do
6
+ render_views
7
+
8
+ context "when JSON API used" do
9
+ before do
10
+ allow(Doorkeeper.configuration).to receive(:api_only).and_return(true)
11
+ allow(Doorkeeper.configuration).to receive(:authenticate_admin).and_return(->(*) { true })
12
+ end
13
+
14
+ it "creates an application" do
15
+ expect do
16
+ post :create, params: {
17
+ doorkeeper_application: {
18
+ name: "Example",
19
+ redirect_uri: "https://example.com",
20
+ }, format: :json,
21
+ }
22
+ end.to(change { Doorkeeper::Application.count })
23
+
24
+ expect(response).to be_successful
25
+
26
+ expect(json_response).to include("id", "name", "uid", "secret", "redirect_uri", "scopes")
27
+
28
+ application = Doorkeeper::Application.last
29
+ secret_from_response = json_response["secret"]
30
+ expect(application).to be_secret_matches(secret_from_response)
31
+
32
+ expect(json_response["name"]).to eq("Example")
33
+ expect(json_response["redirect_uri"]).to eq("https://example.com")
34
+ end
35
+
36
+ it "returns validation errors on wrong create params" do
37
+ expect do
38
+ post :create, params: {
39
+ doorkeeper_application: {
40
+ name: "Example",
41
+ }, format: :json,
42
+ }
43
+ end.not_to(change { Doorkeeper::Application.count })
44
+
45
+ expect(response).to have_http_status(422)
46
+
47
+ expect(json_response).to include("errors")
48
+ end
49
+
50
+ it "returns validations on wrong create params (unspecified scheme)" do
51
+ expect do
52
+ post :create, params: {
53
+ doorkeeper_application: {
54
+ name: "Example",
55
+ redirect_uri: "app.com:80",
56
+ }, format: :json,
57
+ }
58
+ end.not_to(change { Doorkeeper::Application.count })
59
+
60
+ expect(response).to have_http_status(422)
61
+
62
+ expect(json_response).to include("errors")
63
+ end
64
+
65
+ it "returns application info" do
66
+ application = FactoryBot.create(:application, name: "Change me")
67
+
68
+ get :show, params: { id: application.id, format: :json }
69
+
70
+ expect(response).to be_successful
71
+
72
+ expect(json_response).to include("id", "name", "uid", "secret", "redirect_uri", "scopes")
73
+ end
74
+
75
+ it "updates application" do
76
+ application = FactoryBot.create(:application, name: "Change me")
77
+
78
+ put :update, params: {
79
+ id: application.id,
80
+ doorkeeper_application: {
81
+ name: "Example App",
82
+ redirect_uri: "https://example.com",
83
+ }, format: :json,
84
+ }
85
+
86
+ expect(application.reload.name).to eq "Example App"
87
+
88
+ expect(json_response).to include("id", "name", "uid", "secret", "redirect_uri", "scopes")
89
+ end
90
+
91
+ it "returns validation errors on wrong update params" do
92
+ application = FactoryBot.create(:application, name: "Change me")
93
+
94
+ put :update, params: {
95
+ id: application.id,
96
+ doorkeeper_application: {
97
+ name: "Example App",
98
+ redirect_uri: "localhost:3000",
99
+ }, format: :json,
100
+ }
101
+
102
+ expect(response).to have_http_status(422)
103
+
104
+ expect(json_response).to include("errors")
105
+ end
106
+
107
+ it "destroys an application" do
108
+ application = FactoryBot.create(:application)
109
+
110
+ delete :destroy, params: { id: application.id, format: :json }
111
+
112
+ expect(response).to have_http_status(204)
113
+ expect(Doorkeeper::Application.count).to be_zero
114
+ end
115
+ end
116
+
117
+ context "when admin is not authenticated" do
118
+ before do
119
+ allow(Doorkeeper.config).to receive(:authenticate_admin).and_return(proc do
120
+ redirect_to main_app.root_url
121
+ end)
122
+ end
123
+
124
+ it "redirects as set in Doorkeeper.authenticate_admin" do
125
+ get :index
126
+ expect(response).to redirect_to(controller.main_app.root_url)
127
+ end
128
+
129
+ it "does not create application" do
130
+ expect do
131
+ post :create, params: {
132
+ doorkeeper_application: {
133
+ name: "Example",
134
+ redirect_uri: "https://example.com",
135
+ },
136
+ }
137
+ end.not_to(change { Doorkeeper::Application.count })
138
+ end
139
+ end
140
+
141
+ context "when admin is authenticated" do
142
+ before do
143
+ allow(Doorkeeper.configuration).to receive(:authenticate_admin).and_return(->(*) { true })
144
+ end
145
+
146
+ context "when application secrets are hashed" do
147
+ before do
148
+ allow(Doorkeeper.configuration)
149
+ .to receive(:application_secret_strategy).and_return(Doorkeeper::SecretStoring::Sha256Hash)
150
+ end
151
+
152
+ it "shows the application secret after creating a new application" do
153
+ expect do
154
+ post :create, params: {
155
+ doorkeeper_application: {
156
+ name: "Example",
157
+ redirect_uri: "https://example.com",
158
+ },
159
+ }
160
+ end.to change { Doorkeeper::Application.count }.by(1)
161
+
162
+ application = Doorkeeper::Application.last
163
+
164
+ secret_from_flash = flash[:application_secret]
165
+ expect(secret_from_flash).not_to be_empty
166
+ expect(application).to be_secret_matches(secret_from_flash)
167
+ expect(response).to redirect_to(controller.main_app.oauth_application_url(application.id))
168
+
169
+ get :show, params: { id: application.id, format: :html }
170
+
171
+ # We don't know the application secret here (because its hashed) so we can not assert its text on the page
172
+ # Instead, we read it from the page and then check if it matches the application secret
173
+ code_element = /code.*id="secret">\s*\K([^<]*)/m.match(response.body)
174
+ secret_from_page = code_element[1].strip
175
+
176
+ expect(response.body).to have_selector("code#application_id", text: application.uid)
177
+ expect(response.body).to have_selector("code#secret")
178
+ expect(secret_from_page).not_to be_empty
179
+ expect(application).to be_secret_matches(secret_from_page)
180
+ end
181
+
182
+ it "does not show an application secret when application did already exist" do
183
+ application = FactoryBot.create(:application)
184
+ get :show, params: { id: application.id, format: :html }
185
+
186
+ expect(response.body).to have_selector("code#application_id", text: application.uid)
187
+ expect(response.body).to have_selector("code#secret", text: "")
188
+ end
189
+
190
+ it "returns the application details in a json response" do
191
+ expect do
192
+ post :create, params: {
193
+ doorkeeper_application: {
194
+ name: "Example",
195
+ redirect_uri: "https://example.com",
196
+ }, format: :json,
197
+ }
198
+ end.to(change { Doorkeeper::Application.count })
199
+
200
+ expect(response).to be_successful
201
+
202
+ expect(json_response).to include("id", "name", "uid", "secret", "redirect_uri", "scopes")
203
+
204
+ application = Doorkeeper::Application.last
205
+ secret_from_response = json_response["secret"]
206
+ expect(application).to be_secret_matches(secret_from_response)
207
+
208
+ expect(json_response["name"]).to eq("Example")
209
+ expect(json_response["redirect_uri"]).to eq("https://example.com")
210
+ end
211
+ end
212
+
213
+ it "sorts applications by created_at" do
214
+ first_application = FactoryBot.create(:application)
215
+ second_application = FactoryBot.create(:application)
216
+ expect(Doorkeeper::Application).to receive(:ordered_by).and_call_original
217
+
218
+ get :index
219
+
220
+ expect(response.body).to have_selector("tbody tr:first-child#application_#{first_application.id}")
221
+ expect(response.body).to have_selector("tbody tr:last-child#application_#{second_application.id}")
222
+ end
223
+
224
+ it "creates application" do
225
+ expect do
226
+ post :create, params: {
227
+ doorkeeper_application: {
228
+ name: "Example",
229
+ redirect_uri: "https://example.com",
230
+ },
231
+ }
232
+ end.to change { Doorkeeper::Application.count }.by(1)
233
+
234
+ expect(response).to be_redirect
235
+ end
236
+
237
+ it "shows application details" do
238
+ application = FactoryBot.create(:application)
239
+ get :show, params: { id: application.id, format: :html }
240
+
241
+ expect(response.body).to have_selector("code#application_id", text: application.uid)
242
+ expect(response.body).to have_selector("code#secret", text: application.plaintext_secret)
243
+ end
244
+
245
+ it "does not allow mass assignment of uid or secret" do
246
+ application = FactoryBot.create(:application)
247
+ put :update, params: {
248
+ id: application.id,
249
+ doorkeeper_application: {
250
+ uid: "1A2B3C4D",
251
+ secret: "1A2B3C4D",
252
+ },
253
+ }
254
+
255
+ expect(application.reload.uid).not_to eq "1A2B3C4D"
256
+ end
257
+
258
+ it "updates application" do
259
+ application = FactoryBot.create(:application)
260
+ put :update, params: {
261
+ id: application.id, doorkeeper_application: {
262
+ name: "Example",
263
+ redirect_uri: "https://example.com",
264
+ },
265
+ }
266
+
267
+ expect(application.reload.name).to eq "Example"
268
+ end
269
+ end
270
+ end