sorcery 0.13.0 → 0.16.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +5 -0
- data/.github/workflows/ruby.yml +49 -0
- data/.rubocop.yml +2 -2
- data/.rubocop_todo.yml +157 -1
- data/CHANGELOG.md +49 -0
- data/CODE_OF_CONDUCT.md +14 -0
- data/Gemfile +1 -1
- data/README.md +4 -4
- data/Rakefile +3 -1
- data/SECURITY.md +19 -0
- data/gemfiles/rails_52.gemfile +7 -0
- data/gemfiles/rails_60.gemfile +7 -0
- data/lib/generators/sorcery/helpers.rb +4 -0
- data/lib/generators/sorcery/templates/initializer.rb +111 -85
- data/lib/generators/sorcery/templates/migration/activity_logging.rb +5 -5
- data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +4 -4
- data/lib/generators/sorcery/templates/migration/core.rb +4 -4
- data/lib/generators/sorcery/templates/migration/external.rb +3 -3
- data/lib/generators/sorcery/templates/migration/magic_login.rb +4 -4
- data/lib/generators/sorcery/templates/migration/remember_me.rb +3 -3
- data/lib/generators/sorcery/templates/migration/reset_password.rb +5 -5
- data/lib/generators/sorcery/templates/migration/user_activation.rb +4 -4
- data/lib/sorcery/adapters/active_record_adapter.rb +2 -2
- data/lib/sorcery/controller.rb +4 -1
- data/lib/sorcery/controller/config.rb +6 -6
- data/lib/sorcery/controller/submodules/activity_logging.rb +5 -3
- data/lib/sorcery/controller/submodules/external.rb +4 -1
- data/lib/sorcery/controller/submodules/http_basic_auth.rb +1 -0
- data/lib/sorcery/controller/submodules/remember_me.rb +2 -1
- data/lib/sorcery/controller/submodules/session_timeout.rb +2 -0
- data/lib/sorcery/crypto_providers/aes256.rb +1 -1
- data/lib/sorcery/crypto_providers/bcrypt.rb +6 -1
- data/lib/sorcery/engine.rb +7 -1
- data/lib/sorcery/model.rb +6 -5
- data/lib/sorcery/model/config.rb +5 -0
- data/lib/sorcery/model/submodules/magic_login.rb +7 -4
- data/lib/sorcery/model/submodules/reset_password.rb +6 -2
- data/lib/sorcery/providers/battlenet.rb +51 -0
- data/lib/sorcery/providers/discord.rb +52 -0
- data/lib/sorcery/providers/line.rb +63 -0
- data/lib/sorcery/providers/linkedin.rb +45 -36
- data/lib/sorcery/providers/vk.rb +1 -1
- data/lib/sorcery/version.rb +1 -1
- data/sorcery.gemspec +5 -6
- data/spec/controllers/controller_oauth2_spec.rb +41 -6
- data/spec/controllers/controller_oauth_spec.rb +6 -0
- data/spec/controllers/controller_remember_me_spec.rb +15 -12
- data/spec/controllers/controller_spec.rb +11 -1
- data/spec/providers/example_provider_spec.rb +17 -0
- data/spec/providers/example_spec.rb +17 -0
- data/spec/rails_app/app/assets/config/manifest.js +1 -0
- data/spec/rails_app/app/controllers/application_controller.rb +2 -0
- data/spec/rails_app/app/controllers/sorcery_controller.rb +69 -1
- data/spec/rails_app/config/routes.rb +10 -0
- data/spec/shared_examples/user_reset_password_shared_examples.rb +18 -2
- data/spec/shared_examples/user_shared_examples.rb +63 -0
- data/spec/sorcery_crypto_providers_spec.rb +60 -0
- data/spec/support/migration_helper.rb +12 -2
- data/spec/support/providers/example.rb +11 -0
- data/spec/support/providers/example_provider.rb +11 -0
- metadata +25 -15
- data/.travis.yml +0 -38
- data/gemfiles/active_record_rails_40.gemfile +0 -6
- data/gemfiles/active_record_rails_41.gemfile +0 -6
- data/gemfiles/active_record_rails_42.gemfile +0 -6
@@ -150,6 +150,16 @@ describe SorceryController, type: :controller do
|
|
150
150
|
end
|
151
151
|
end
|
152
152
|
|
153
|
+
it 'require_login before_action does not save the url for JSON requests' do
|
154
|
+
get :some_action, format: :json
|
155
|
+
expect(session[:return_to_url]).to be_nil
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'require_login before_action does not save the url for XHR requests' do
|
159
|
+
get :some_action, xhr: true
|
160
|
+
expect(session[:return_to_url]).to be_nil
|
161
|
+
end
|
162
|
+
|
153
163
|
it 'on successful login the user is redirected to the url he originally wanted' do
|
154
164
|
session[:return_to_url] = 'http://test.host/some_action'
|
155
165
|
post :test_return_to, params: { email: 'bla@bla.com', password: 'secret' }
|
@@ -161,7 +171,7 @@ describe SorceryController, type: :controller do
|
|
161
171
|
# --- auto_login(user) ---
|
162
172
|
specify { should respond_to(:auto_login) }
|
163
173
|
|
164
|
-
it 'auto_login(user)
|
174
|
+
it 'auto_login(user) logs in a user instance' do
|
165
175
|
session[:user_id] = nil
|
166
176
|
subject.auto_login(user)
|
167
177
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'sorcery/providers/base'
|
5
|
+
|
6
|
+
describe Sorcery::Providers::ExampleProvider do
|
7
|
+
before(:all) do
|
8
|
+
sorcery_reload!([:external])
|
9
|
+
sorcery_controller_property_set(:external_providers, [:example_provider])
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'fetching a multi-word custom provider' do
|
13
|
+
it 'returns the provider' do
|
14
|
+
expect(Sorcery::Controller::Config.example_provider).to be_a(Sorcery::Providers::ExampleProvider)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'sorcery/providers/base'
|
5
|
+
|
6
|
+
describe Sorcery::Providers::Example do
|
7
|
+
before(:all) do
|
8
|
+
sorcery_reload!([:external])
|
9
|
+
sorcery_controller_property_set(:external_providers, [:example])
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'fetching a single-word custom provider' do
|
13
|
+
it 'returns the provider' do
|
14
|
+
expect(Sorcery::Controller::Config.example).to be_a(Sorcery::Providers::Example)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
{}
|
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'oauth'
|
2
2
|
|
3
|
-
class SorceryController <
|
3
|
+
class SorceryController < ApplicationController
|
4
4
|
protect_from_forgery
|
5
5
|
|
6
6
|
before_action :require_login_from_http_basic, only: [:test_http_basic_auth]
|
7
7
|
before_action :require_login, only: %i[
|
8
8
|
test_logout
|
9
|
+
test_logout_with_forget_me
|
9
10
|
test_logout_with_force_forget_me
|
10
11
|
test_should_be_logged_in
|
11
12
|
some_action
|
@@ -50,6 +51,13 @@ class SorceryController < ActionController::Base
|
|
50
51
|
head :ok
|
51
52
|
end
|
52
53
|
|
54
|
+
def test_logout_with_forget_me
|
55
|
+
remember_me!
|
56
|
+
forget_me!
|
57
|
+
logout
|
58
|
+
head :ok
|
59
|
+
end
|
60
|
+
|
53
61
|
def test_logout_with_force_forget_me
|
54
62
|
remember_me!
|
55
63
|
force_forget_me!
|
@@ -142,6 +150,10 @@ class SorceryController < ActionController::Base
|
|
142
150
|
login_at(:slack)
|
143
151
|
end
|
144
152
|
|
153
|
+
def login_at_test_line
|
154
|
+
login_at(:line)
|
155
|
+
end
|
156
|
+
|
145
157
|
def login_at_test_with_state
|
146
158
|
login_at(:facebook, state: 'bla')
|
147
159
|
end
|
@@ -154,6 +166,14 @@ class SorceryController < ActionController::Base
|
|
154
166
|
login_at(:auth0)
|
155
167
|
end
|
156
168
|
|
169
|
+
def login_at_test_discord
|
170
|
+
login_at(:discord)
|
171
|
+
end
|
172
|
+
|
173
|
+
def login_at_test_battlenet
|
174
|
+
login_at(:battlenet)
|
175
|
+
end
|
176
|
+
|
157
177
|
def test_login_from_twitter
|
158
178
|
if (@user = login_from(:twitter))
|
159
179
|
redirect_to 'bla', notice: 'Success!'
|
@@ -268,6 +288,30 @@ class SorceryController < ActionController::Base
|
|
268
288
|
end
|
269
289
|
end
|
270
290
|
|
291
|
+
def test_login_from_line
|
292
|
+
if @user = login_from(:line)
|
293
|
+
redirect_to 'bla', notice: 'Success!'
|
294
|
+
else
|
295
|
+
redirect_to 'blu', alert: 'Failed!'
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def test_login_from_discord
|
300
|
+
if (@user = login_from(:discord))
|
301
|
+
redirect_to 'bla', notice: 'Success!'
|
302
|
+
else
|
303
|
+
redirect_to 'blu', alert: 'Failed!'
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def test_login_from_battlenet
|
308
|
+
if (@user = login_from(:battlenet))
|
309
|
+
redirect_to 'bla', notice: 'Success!'
|
310
|
+
else
|
311
|
+
redirect_to 'blu', alert: 'Failed!'
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
271
315
|
def test_return_to_with_external_twitter
|
272
316
|
if (@user = login_from(:twitter))
|
273
317
|
redirect_back_or_to 'bla', notice: 'Success!'
|
@@ -382,6 +426,30 @@ class SorceryController < ActionController::Base
|
|
382
426
|
end
|
383
427
|
end
|
384
428
|
|
429
|
+
def test_return_to_with_external_line
|
430
|
+
if @user = login_from(:line)
|
431
|
+
redirect_back_or_to 'bla', notice: 'Success!'
|
432
|
+
else
|
433
|
+
redirect_to 'blu', alert: 'Failed!'
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
def test_return_to_with_external_discord
|
438
|
+
if (@user = login_from(:discord))
|
439
|
+
redirect_back_or_to 'bla', notice: 'Success!'
|
440
|
+
else
|
441
|
+
redirect_to 'blu', alert: 'Failed!'
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
def test_return_to_with_external_battlenet
|
446
|
+
if (@user = login_from(:battlenet))
|
447
|
+
redirect_back_or_to 'bla', notice: 'Success!'
|
448
|
+
else
|
449
|
+
redirect_to 'blu', alert: 'Failed!'
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
385
453
|
def test_create_from_provider
|
386
454
|
provider = params[:provider]
|
387
455
|
login_from(provider)
|
@@ -11,6 +11,7 @@ AppRoot::Application.routes.draw do
|
|
11
11
|
get :test_login_from_cookie
|
12
12
|
get :test_login_from
|
13
13
|
get :test_logout_with_remember
|
14
|
+
get :test_logout_with_forget_me
|
14
15
|
get :test_logout_with_force_forget_me
|
15
16
|
get :test_invalidate_active_session
|
16
17
|
get :test_should_be_logged_in
|
@@ -32,6 +33,9 @@ AppRoot::Application.routes.draw do
|
|
32
33
|
get :test_login_from_slack
|
33
34
|
get :test_login_from_instagram
|
34
35
|
get :test_login_from_auth0
|
36
|
+
get :test_login_from_line
|
37
|
+
get :test_login_from_discord
|
38
|
+
get :test_login_from_battlenet
|
35
39
|
get :login_at_test
|
36
40
|
get :login_at_test_twitter
|
37
41
|
get :login_at_test_facebook
|
@@ -47,6 +51,9 @@ AppRoot::Application.routes.draw do
|
|
47
51
|
get :login_at_test_slack
|
48
52
|
get :login_at_test_instagram
|
49
53
|
get :login_at_test_auth0
|
54
|
+
get :login_at_test_line
|
55
|
+
get :login_at_test_discord
|
56
|
+
get :login_at_test_battlenet
|
50
57
|
get :test_return_to_with_external
|
51
58
|
get :test_return_to_with_external_twitter
|
52
59
|
get :test_return_to_with_external_facebook
|
@@ -62,6 +69,9 @@ AppRoot::Application.routes.draw do
|
|
62
69
|
get :test_return_to_with_external_slack
|
63
70
|
get :test_return_to_with_external_instagram
|
64
71
|
get :test_return_to_with_external_auth0
|
72
|
+
get :test_return_to_with_external_line
|
73
|
+
get :test_return_to_with_external_discord
|
74
|
+
get :test_return_to_with_external_battlenet
|
65
75
|
get :test_http_basic_auth
|
66
76
|
get :some_action_making_a_non_persisted_change_to_the_user
|
67
77
|
post :test_login_with_remember
|
@@ -14,6 +14,8 @@ shared_examples_for 'rails_3_reset_password_model' do
|
|
14
14
|
context 'API' do
|
15
15
|
specify { expect(user).to respond_to :deliver_reset_password_instructions! }
|
16
16
|
|
17
|
+
specify { expect(user).to respond_to :change_password }
|
18
|
+
|
17
19
|
specify { expect(user).to respond_to :change_password! }
|
18
20
|
|
19
21
|
it 'responds to .load_from_reset_password_token' do
|
@@ -314,13 +316,27 @@ shared_examples_for 'rails_3_reset_password_model' do
|
|
314
316
|
end
|
315
317
|
end
|
316
318
|
|
317
|
-
it 'when change_password! is called, deletes reset_password_token' do
|
319
|
+
it 'when change_password! is called, deletes reset_password_token and calls #save!' do
|
318
320
|
user.deliver_reset_password_instructions!
|
319
321
|
|
320
322
|
expect(user.reset_password_token).not_to be_nil
|
323
|
+
expect(user).to_not receive(:save)
|
324
|
+
expect(user).to receive(:save!)
|
321
325
|
|
322
326
|
user.change_password!('blabulsdf')
|
323
|
-
|
327
|
+
|
328
|
+
expect(user.reset_password_token).to be_nil
|
329
|
+
end
|
330
|
+
|
331
|
+
it 'when change_password is called, deletes reset_password_token and calls #save' do
|
332
|
+
new_password = 'blabulsdf'
|
333
|
+
|
334
|
+
user.deliver_reset_password_instructions!
|
335
|
+
expect(user.reset_password_token).not_to be_nil
|
336
|
+
expect(user).to_not receive(:save!)
|
337
|
+
expect(user).to receive(:save)
|
338
|
+
|
339
|
+
user.change_password(new_password)
|
324
340
|
|
325
341
|
expect(user.reset_password_token).to be_nil
|
326
342
|
end
|
@@ -54,6 +54,13 @@ shared_examples_for 'rails_3_core_model' do
|
|
54
54
|
expect(User.sorcery_config.custom_encryption_provider).to eq Array
|
55
55
|
end
|
56
56
|
|
57
|
+
it "enables configuration option 'pepper'" do
|
58
|
+
pepper = '*$%&%*++'
|
59
|
+
sorcery_model_property_set(:pepper, pepper)
|
60
|
+
|
61
|
+
expect(User.sorcery_config.pepper).to eq pepper
|
62
|
+
end
|
63
|
+
|
57
64
|
it "enables configuration option 'salt_join_token'" do
|
58
65
|
salt_join_token = '--%%*&-'
|
59
66
|
sorcery_model_property_set(:salt_join_token, salt_join_token)
|
@@ -459,6 +466,14 @@ shared_examples_for 'rails_3_core_model' do
|
|
459
466
|
expect(User.encrypt(@text)).to eq Sorcery::CryptoProviders::SHA512.encrypt(@text)
|
460
467
|
end
|
461
468
|
|
469
|
+
it 'if encryption algo is bcrypt it works' do
|
470
|
+
sorcery_model_property_set(:encryption_algorithm, :bcrypt)
|
471
|
+
|
472
|
+
# comparison is done using BCrypt::Password#==(raw_token), not by String#==
|
473
|
+
expect(User.encrypt(@text)).to be_an_instance_of BCrypt::Password
|
474
|
+
expect(User.encrypt(@text)).to eq @text
|
475
|
+
end
|
476
|
+
|
462
477
|
it 'salt is random for each user and saved in db' do
|
463
478
|
sorcery_model_property_set(:salt_attribute_name, :salt)
|
464
479
|
|
@@ -488,6 +503,54 @@ shared_examples_for 'rails_3_core_model' do
|
|
488
503
|
|
489
504
|
expect(user.crypted_password).to eq Sorcery::CryptoProviders::SHA512.encrypt('secret', user.salt)
|
490
505
|
end
|
506
|
+
|
507
|
+
it 'if pepper is set uses it to encrypt' do
|
508
|
+
sorcery_model_property_set(:salt_attribute_name, :salt)
|
509
|
+
sorcery_model_property_set(:pepper, '++@^$')
|
510
|
+
sorcery_model_property_set(:encryption_algorithm, :bcrypt)
|
511
|
+
|
512
|
+
# password comparison is done using BCrypt::Password#==(raw_token), not String#==
|
513
|
+
bcrypt_password = BCrypt::Password.new(user.crypted_password)
|
514
|
+
allow(::BCrypt::Password).to receive(:create) do |token, options = {}|
|
515
|
+
# need to use common BCrypt's salt when genarating BCrypt::Password objects
|
516
|
+
# so that any generated password hashes can be compared each other
|
517
|
+
::BCrypt::Engine.hash_secret(token, bcrypt_password.salt)
|
518
|
+
end
|
519
|
+
|
520
|
+
expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret')
|
521
|
+
|
522
|
+
Sorcery::CryptoProviders::BCrypt.pepper = ''
|
523
|
+
|
524
|
+
expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret', user.salt)
|
525
|
+
|
526
|
+
Sorcery::CryptoProviders::BCrypt.pepper = User.sorcery_config.pepper
|
527
|
+
|
528
|
+
expect(user.crypted_password).to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret', user.salt)
|
529
|
+
end
|
530
|
+
|
531
|
+
it 'if pepper is empty string (default) does not use pepper to encrypt' do
|
532
|
+
sorcery_model_property_set(:salt_attribute_name, :salt)
|
533
|
+
sorcery_model_property_set(:pepper, '')
|
534
|
+
sorcery_model_property_set(:encryption_algorithm, :bcrypt)
|
535
|
+
|
536
|
+
# password comparison is done using BCrypt::Password#==(raw_token), not String#==
|
537
|
+
bcrypt_password = BCrypt::Password.new(user.crypted_password)
|
538
|
+
allow(::BCrypt::Password).to receive(:create) do |token, options = {}|
|
539
|
+
# need to use common BCrypt's salt when genarating BCrypt::Password objects
|
540
|
+
# so that any generated password hashes can be compared each other
|
541
|
+
::BCrypt::Engine.hash_secret(token, bcrypt_password.salt)
|
542
|
+
end
|
543
|
+
|
544
|
+
expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret')
|
545
|
+
|
546
|
+
Sorcery::CryptoProviders::BCrypt.pepper = 'some_pepper'
|
547
|
+
|
548
|
+
expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret', user.salt)
|
549
|
+
|
550
|
+
Sorcery::CryptoProviders::BCrypt.pepper = User.sorcery_config.pepper
|
551
|
+
|
552
|
+
expect(user.crypted_password).to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret', user.salt)
|
553
|
+
end
|
491
554
|
end
|
492
555
|
|
493
556
|
describe 'ORM adapter' do
|
@@ -148,6 +148,7 @@ describe 'Crypto Providers wrappers' do
|
|
148
148
|
before(:all) do
|
149
149
|
Sorcery::CryptoProviders::BCrypt.cost = 1
|
150
150
|
@digest = BCrypt::Password.create('Noam Ben-Ari', cost: Sorcery::CryptoProviders::BCrypt.cost)
|
151
|
+
@tokens = %w[password gq18WBnJYNh2arkC1kgH]
|
151
152
|
end
|
152
153
|
|
153
154
|
after(:each) do
|
@@ -181,5 +182,64 @@ describe 'Crypto Providers wrappers' do
|
|
181
182
|
# stubbed in Sorcery::TestHelpers::Internal
|
182
183
|
expect(Sorcery::CryptoProviders::BCrypt.cost).to eq 1
|
183
184
|
end
|
185
|
+
|
186
|
+
it 'matches token encrypted with salt from upstream' do
|
187
|
+
# note: actual comparison is done by BCrypt::Password#==(raw_token)
|
188
|
+
expect(Sorcery::CryptoProviders::BCrypt.encrypt(@tokens)).to eq @tokens.flatten.join
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'respond_to?(:pepper) returns true' do
|
192
|
+
expect(Sorcery::CryptoProviders::BCrypt.respond_to?(:pepper)).to be true
|
193
|
+
end
|
194
|
+
|
195
|
+
context 'when pepper is provided' do
|
196
|
+
before(:each) do
|
197
|
+
Sorcery::CryptoProviders::BCrypt.pepper = 'pepper'
|
198
|
+
@digest = Sorcery::CryptoProviders::BCrypt.encrypt(@tokens) # a BCrypt::Password object
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'matches token encrypted with salt and pepper from upstream' do
|
202
|
+
# note: actual comparison is done by BCrypt::Password#==(raw_token)
|
203
|
+
expect(@digest).to eq @tokens.flatten.join.concat('pepper')
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'matches? returns true when matches' do
|
207
|
+
expect(Sorcery::CryptoProviders::BCrypt.matches?(@digest, *@tokens)).to be true
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'matches? returns false when pepper is replaced with empty string' do
|
211
|
+
Sorcery::CryptoProviders::BCrypt.pepper = ''
|
212
|
+
expect(Sorcery::CryptoProviders::BCrypt.matches?(@digest, *@tokens)).to be false
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'matches? returns false when no match' do
|
216
|
+
expect(Sorcery::CryptoProviders::BCrypt.matches?(@digest, 'a_random_incorrect_password')).to be false
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
context "when pepper is an empty string (default)" do
|
221
|
+
before(:each) do
|
222
|
+
Sorcery::CryptoProviders::BCrypt.pepper = ''
|
223
|
+
@digest = Sorcery::CryptoProviders::BCrypt.encrypt(@tokens) # a BCrypt::Password object
|
224
|
+
end
|
225
|
+
|
226
|
+
# make sure the default pepper '' does nothing
|
227
|
+
it 'matches token encrypted with salt only (without pepper)' do
|
228
|
+
expect(@digest).to eq @tokens.flatten.join # keep consistency with the older versions of #join_token
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'matches? returns true when matches' do
|
232
|
+
expect(Sorcery::CryptoProviders::BCrypt.matches?(@digest, *@tokens)).to be true
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'matches? returns false when pepper has changed' do
|
236
|
+
Sorcery::CryptoProviders::BCrypt.pepper = 'a new pepper'
|
237
|
+
expect(Sorcery::CryptoProviders::BCrypt.matches?(@digest, *@tokens)).to be false
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'matches? returns false when no match' do
|
241
|
+
expect(Sorcery::CryptoProviders::BCrypt.matches?(@digest, 'a_random_incorrect_password')).to be false
|
242
|
+
end
|
243
|
+
end
|
184
244
|
end
|
185
245
|
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
class MigrationHelper
|
2
2
|
class << self
|
3
3
|
def migrate(path)
|
4
|
-
if ActiveRecord.version >= Gem::Version.new('
|
4
|
+
if ActiveRecord.version >= Gem::Version.new('6.0.0')
|
5
|
+
ActiveRecord::MigrationContext.new(path, schema_migration).migrate
|
6
|
+
elsif ActiveRecord.version >= Gem::Version.new('5.2.0')
|
5
7
|
ActiveRecord::MigrationContext.new(path).migrate
|
6
8
|
else
|
7
9
|
ActiveRecord::Migrator.migrate(path)
|
@@ -9,11 +11,19 @@ class MigrationHelper
|
|
9
11
|
end
|
10
12
|
|
11
13
|
def rollback(path)
|
12
|
-
if ActiveRecord.version >= Gem::Version.new('
|
14
|
+
if ActiveRecord.version >= Gem::Version.new('6.0.0')
|
15
|
+
ActiveRecord::MigrationContext.new(path, schema_migration).rollback
|
16
|
+
elsif ActiveRecord.version >= Gem::Version.new('5.2.0')
|
13
17
|
ActiveRecord::MigrationContext.new(path).rollback
|
14
18
|
else
|
15
19
|
ActiveRecord::Migrator.rollback(path)
|
16
20
|
end
|
17
21
|
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def schema_migration
|
26
|
+
ActiveRecord::Base.connection.schema_migration
|
27
|
+
end
|
18
28
|
end
|
19
29
|
end
|