doorkeeper 5.2.6 → 5.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of doorkeeper might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Appraisals +2 -2
- data/CHANGELOG.md +15 -14
- data/Gemfile +2 -2
- data/app/controllers/doorkeeper/application_controller.rb +2 -2
- data/app/controllers/doorkeeper/application_metal_controller.rb +2 -2
- data/app/controllers/doorkeeper/applications_controller.rb +3 -3
- data/app/controllers/doorkeeper/authorizations_controller.rb +2 -2
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +3 -3
- data/gemfiles/rails_5_0.gemfile +2 -2
- data/gemfiles/rails_5_1.gemfile +2 -2
- data/gemfiles/rails_5_2.gemfile +2 -2
- data/gemfiles/rails_6_0.gemfile +2 -2
- data/gemfiles/rails_master.gemfile +2 -2
- data/lib/doorkeeper.rb +2 -3
- data/lib/doorkeeper/config.rb +71 -39
- data/lib/doorkeeper/grape/helpers.rb +1 -1
- data/lib/doorkeeper/helpers/controller.rb +10 -8
- data/lib/doorkeeper/models/access_grant_mixin.rb +7 -6
- data/lib/doorkeeper/models/access_token_mixin.rb +55 -18
- data/lib/doorkeeper/models/application_mixin.rb +3 -3
- data/lib/doorkeeper/models/concerns/ownership.rb +1 -1
- data/lib/doorkeeper/models/concerns/reusable.rb +1 -1
- data/lib/doorkeeper/models/concerns/revocable.rb +0 -27
- data/lib/doorkeeper/oauth/authorization/code.rb +4 -4
- data/lib/doorkeeper/oauth/authorization/token.rb +9 -6
- data/lib/doorkeeper/oauth/authorization_code_request.rb +13 -6
- data/lib/doorkeeper/oauth/base_request.rb +8 -4
- data/lib/doorkeeper/oauth/client.rb +7 -8
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +16 -9
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +7 -7
- data/lib/doorkeeper/oauth/client_credentials/{validation.rb → validator.rb} +4 -4
- data/lib/doorkeeper/oauth/client_credentials_request.rb +1 -1
- data/lib/doorkeeper/oauth/code_response.rb +2 -2
- data/lib/doorkeeper/oauth/error.rb +1 -1
- data/lib/doorkeeper/oauth/error_response.rb +5 -5
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +7 -5
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +8 -5
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +1 -1
- data/lib/doorkeeper/oauth/invalid_request_response.rb +3 -3
- data/lib/doorkeeper/oauth/invalid_token_response.rb +5 -2
- data/lib/doorkeeper/oauth/password_access_token_request.rb +3 -3
- data/lib/doorkeeper/oauth/pre_authorization.rb +7 -5
- data/lib/doorkeeper/oauth/refresh_token_request.rb +5 -5
- data/lib/doorkeeper/oauth/token.rb +2 -2
- data/lib/doorkeeper/oauth/token_introspection.rb +6 -6
- data/lib/doorkeeper/orm/active_record.rb +3 -3
- data/lib/doorkeeper/orm/active_record/access_grant.rb +4 -43
- data/lib/doorkeeper/orm/active_record/access_token.rb +4 -35
- data/lib/doorkeeper/orm/active_record/application.rb +3 -155
- data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +53 -0
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +47 -0
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +128 -0
- data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +3 -3
- data/lib/doorkeeper/rails/helpers.rb +4 -4
- data/lib/doorkeeper/rails/routes.rb +5 -7
- data/lib/doorkeeper/rake/db.rake +3 -3
- data/lib/doorkeeper/request.rb +1 -1
- data/lib/doorkeeper/request/authorization_code.rb +3 -3
- data/lib/doorkeeper/request/client_credentials.rb +2 -2
- data/lib/doorkeeper/request/password.rb +2 -2
- data/lib/doorkeeper/request/refresh_token.rb +3 -3
- data/lib/doorkeeper/server.rb +1 -1
- data/lib/doorkeeper/stale_records_cleaner.rb +1 -1
- data/lib/doorkeeper/version.rb +2 -2
- data/lib/generators/doorkeeper/application_owner_generator.rb +1 -1
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +1 -1
- data/lib/generators/doorkeeper/migration_generator.rb +1 -1
- data/lib/generators/doorkeeper/pkce_generator.rb +1 -1
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +2 -2
- data/lib/generators/doorkeeper/templates/initializer.rb +39 -8
- data/spec/controllers/application_metal_controller_spec.rb +1 -1
- data/spec/controllers/applications_controller_spec.rb +3 -2
- data/spec/controllers/authorizations_controller_spec.rb +18 -18
- data/spec/controllers/protected_resources_controller_spec.rb +25 -17
- data/spec/controllers/token_info_controller_spec.rb +1 -1
- data/spec/controllers/tokens_controller_spec.rb +1 -1
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +3 -3
- data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +1 -1
- data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +1 -1
- data/spec/generators/install_generator_spec.rb +1 -1
- data/spec/generators/previous_refresh_token_generator_spec.rb +2 -2
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
- data/spec/lib/config_spec.rb +61 -21
- data/spec/lib/doorkeeper_spec.rb +1 -1
- data/spec/lib/models/revocable_spec.rb +3 -3
- data/spec/lib/oauth/authorization_code_request_spec.rb +127 -125
- data/spec/lib/oauth/base_request_spec.rb +160 -158
- data/spec/lib/oauth/base_response_spec.rb +27 -29
- data/spec/lib/oauth/client/credentials_spec.rb +1 -1
- data/spec/lib/oauth/client_credentials/creator_spec.rb +42 -5
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +12 -12
- data/spec/lib/oauth/client_credentials/validation_spec.rb +4 -4
- data/spec/lib/oauth/client_credentials_integration_spec.rb +16 -18
- data/spec/lib/oauth/client_credentials_request_spec.rb +78 -80
- data/spec/lib/oauth/client_spec.rb +26 -26
- data/spec/lib/oauth/code_request_spec.rb +34 -34
- data/spec/lib/oauth/code_response_spec.rb +21 -25
- data/spec/lib/oauth/error_response_spec.rb +42 -44
- data/spec/lib/oauth/error_spec.rb +12 -14
- data/spec/lib/oauth/forbidden_token_response_spec.rb +11 -13
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +30 -18
- data/spec/lib/oauth/invalid_request_response_spec.rb +48 -50
- data/spec/lib/oauth/invalid_token_response_spec.rb +32 -34
- data/spec/lib/oauth/password_access_token_request_spec.rb +145 -147
- data/spec/lib/oauth/pre_authorization_spec.rb +159 -161
- data/spec/lib/oauth/refresh_token_request_spec.rb +138 -139
- data/spec/lib/oauth/scopes_spec.rb +104 -106
- data/spec/lib/oauth/token_request_spec.rb +115 -111
- data/spec/lib/oauth/token_response_spec.rb +71 -73
- data/spec/lib/oauth/token_spec.rb +121 -123
- data/spec/models/doorkeeper/access_grant_spec.rb +3 -5
- data/spec/models/doorkeeper/access_token_spec.rb +7 -7
- data/spec/models/doorkeeper/application_spec.rb +295 -373
- data/spec/requests/applications/applications_request_spec.rb +1 -1
- data/spec/requests/endpoints/authorization_spec.rb +5 -3
- data/spec/requests/flows/authorization_code_spec.rb +34 -22
- data/spec/requests/flows/client_credentials_spec.rb +1 -1
- data/spec/requests/flows/password_spec.rb +32 -12
- data/spec/requests/flows/refresh_token_spec.rb +19 -19
- data/spec/requests/flows/revoke_token_spec.rb +18 -12
- data/spec/spec_helper.rb +1 -4
- data/spec/support/shared/controllers_shared_context.rb +33 -23
- data/spec/validators/redirect_uri_validator_spec.rb +1 -1
- metadata +6 -5
- data/spec/support/http_method_shim.rb +0 -29
@@ -2,177 +2,176 @@
|
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
5
|
+
describe Doorkeeper::OAuth::RefreshTokenRequest do
|
6
|
+
let(:server) do
|
7
|
+
double :server,
|
8
|
+
access_token_expires_in: 2.minutes
|
9
|
+
end
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
let(:refresh_token) do
|
12
|
+
FactoryBot.create(:access_token, use_refresh_token: true)
|
13
|
+
end
|
15
14
|
|
16
|
-
|
17
|
-
|
15
|
+
let(:client) { refresh_token.application }
|
16
|
+
let(:credentials) { Doorkeeper::OAuth::Client::Credentials.new(client.uid, client.secret) }
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
before do
|
19
|
+
allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
|
20
|
+
allow(server).to receive(:option_defined?).with(:custom_access_token_expires_in).and_return(false)
|
21
|
+
end
|
23
22
|
|
24
|
-
|
23
|
+
subject { described_class.new server, refresh_token, credentials }
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
it "issues a new token for the client" do
|
26
|
+
expect { subject.authorize }.to change { client.reload.access_tokens.count }.by(1)
|
27
|
+
# #sort_by used for MongoDB ORM extensions for valid ordering
|
28
|
+
expect(client.reload.access_tokens.max_by(&:created_at).expires_in).to eq(120)
|
29
|
+
end
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
31
|
+
it "issues a new token for the client with custom expires_in" do
|
32
|
+
server = double :server,
|
33
|
+
access_token_expires_in: 2.minutes,
|
34
|
+
custom_access_token_expires_in: lambda { |context|
|
35
|
+
context.grant_type == Doorkeeper::OAuth::REFRESH_TOKEN ? 1234 : nil
|
36
|
+
}
|
38
37
|
|
39
|
-
|
40
|
-
|
38
|
+
allow(server).to receive(:option_defined?).with(:custom_access_token_expires_in).and_return(true)
|
39
|
+
allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
|
41
40
|
|
42
|
-
|
41
|
+
described_class.new(server, refresh_token, credentials).authorize
|
43
42
|
|
44
|
-
|
45
|
-
|
46
|
-
|
43
|
+
# #sort_by used for MongoDB ORM extensions for valid ordering
|
44
|
+
expect(client.reload.access_tokens.max_by(&:created_at).expires_in).to eq(1234)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "revokes the previous token" do
|
48
|
+
expect { subject.authorize }.to change { refresh_token.revoked? }.from(false).to(true)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "calls configured request callback methods" do
|
52
|
+
expect(Doorkeeper.configuration.before_successful_strategy_response)
|
53
|
+
.to receive(:call).with(subject).once
|
54
|
+
|
55
|
+
expect(Doorkeeper.configuration.after_successful_strategy_response)
|
56
|
+
.to receive(:call).with(subject, instance_of(Doorkeeper::OAuth::TokenResponse)).once
|
57
|
+
|
58
|
+
subject.authorize
|
59
|
+
end
|
60
|
+
|
61
|
+
it "requires the refresh token" do
|
62
|
+
subject.refresh_token = nil
|
63
|
+
subject.validate
|
64
|
+
expect(subject.error).to eq(:invalid_request)
|
65
|
+
expect(subject.missing_param).to eq(:refresh_token)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "requires credentials to be valid if provided" do
|
69
|
+
subject.client = nil
|
70
|
+
subject.validate
|
71
|
+
expect(subject.error).to eq(:invalid_client)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "requires the token's client and current client to match" do
|
75
|
+
subject.client = FactoryBot.create(:application)
|
76
|
+
subject.validate
|
77
|
+
expect(subject.error).to eq(:invalid_grant)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "rejects revoked tokens" do
|
81
|
+
refresh_token.revoke
|
82
|
+
subject.validate
|
83
|
+
expect(subject.error).to eq(:invalid_grant)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "accepts expired tokens" do
|
87
|
+
refresh_token.expires_in = -1
|
88
|
+
refresh_token.save
|
89
|
+
subject.validate
|
90
|
+
expect(subject).to be_valid
|
91
|
+
end
|
47
92
|
|
48
|
-
|
49
|
-
|
93
|
+
context "refresh tokens expire on access token use" do
|
94
|
+
let(:server) do
|
95
|
+
double :server,
|
96
|
+
access_token_expires_in: 2.minutes,
|
97
|
+
custom_access_token_expires_in: lambda { |context|
|
98
|
+
context.grant_type == Doorkeeper::OAuth::REFRESH_TOKEN ? 1234 : nil
|
99
|
+
}
|
50
100
|
end
|
51
101
|
|
52
|
-
|
53
|
-
|
54
|
-
|
102
|
+
before do
|
103
|
+
allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(true)
|
104
|
+
end
|
55
105
|
|
56
|
-
|
57
|
-
|
106
|
+
it "issues a new token for the client" do
|
107
|
+
expect { subject.authorize }.to change { client.reload.access_tokens.count }.by(1)
|
108
|
+
end
|
58
109
|
|
110
|
+
it "does not revoke the previous token" do
|
59
111
|
subject.authorize
|
112
|
+
expect(refresh_token).not_to be_revoked
|
60
113
|
end
|
61
114
|
|
62
|
-
it "
|
63
|
-
subject.
|
64
|
-
|
65
|
-
|
66
|
-
|
115
|
+
it "sets the previous refresh token in the new access token" do
|
116
|
+
subject.authorize
|
117
|
+
expect(
|
118
|
+
# #sort_by used for MongoDB ORM extensions for valid ordering
|
119
|
+
client.access_tokens.max_by(&:created_at).previous_refresh_token,
|
120
|
+
).to eq(refresh_token.refresh_token)
|
67
121
|
end
|
122
|
+
end
|
68
123
|
|
69
|
-
|
70
|
-
|
71
|
-
subject.validate
|
72
|
-
expect(subject.error).to eq(:invalid_client)
|
73
|
-
end
|
124
|
+
context "clientless access tokens" do
|
125
|
+
let!(:refresh_token) { FactoryBot.create(:clientless_access_token, use_refresh_token: true) }
|
74
126
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
expect
|
127
|
+
subject { described_class.new server, refresh_token, nil }
|
128
|
+
|
129
|
+
it "issues a new token without a client" do
|
130
|
+
expect { subject.authorize }.to change { Doorkeeper::AccessToken.count }.by(1)
|
79
131
|
end
|
132
|
+
end
|
80
133
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
134
|
+
context "with scopes" do
|
135
|
+
let(:refresh_token) do
|
136
|
+
FactoryBot.create :access_token,
|
137
|
+
use_refresh_token: true,
|
138
|
+
scopes: "public write"
|
85
139
|
end
|
140
|
+
let(:parameters) { {} }
|
86
141
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
subject.
|
91
|
-
expect(
|
142
|
+
subject { described_class.new server, refresh_token, credentials, parameters }
|
143
|
+
|
144
|
+
it "transfers scopes from the old token to the new token" do
|
145
|
+
subject.authorize
|
146
|
+
expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public write])
|
92
147
|
end
|
93
148
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
custom_access_token_expires_in: lambda { |context|
|
99
|
-
context.grant_type == Doorkeeper::OAuth::REFRESH_TOKEN ? 1234 : nil
|
100
|
-
}
|
101
|
-
end
|
102
|
-
|
103
|
-
before do
|
104
|
-
allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(true)
|
105
|
-
end
|
106
|
-
|
107
|
-
it "issues a new token for the client" do
|
108
|
-
expect { subject.authorize }.to change { client.reload.access_tokens.count }.by(1)
|
109
|
-
end
|
110
|
-
|
111
|
-
it "does not revoke the previous token" do
|
112
|
-
subject.authorize
|
113
|
-
expect(refresh_token).not_to be_revoked
|
114
|
-
end
|
115
|
-
|
116
|
-
it "sets the previous refresh token in the new access token" do
|
117
|
-
subject.authorize
|
118
|
-
expect(
|
119
|
-
# #sort_by used for MongoDB ORM extensions for valid ordering
|
120
|
-
client.access_tokens.max_by(&:created_at).previous_refresh_token
|
121
|
-
).to eq(refresh_token.refresh_token)
|
122
|
-
end
|
149
|
+
it "reduces scopes to the provided scopes" do
|
150
|
+
parameters[:scopes] = "public"
|
151
|
+
subject.authorize
|
152
|
+
expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public])
|
123
153
|
end
|
124
154
|
|
125
|
-
|
126
|
-
|
155
|
+
it "validates that scopes are included in the original access token" do
|
156
|
+
parameters[:scopes] = "public update"
|
127
157
|
|
128
|
-
subject
|
158
|
+
subject.validate
|
159
|
+
expect(subject.error).to eq(:invalid_scope)
|
160
|
+
end
|
129
161
|
|
130
|
-
|
131
|
-
|
132
|
-
|
162
|
+
it "uses params[:scope] in favor of scopes if present (valid)" do
|
163
|
+
parameters[:scopes] = "public update"
|
164
|
+
parameters[:scope] = "public"
|
165
|
+
subject.authorize
|
166
|
+
expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public])
|
133
167
|
end
|
134
168
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
let(:parameters) { {} }
|
142
|
-
subject { RefreshTokenRequest.new server, refresh_token, credentials, parameters }
|
143
|
-
|
144
|
-
it "transfers scopes from the old token to the new token" do
|
145
|
-
subject.authorize
|
146
|
-
expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public write])
|
147
|
-
end
|
148
|
-
|
149
|
-
it "reduces scopes to the provided scopes" do
|
150
|
-
parameters[:scopes] = "public"
|
151
|
-
subject.authorize
|
152
|
-
expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public])
|
153
|
-
end
|
154
|
-
|
155
|
-
it "validates that scopes are included in the original access token" do
|
156
|
-
parameters[:scopes] = "public update"
|
157
|
-
|
158
|
-
subject.validate
|
159
|
-
expect(subject.error).to eq(:invalid_scope)
|
160
|
-
end
|
161
|
-
|
162
|
-
it "uses params[:scope] in favor of scopes if present (valid)" do
|
163
|
-
parameters[:scopes] = "public update"
|
164
|
-
parameters[:scope] = "public"
|
165
|
-
subject.authorize
|
166
|
-
expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public])
|
167
|
-
end
|
168
|
-
|
169
|
-
it "uses params[:scope] in favor of scopes if present (invalid)" do
|
170
|
-
parameters[:scopes] = "public"
|
171
|
-
parameters[:scope] = "public update"
|
172
|
-
|
173
|
-
subject.validate
|
174
|
-
expect(subject.error).to eq(:invalid_scope)
|
175
|
-
end
|
169
|
+
it "uses params[:scope] in favor of scopes if present (invalid)" do
|
170
|
+
parameters[:scopes] = "public"
|
171
|
+
parameters[:scope] = "public update"
|
172
|
+
|
173
|
+
subject.validate
|
174
|
+
expect(subject.error).to eq(:invalid_scope)
|
176
175
|
end
|
177
176
|
end
|
178
177
|
end
|
@@ -2,147 +2,145 @@
|
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
|
-
|
6
|
-
describe
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
5
|
+
describe Doorkeeper::OAuth::Scopes do
|
6
|
+
describe "#add" do
|
7
|
+
it "allows you to add scopes with symbols" do
|
8
|
+
subject.add :public
|
9
|
+
expect(subject.all).to eq(["public"])
|
10
|
+
end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
it "allows you to add scopes with strings" do
|
13
|
+
subject.add "public"
|
14
|
+
expect(subject.all).to eq(["public"])
|
15
|
+
end
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
17
|
+
it "do not add already included scopes" do
|
18
|
+
subject.add :public
|
19
|
+
subject.add :public
|
20
|
+
expect(subject.all).to eq(["public"])
|
23
21
|
end
|
22
|
+
end
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
describe "#exists" do
|
25
|
+
before do
|
26
|
+
subject.add :public
|
27
|
+
end
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
it "returns true if scope with given name is present" do
|
30
|
+
expect(subject.exists?("public")).to be_truthy
|
31
|
+
end
|
33
32
|
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
it "returns false if scope with given name does not exist" do
|
34
|
+
expect(subject.exists?("other")).to be_falsey
|
35
|
+
end
|
37
36
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
37
|
+
it "handles symbols" do
|
38
|
+
expect(subject.exists?(:public)).to be_truthy
|
39
|
+
expect(subject.exists?(:other)).to be_falsey
|
42
40
|
end
|
41
|
+
end
|
43
42
|
|
44
|
-
|
45
|
-
|
43
|
+
describe ".from_string" do
|
44
|
+
let(:string) { "public write" }
|
46
45
|
|
47
|
-
|
46
|
+
subject { described_class.from_string(string) }
|
48
47
|
|
49
|
-
|
48
|
+
it { expect(subject).to be_a(described_class) }
|
50
49
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
50
|
+
describe "#all" do
|
51
|
+
it "should be an array of the expected scopes" do
|
52
|
+
scopes_array = subject.all
|
53
|
+
expect(scopes_array.size).to eq(2)
|
54
|
+
expect(scopes_array).to include("public")
|
55
|
+
expect(scopes_array).to include("write")
|
58
56
|
end
|
59
57
|
end
|
58
|
+
end
|
60
59
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
60
|
+
describe "#+" do
|
61
|
+
it "can add to another scope object" do
|
62
|
+
scopes = described_class.from_string("public") + described_class.from_string("admin")
|
63
|
+
expect(scopes.all).to eq(%w[public admin])
|
64
|
+
end
|
66
65
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
66
|
+
it "does not change the existing object" do
|
67
|
+
origin = described_class.from_string("public")
|
68
|
+
expect(origin.to_s).to eq("public")
|
69
|
+
end
|
71
70
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
71
|
+
it "can add an array to a scope object" do
|
72
|
+
scopes = described_class.from_string("public") + ["admin"]
|
73
|
+
expect(scopes.all).to eq(%w[public admin])
|
74
|
+
end
|
76
75
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
end
|
76
|
+
it "raises an error if cannot handle addition" do
|
77
|
+
expect do
|
78
|
+
described_class.from_string("public") + "admin"
|
79
|
+
end.to raise_error(NoMethodError)
|
82
80
|
end
|
81
|
+
end
|
83
82
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
83
|
+
describe "#&" do
|
84
|
+
it "can get intersection with another scope object" do
|
85
|
+
scopes = described_class.from_string("public admin") & described_class.from_string("write admin")
|
86
|
+
expect(scopes.all).to eq(%w[admin])
|
87
|
+
end
|
89
88
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
89
|
+
it "does not change the existing object" do
|
90
|
+
origin = described_class.from_string("public admin")
|
91
|
+
origin & described_class.from_string("write admin")
|
92
|
+
expect(origin.to_s).to eq("public admin")
|
93
|
+
end
|
95
94
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
end
|
95
|
+
it "can get intersection with an array" do
|
96
|
+
scopes = described_class.from_string("public admin") & %w[write admin]
|
97
|
+
expect(scopes.all).to eq(%w[admin])
|
100
98
|
end
|
99
|
+
end
|
101
100
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
101
|
+
describe "#==" do
|
102
|
+
it "is equal to another set of scopes" do
|
103
|
+
expect(described_class.from_string("public")).to eq(described_class.from_string("public"))
|
104
|
+
end
|
106
105
|
|
107
|
-
|
108
|
-
|
109
|
-
|
106
|
+
it "is equal to another set of scopes with no particular order" do
|
107
|
+
expect(described_class.from_string("public write")).to eq(described_class.from_string("write public"))
|
108
|
+
end
|
110
109
|
|
111
|
-
|
112
|
-
|
113
|
-
|
110
|
+
it "differs from another set of scopes when scopes are not the same" do
|
111
|
+
expect(described_class.from_string("public write")).not_to eq(described_class.from_string("write"))
|
112
|
+
end
|
114
113
|
|
115
|
-
|
116
|
-
|
117
|
-
end
|
114
|
+
it "does not raise an error when compared to a non-enumerable object" do
|
115
|
+
expect { described_class.from_string("public") == false }.not_to raise_error
|
118
116
|
end
|
117
|
+
end
|
119
118
|
|
120
|
-
|
121
|
-
|
119
|
+
describe "#has_scopes?" do
|
120
|
+
subject { described_class.from_string("public admin") }
|
122
121
|
|
123
|
-
|
124
|
-
|
125
|
-
|
122
|
+
it "returns true when at least one scope is included" do
|
123
|
+
expect(subject.has_scopes?(described_class.from_string("public"))).to be_truthy
|
124
|
+
end
|
126
125
|
|
127
|
-
|
128
|
-
|
129
|
-
|
126
|
+
it "returns true when all scopes are included" do
|
127
|
+
expect(subject.has_scopes?(described_class.from_string("public admin"))).to be_truthy
|
128
|
+
end
|
130
129
|
|
131
|
-
|
132
|
-
|
133
|
-
|
130
|
+
it "is true if all scopes are included in any order" do
|
131
|
+
expect(subject.has_scopes?(described_class.from_string("admin public"))).to be_truthy
|
132
|
+
end
|
134
133
|
|
135
|
-
|
136
|
-
|
137
|
-
|
134
|
+
it "is false if no scopes are included" do
|
135
|
+
expect(subject.has_scopes?(described_class.from_string("notexistent"))).to be_falsey
|
136
|
+
end
|
138
137
|
|
139
|
-
|
140
|
-
|
141
|
-
|
138
|
+
it "returns false when any scope is not included" do
|
139
|
+
expect(subject.has_scopes?(described_class.from_string("public nope"))).to be_falsey
|
140
|
+
end
|
142
141
|
|
143
|
-
|
144
|
-
|
145
|
-
end
|
142
|
+
it "is false if no scopes are included even for existing ones" do
|
143
|
+
expect(subject.has_scopes?(described_class.from_string("public admin notexistent"))).to be_falsey
|
146
144
|
end
|
147
145
|
end
|
148
146
|
end
|