devise-argon2 1.1.0 → 2.0.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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +66 -0
- data/.gitignore +3 -0
- data/CHANGELOG.md +32 -0
- data/Gemfile +9 -4
- data/README.md +120 -32
- data/devise-argon2.gemspec +17 -14
- data/lib/devise-argon2/model.rb +101 -0
- data/lib/devise-argon2/version.rb +5 -0
- data/lib/devise-argon2.rb +8 -3
- data/spec/devise-argon2_spec.rb +273 -27
- data/spec/orm/active_record.rb +1 -0
- data/spec/orm/mongoid.rb +5 -0
- data/spec/rails_app/Rakefile +6 -0
- data/spec/rails_app/app/active_record/old_user.rb +3 -0
- data/spec/rails_app/app/active_record/user.rb +3 -0
- data/spec/rails_app/app/controllers/application_controller.rb +3 -0
- data/spec/rails_app/app/mongoid/old_user.rb +12 -0
- data/spec/rails_app/app/mongoid/user.rb +10 -0
- data/spec/rails_app/bin/bundle +109 -0
- data/spec/rails_app/bin/rails +4 -0
- data/spec/rails_app/bin/rake +4 -0
- data/spec/rails_app/bin/setup +33 -0
- data/spec/rails_app/config/application.rb +24 -0
- data/spec/rails_app/config/boot.rb +5 -0
- data/spec/rails_app/config/database.yml +14 -0
- data/spec/rails_app/config/environment.rb +7 -0
- data/spec/rails_app/config/initializers/devise.rb +6 -0
- data/spec/rails_app/config/mongoid.yml +10 -0
- data/spec/rails_app/config.ru +6 -0
- data/spec/rails_app/db/migrate/20230617201921_devise_create_users.rb +15 -0
- data/spec/rails_app/db/migrate/20231004084147_devise_create_old_users.rb +17 -0
- data/spec/rails_app/db/schema.rb +31 -0
- data/spec/spec_helper.rb +7 -3
- metadata +64 -31
- data/.travis.yml +0 -13
- data/lib/devise/encryptable/encryptors/argon2/version.rb +0 -7
- data/lib/devise/encryptable/encryptors/argon2.rb +0 -17
data/spec/devise-argon2_spec.rb
CHANGED
@@ -1,50 +1,296 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'spec_helper'
|
3
|
+
require 'bcrypt'
|
3
4
|
|
4
|
-
describe Devise::
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
describe Devise::Models::Argon2 do
|
6
|
+
CORRECT_PASSWORD = 'Tr0ub4dor&3'
|
7
|
+
INCORRECT_PASSWORD = 'wrong'
|
8
|
+
DEFAULT_M_COST = 3
|
9
|
+
DEFAULT_T_COST = 1
|
10
|
+
DEFAULT_P_COST = 1
|
8
11
|
|
9
|
-
|
10
|
-
let(:salt) { "You say you love me like salt! The simplest spice in my kingdom!" }
|
11
|
-
let(:pepper) { "I don't really want to stop the show But I thought that you might like to know That the singer's going to sing a song And he wants you all to sing along" }
|
12
|
+
let(:user) { User.new(password: CORRECT_PASSWORD) }
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
before do
|
15
|
+
Devise.pepper = nil
|
16
|
+
Devise.argon2_options = {
|
17
|
+
m_cost: DEFAULT_M_COST,
|
18
|
+
t_cost: DEFAULT_T_COST,
|
19
|
+
p_cost: DEFAULT_P_COST
|
20
|
+
}
|
21
|
+
User.destroy_all
|
22
|
+
end
|
23
|
+
|
24
|
+
def work_factors(hash)
|
25
|
+
hash_format = Argon2::HashFormat.new(hash)
|
26
|
+
{
|
27
|
+
m_cost: hash_format.m_cost,
|
28
|
+
t_cost: hash_format.t_cost,
|
29
|
+
p_cost: hash_format.p_cost
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'valid_password?' do
|
34
|
+
shared_examples 'a password is validated if and only if it is correct' do
|
35
|
+
it 'validates the correct password' do
|
36
|
+
expect(user.valid_password?(CORRECT_PASSWORD)).to be true
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'does not validate an incorrect password' do
|
40
|
+
expect(user.valid_password?(INCORRECT_PASSWORD)).to be false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'no pepper' do
|
45
|
+
include_examples 'a password is validated if and only if it is correct'
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'Devise.pepper is set' do
|
49
|
+
before do
|
50
|
+
Devise.pepper = 'pepper'
|
51
|
+
end
|
52
|
+
|
53
|
+
include_examples 'a password is validated if and only if it is correct'
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'argon2_options[:secret] is set' do
|
57
|
+
before do
|
58
|
+
Devise.argon2_options[:secret] = 'pepper'
|
59
|
+
end
|
15
60
|
|
16
|
-
|
17
|
-
|
18
|
-
|
61
|
+
include_examples 'a password is validated if and only if it is correct'
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'encrypted_password is a BCrypt hash' do
|
65
|
+
before do
|
66
|
+
Devise.pepper = 'devise pepper'
|
67
|
+
Devise.argon2_options.merge!({ secret: 'argon2 secret' })
|
68
|
+
|
69
|
+
# Devise peppers by concatenating password and pepper:
|
70
|
+
# https://github.com/heartcombo/devise/blob/main/lib/devise/encryptor.rb
|
71
|
+
bcrypt_hash = BCrypt::Password.create("#{CORRECT_PASSWORD}#{Devise.pepper}", cost: 4)
|
72
|
+
|
73
|
+
user.encrypted_password = bcrypt_hash
|
74
|
+
end
|
75
|
+
|
76
|
+
include_examples 'a password is validated if and only if it is correct'
|
77
|
+
|
78
|
+
it 'updates hash if valid password is given' do
|
79
|
+
expect{ user.valid_password?(CORRECT_PASSWORD) }.to(change(user, :encrypted_password))
|
80
|
+
expect(
|
81
|
+
::Argon2::Password.verify_password(
|
82
|
+
CORRECT_PASSWORD,
|
83
|
+
user.encrypted_password,
|
84
|
+
'argon2 secret'
|
85
|
+
)
|
86
|
+
).to be true
|
87
|
+
end
|
19
88
|
|
20
|
-
it
|
21
|
-
expect(
|
89
|
+
it 'does not update the hash if an invalid password is given' do
|
90
|
+
expect{ user.valid_password?(INCORRECT_PASSWORD) }.not_to(change(user, :encrypted_password))
|
22
91
|
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'encrypted_password is hashed with version 1 of devise-argon2' do
|
95
|
+
let(:user) { OldUser.new(password: CORRECT_PASSWORD) }
|
23
96
|
|
24
|
-
|
25
|
-
|
97
|
+
before do
|
98
|
+
Devise.pepper = 'devise pepper'
|
99
|
+
Devise.argon2_options.merge!({
|
100
|
+
secret: 'argon2 secret',
|
101
|
+
migrate_from_devise_argon2_v1: true
|
102
|
+
})
|
103
|
+
|
104
|
+
user.password_salt = 'devise-argon2 v1 salt'
|
105
|
+
user.encrypted_password = ::Argon2::Password.create(
|
106
|
+
"#{CORRECT_PASSWORD}#{user.password_salt}#{Devise.pepper}"
|
107
|
+
)
|
26
108
|
end
|
27
109
|
|
28
|
-
|
29
|
-
|
110
|
+
include_examples 'a password is validated if and only if it is correct'
|
111
|
+
|
112
|
+
it 'updates hash once if valid password is given' do
|
113
|
+
expect{ user.valid_password?(CORRECT_PASSWORD) }.to(
|
114
|
+
change(user, :encrypted_password)
|
115
|
+
.and(change(user, :password_salt).to(nil))
|
116
|
+
)
|
117
|
+
expect(
|
118
|
+
::Argon2::Password.verify_password(
|
119
|
+
CORRECT_PASSWORD,
|
120
|
+
user.encrypted_password,
|
121
|
+
'argon2 secret'
|
122
|
+
)
|
123
|
+
).to be true
|
124
|
+
expect{ user.valid_password?(CORRECT_PASSWORD) }.not_to(change(user, :encrypted_password))
|
30
125
|
end
|
31
126
|
|
32
|
-
it
|
33
|
-
expect(
|
127
|
+
it 'does not update the hash if an invalid password is given' do
|
128
|
+
expect{ user.valid_password?(INCORRECT_PASSWORD) }.not_to(change(user, :encrypted_password))
|
34
129
|
end
|
35
130
|
end
|
36
131
|
|
37
|
-
describe
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
132
|
+
describe 'updating outdated work factors' do
|
133
|
+
it 'updates work factors if a valid password is given' do
|
134
|
+
user # build user
|
135
|
+
|
136
|
+
Devise.argon2_options.merge!({
|
137
|
+
m_cost: 4,
|
138
|
+
t_cost: 3,
|
139
|
+
p_cost: 2
|
140
|
+
})
|
141
|
+
|
142
|
+
expect{ user.valid_password?(CORRECT_PASSWORD) }.to(
|
143
|
+
change{ work_factors(user.encrypted_password) }
|
144
|
+
.from({ m_cost: 1 << DEFAULT_M_COST, t_cost: DEFAULT_T_COST, p_cost: DEFAULT_P_COST})
|
145
|
+
.to({ m_cost: 1 << 4, t_cost: 3, p_cost: 2 })
|
146
|
+
)
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'does not update work factors if an invalid password is given' do
|
150
|
+
user # build user
|
42
151
|
|
43
|
-
|
44
|
-
|
152
|
+
Devise.argon2_options.merge!({
|
153
|
+
m_cost: 4,
|
154
|
+
t_cost: 3,
|
155
|
+
p_cost: 2
|
156
|
+
})
|
157
|
+
|
158
|
+
expect{ user.valid_password?(INCORRECT_PASSWORD) }
|
159
|
+
.not_to change{ work_factors(user.encrypted_password) }
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'updates work factors for a persisted user' do
|
163
|
+
user.save!
|
164
|
+
|
165
|
+
Devise.argon2_options.merge!({
|
166
|
+
m_cost: 4,
|
167
|
+
t_cost: 3,
|
168
|
+
p_cost: 2
|
169
|
+
})
|
170
|
+
|
171
|
+
expect{ user.valid_password?(CORRECT_PASSWORD) }.to(
|
172
|
+
change{ work_factors(user.encrypted_password) }
|
173
|
+
.from({ m_cost: 1 << DEFAULT_M_COST, t_cost: DEFAULT_T_COST, p_cost: DEFAULT_P_COST})
|
174
|
+
.to({ m_cost: 1 << 4, t_cost: 3, p_cost: 2 })
|
175
|
+
)
|
176
|
+
end
|
177
|
+
|
178
|
+
if Argon2::VERSION >= '2.3.0'
|
179
|
+
it 'updates work factors if they changed via profile option' do
|
180
|
+
# Build user with argon2 default work factors (which match the RFC_9106_LOW_MEMORY
|
181
|
+
# profile.)
|
182
|
+
Devise.argon2_options = {}
|
183
|
+
user
|
184
|
+
|
185
|
+
Devise.argon2_options = { profile: :pre_rfc_9106 }
|
186
|
+
|
187
|
+
expect{ user.valid_password?(CORRECT_PASSWORD) }.to(
|
188
|
+
change{ work_factors(user.encrypted_password) }
|
189
|
+
.to(
|
190
|
+
{
|
191
|
+
m_cost: 1 << Argon2::Profiles[:pre_rfc_9106][:m_cost],
|
192
|
+
t_cost: Argon2::Profiles[:pre_rfc_9106][:t_cost],
|
193
|
+
p_cost: Argon2::Profiles[:pre_rfc_9106][:p_cost]
|
194
|
+
}
|
195
|
+
)
|
196
|
+
)
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'gives precendence to the profile option over explicit configuration of work factors' do
|
200
|
+
Devise.argon2_options = {
|
201
|
+
m_cost: Argon2::Profiles[:pre_rfc_9106][:m_cost] + 1,
|
202
|
+
t_cost: Argon2::Profiles[:pre_rfc_9106][:t_cost] + 1,
|
203
|
+
p_cost: Argon2::Profiles[:pre_rfc_9106][:p_cost] + 1
|
204
|
+
}
|
205
|
+
user # build user
|
206
|
+
|
207
|
+
Devise.argon2_options = {
|
208
|
+
profile: :pre_rfc_9106,
|
209
|
+
m_cost: Argon2::Profiles[:pre_rfc_9106][:m_cost] + 1,
|
210
|
+
t_cost: Argon2::Profiles[:pre_rfc_9106][:t_cost] + 1,
|
211
|
+
p_cost: Argon2::Profiles[:pre_rfc_9106][:p_cost] + 1
|
212
|
+
}
|
213
|
+
|
214
|
+
expect{ user.valid_password?(CORRECT_PASSWORD) }.to(
|
215
|
+
change{ work_factors(user.encrypted_password) }
|
216
|
+
.to(
|
217
|
+
{
|
218
|
+
m_cost: 1 << Argon2::Profiles[:pre_rfc_9106][:m_cost],
|
219
|
+
t_cost: Argon2::Profiles[:pre_rfc_9106][:t_cost],
|
220
|
+
p_cost: Argon2::Profiles[:pre_rfc_9106][:p_cost]
|
221
|
+
}
|
222
|
+
)
|
223
|
+
)
|
224
|
+
end
|
45
225
|
end
|
46
226
|
end
|
47
227
|
|
228
|
+
it 'ignores migrate_from_devise_argon2_v1 if password_salt is not present' do
|
229
|
+
Devise.argon2_options.merge!({ migrate_from_devise_argon2_v1: true })
|
230
|
+
expect{ user.valid_password?(CORRECT_PASSWORD) }.not_to(change(user, :encrypted_password))
|
231
|
+
end
|
48
232
|
end
|
49
233
|
|
234
|
+
describe 'password_digest' do
|
235
|
+
context 'no pepper' do
|
236
|
+
it 'hashes the given password with Argon2' do
|
237
|
+
expect(
|
238
|
+
Argon2::Password.verify_password(CORRECT_PASSWORD, user.encrypted_password)
|
239
|
+
).to be true
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
context 'Devise.pepper is set' do
|
244
|
+
before do
|
245
|
+
Devise.pepper = 'pepper'
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'uses Devise.pepper as secret key for Argon2' do
|
249
|
+
expect(
|
250
|
+
Argon2::Password.verify_password(CORRECT_PASSWORD, user.encrypted_password, 'pepper')
|
251
|
+
).to be true
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
context 'argon2_options[:secret] is set' do
|
256
|
+
before do
|
257
|
+
Devise.argon2_options[:secret] = 'pepper'
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'uses argon2_options[:secret] as secret key for Argon2' do
|
261
|
+
expect(
|
262
|
+
Argon2::Password.verify_password(CORRECT_PASSWORD, user.encrypted_password, 'pepper')
|
263
|
+
).to be true
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
context 'both Devise.pepper and argon2_options[:secret] are set' do
|
268
|
+
before do
|
269
|
+
Devise.pepper = 'devise pepper'
|
270
|
+
Devise.argon2_options[:secret] = 'argon2_options pepper'
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'uses argon2_options[:secret] as secret key for Argon2' do
|
274
|
+
expect(
|
275
|
+
Argon2::Password.verify_password(
|
276
|
+
CORRECT_PASSWORD,
|
277
|
+
user.encrypted_password,
|
278
|
+
'argon2_options pepper'
|
279
|
+
)
|
280
|
+
).to be true
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'uses work factors given in argon2_options' do
|
285
|
+
Devise.argon2_options.merge!({
|
286
|
+
m_cost: 4,
|
287
|
+
t_cost: 3,
|
288
|
+
p_cost: 2
|
289
|
+
})
|
290
|
+
|
291
|
+
expect(work_factors(user.encrypted_password)).to eq(
|
292
|
+
{ m_cost: 1 << 4, t_cost: 3, p_cost: 2 }
|
293
|
+
)
|
294
|
+
end
|
295
|
+
end
|
50
296
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
ActiveRecord::Base.logger = Logger.new(nil)
|
data/spec/orm/mongoid.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
class OldUser
|
2
|
+
include Mongoid::Document
|
3
|
+
|
4
|
+
devise :database_authenticatable, :argon2
|
5
|
+
|
6
|
+
field :email, type: String, default: ""
|
7
|
+
field :encrypted_password, type: String, default: ""
|
8
|
+
|
9
|
+
field :password_salt, type: String, default: ""
|
10
|
+
|
11
|
+
include Mongoid::Timestamps
|
12
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'bundle' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "rubygems"
|
12
|
+
|
13
|
+
m = Module.new do
|
14
|
+
module_function
|
15
|
+
|
16
|
+
def invoked_as_script?
|
17
|
+
File.expand_path($0) == File.expand_path(__FILE__)
|
18
|
+
end
|
19
|
+
|
20
|
+
def env_var_version
|
21
|
+
ENV["BUNDLER_VERSION"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def cli_arg_version
|
25
|
+
return unless invoked_as_script? # don't want to hijack other binstubs
|
26
|
+
return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
|
27
|
+
bundler_version = nil
|
28
|
+
update_index = nil
|
29
|
+
ARGV.each_with_index do |a, i|
|
30
|
+
if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
|
31
|
+
bundler_version = a
|
32
|
+
end
|
33
|
+
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
|
34
|
+
bundler_version = $1
|
35
|
+
update_index = i
|
36
|
+
end
|
37
|
+
bundler_version
|
38
|
+
end
|
39
|
+
|
40
|
+
def gemfile
|
41
|
+
gemfile = ENV["BUNDLE_GEMFILE"]
|
42
|
+
return gemfile if gemfile && !gemfile.empty?
|
43
|
+
|
44
|
+
File.expand_path("../Gemfile", __dir__)
|
45
|
+
end
|
46
|
+
|
47
|
+
def lockfile
|
48
|
+
lockfile =
|
49
|
+
case File.basename(gemfile)
|
50
|
+
when "gems.rb" then gemfile.sub(/\.rb$/, ".locked")
|
51
|
+
else "#{gemfile}.lock"
|
52
|
+
end
|
53
|
+
File.expand_path(lockfile)
|
54
|
+
end
|
55
|
+
|
56
|
+
def lockfile_version
|
57
|
+
return unless File.file?(lockfile)
|
58
|
+
lockfile_contents = File.read(lockfile)
|
59
|
+
return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
|
60
|
+
Regexp.last_match(1)
|
61
|
+
end
|
62
|
+
|
63
|
+
def bundler_requirement
|
64
|
+
@bundler_requirement ||=
|
65
|
+
env_var_version ||
|
66
|
+
cli_arg_version ||
|
67
|
+
bundler_requirement_for(lockfile_version)
|
68
|
+
end
|
69
|
+
|
70
|
+
def bundler_requirement_for(version)
|
71
|
+
return "#{Gem::Requirement.default}.a" unless version
|
72
|
+
|
73
|
+
bundler_gem_version = Gem::Version.new(version)
|
74
|
+
|
75
|
+
bundler_gem_version.approximate_recommendation
|
76
|
+
end
|
77
|
+
|
78
|
+
def load_bundler!
|
79
|
+
ENV["BUNDLE_GEMFILE"] ||= gemfile
|
80
|
+
|
81
|
+
activate_bundler
|
82
|
+
end
|
83
|
+
|
84
|
+
def activate_bundler
|
85
|
+
gem_error = activation_error_handling do
|
86
|
+
gem "bundler", bundler_requirement
|
87
|
+
end
|
88
|
+
return if gem_error.nil?
|
89
|
+
require_error = activation_error_handling do
|
90
|
+
require "bundler/version"
|
91
|
+
end
|
92
|
+
return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
|
93
|
+
warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
|
94
|
+
exit 42
|
95
|
+
end
|
96
|
+
|
97
|
+
def activation_error_handling
|
98
|
+
yield
|
99
|
+
nil
|
100
|
+
rescue StandardError, LoadError => e
|
101
|
+
e
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
m.load_bundler!
|
106
|
+
|
107
|
+
if m.invoked_as_script?
|
108
|
+
load Gem.bin_path("bundler", "bundle")
|
109
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "fileutils"
|
3
|
+
|
4
|
+
# path to your application root.
|
5
|
+
APP_ROOT = File.expand_path("..", __dir__)
|
6
|
+
|
7
|
+
def system!(*args)
|
8
|
+
system(*args) || abort("\n== Command #{args} failed ==")
|
9
|
+
end
|
10
|
+
|
11
|
+
FileUtils.chdir APP_ROOT do
|
12
|
+
# This script is a way to set up or update your development environment automatically.
|
13
|
+
# This script is idempotent, so that you can run it at any time and get an expectable outcome.
|
14
|
+
# Add necessary setup steps to this file.
|
15
|
+
|
16
|
+
puts "== Installing dependencies =="
|
17
|
+
system! "gem install bundler --conservative"
|
18
|
+
system("bundle check") || system!("bundle install")
|
19
|
+
|
20
|
+
# puts "\n== Copying sample files =="
|
21
|
+
# unless File.exist?("config/database.yml")
|
22
|
+
# FileUtils.cp "config/database.yml.sample", "config/database.yml"
|
23
|
+
# end
|
24
|
+
|
25
|
+
puts "\n== Preparing database =="
|
26
|
+
system! "bin/rails db:prepare"
|
27
|
+
|
28
|
+
puts "\n== Removing old logs and tempfiles =="
|
29
|
+
system! "bin/rails log:clear tmp:clear"
|
30
|
+
|
31
|
+
puts "\n== Restarting application server =="
|
32
|
+
system! "bin/rails restart"
|
33
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
ORM = (ENV['ORM'] || 'active_record')
|
2
|
+
|
3
|
+
require "rails"
|
4
|
+
|
5
|
+
Bundler.require :default, ORM
|
6
|
+
|
7
|
+
require "action_controller/railtie"
|
8
|
+
|
9
|
+
require "#{ORM}/railtie"
|
10
|
+
require "action_mailer/railtie"
|
11
|
+
require 'devise-argon2'
|
12
|
+
|
13
|
+
# Require the gems listed in Gemfile, including any gems
|
14
|
+
# you've limited to :test, :development, or :production.
|
15
|
+
Bundler.require(*Rails.groups)
|
16
|
+
|
17
|
+
module DummyRailsApp
|
18
|
+
class Application < Rails::Application
|
19
|
+
config.load_defaults Rails.version.match(/^\d.\d/)[0]
|
20
|
+
config.eager_load = false
|
21
|
+
config.autoload_paths.reject!{ |p| p =~ /\/app\/(\w+)$/ && !%w(controllers helpers mailers views).include?($1) }
|
22
|
+
config.autoload_paths += ["#{config.root}/app/#{ORM}"]
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# SQLite. Versions 3.8.0 and up are supported.
|
2
|
+
# gem install sqlite3
|
3
|
+
#
|
4
|
+
# Ensure the SQLite 3 gem is defined in your Gemfile
|
5
|
+
# gem "sqlite3"
|
6
|
+
#
|
7
|
+
default: &default
|
8
|
+
adapter: sqlite3
|
9
|
+
pool: 5
|
10
|
+
timeout: 5000
|
11
|
+
|
12
|
+
test:
|
13
|
+
<<: *default
|
14
|
+
database: db/test.sqlite3
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class DeviseCreateUsers < ActiveRecord::Migration[6.0]
|
4
|
+
def change
|
5
|
+
create_table :users do |t|
|
6
|
+
## Database authenticatable
|
7
|
+
t.string :email, null: false, default: ""
|
8
|
+
t.string :encrypted_password, null: false, default: ""
|
9
|
+
|
10
|
+
t.timestamps null: false
|
11
|
+
end
|
12
|
+
|
13
|
+
add_index :users, :email, unique: true
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class DeviseCreateOldUsers < ActiveRecord::Migration[7.0]
|
4
|
+
def change
|
5
|
+
create_table :old_users do |t|
|
6
|
+
## Database authenticatable
|
7
|
+
t.string :email, null: false, default: ""
|
8
|
+
t.string :encrypted_password, null: false, default: ""
|
9
|
+
|
10
|
+
t.string :password_salt
|
11
|
+
|
12
|
+
t.timestamps null: false
|
13
|
+
end
|
14
|
+
|
15
|
+
add_index :old_users, :email, unique: true
|
16
|
+
end
|
17
|
+
end
|