rodauth 1.22.0 → 1.23.0
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/CHANGELOG +12 -0
- data/README.rdoc +5 -3
- data/doc/email_base.rdoc +1 -0
- data/doc/release_notes/1.23.0.txt +32 -0
- data/lib/rodauth.rb +5 -2
- data/lib/rodauth/features/base.rb +8 -0
- data/lib/rodauth/features/change_password_notify.rb +1 -1
- data/lib/rodauth/features/create_account.rb +1 -1
- data/lib/rodauth/features/email_auth.rb +3 -4
- data/lib/rodauth/features/email_base.rb +7 -2
- data/lib/rodauth/features/lockout.rb +1 -1
- data/lib/rodauth/features/login.rb +6 -2
- data/lib/rodauth/features/otp.rb +6 -3
- data/lib/rodauth/features/password_expiration.rb +1 -1
- data/lib/rodauth/features/recovery_codes.rb +3 -3
- data/lib/rodauth/features/reset_password.rb +2 -2
- data/lib/rodauth/features/sms_codes.rb +5 -5
- data/lib/rodauth/features/verify_account.rb +2 -2
- data/lib/rodauth/features/verify_login_change.rb +1 -1
- data/lib/rodauth/version.rb +1 -1
- data/templates/email-auth-request-form.str +2 -2
- data/templates/reset-password-request.str +3 -3
- data/templates/unlock-account-request.str +3 -3
- data/templates/verify-account-resend.str +3 -3
- metadata +5 -43
- data/Rakefile +0 -179
- data/spec/account_expiration_spec.rb +0 -225
- data/spec/all.rb +0 -1
- data/spec/change_login_spec.rb +0 -156
- data/spec/change_password_notify_spec.rb +0 -33
- data/spec/change_password_spec.rb +0 -202
- data/spec/close_account_spec.rb +0 -162
- data/spec/confirm_password_spec.rb +0 -70
- data/spec/create_account_spec.rb +0 -127
- data/spec/disallow_common_passwords_spec.rb +0 -93
- data/spec/disallow_password_reuse_spec.rb +0 -179
- data/spec/email_auth_spec.rb +0 -285
- data/spec/http_basic_auth_spec.rb +0 -143
- data/spec/jwt_cors_spec.rb +0 -57
- data/spec/jwt_refresh_spec.rb +0 -256
- data/spec/jwt_spec.rb +0 -235
- data/spec/lockout_spec.rb +0 -250
- data/spec/login_spec.rb +0 -328
- data/spec/migrate/001_tables.rb +0 -184
- data/spec/migrate/002_account_password_hash_column.rb +0 -11
- data/spec/migrate_password/001_tables.rb +0 -73
- data/spec/migrate_travis/001_tables.rb +0 -141
- data/spec/password_complexity_spec.rb +0 -109
- data/spec/password_expiration_spec.rb +0 -244
- data/spec/password_grace_period_spec.rb +0 -93
- data/spec/remember_spec.rb +0 -451
- data/spec/reset_password_spec.rb +0 -229
- data/spec/rodauth_spec.rb +0 -343
- data/spec/session_expiration_spec.rb +0 -58
- data/spec/single_session_spec.rb +0 -127
- data/spec/spec_helper.rb +0 -327
- data/spec/two_factor_spec.rb +0 -1462
- data/spec/update_password_hash_spec.rb +0 -40
- data/spec/verify_account_grace_period_spec.rb +0 -171
- data/spec/verify_account_spec.rb +0 -240
- data/spec/verify_change_login_spec.rb +0 -46
- data/spec/verify_login_change_spec.rb +0 -232
- data/spec/views/layout-other.str +0 -11
- data/spec/views/layout.str +0 -11
- data/spec/views/login.str +0 -21
@@ -1,73 +0,0 @@
|
|
1
|
-
require 'rodauth/migrations'
|
2
|
-
|
3
|
-
Sequel.migration do
|
4
|
-
up do
|
5
|
-
create_table(:account_password_hashes) do
|
6
|
-
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
7
|
-
String :password_hash, :null=>false
|
8
|
-
end
|
9
|
-
Rodauth.create_database_authentication_functions(self)
|
10
|
-
case database_type
|
11
|
-
when :postgres
|
12
|
-
user = get(Sequel.lit('current_user')).sub(/_password\z/, '')
|
13
|
-
run "REVOKE ALL ON account_password_hashes FROM public"
|
14
|
-
run "REVOKE ALL ON FUNCTION rodauth_get_salt(int8) FROM public"
|
15
|
-
run "REVOKE ALL ON FUNCTION rodauth_valid_password_hash(int8, text) FROM public"
|
16
|
-
run "GRANT INSERT, UPDATE, DELETE ON account_password_hashes TO #{user}"
|
17
|
-
run "GRANT SELECT(id) ON account_password_hashes TO #{user}"
|
18
|
-
run "GRANT EXECUTE ON FUNCTION rodauth_get_salt(int8) TO #{user}"
|
19
|
-
run "GRANT EXECUTE ON FUNCTION rodauth_valid_password_hash(int8, text) TO #{user}"
|
20
|
-
when :mysql
|
21
|
-
user = get(Sequel.lit('current_user')).sub(/_password@/, '@')
|
22
|
-
db_name = get(Sequel.function(:database))
|
23
|
-
run "GRANT EXECUTE ON #{db_name}.* TO #{user}"
|
24
|
-
run "GRANT INSERT, UPDATE, DELETE ON account_password_hashes TO #{user}"
|
25
|
-
run "GRANT SELECT (id) ON account_password_hashes TO #{user}"
|
26
|
-
when :mssql
|
27
|
-
user = get(Sequel.function(:DB_NAME))
|
28
|
-
run "GRANT EXECUTE ON rodauth_get_salt TO #{user}"
|
29
|
-
run "GRANT EXECUTE ON rodauth_valid_password_hash TO #{user}"
|
30
|
-
run "GRANT INSERT, UPDATE, DELETE ON account_password_hashes TO #{user}"
|
31
|
-
run "GRANT SELECT ON account_password_hashes(id) TO #{user}"
|
32
|
-
end
|
33
|
-
|
34
|
-
# Used by the disallow_password_reuse feature
|
35
|
-
create_table(:account_previous_password_hashes) do
|
36
|
-
primary_key :id, :type=>:Bignum
|
37
|
-
foreign_key :account_id, :accounts, :type=>:Bignum
|
38
|
-
String :password_hash, :null=>false
|
39
|
-
end
|
40
|
-
Rodauth.create_database_previous_password_check_functions(self)
|
41
|
-
|
42
|
-
case database_type
|
43
|
-
when :postgres
|
44
|
-
user = get(Sequel.lit('current_user')).sub(/_password\z/, '')
|
45
|
-
run "REVOKE ALL ON account_previous_password_hashes FROM public"
|
46
|
-
run "REVOKE ALL ON FUNCTION rodauth_get_previous_salt(int8) FROM public"
|
47
|
-
run "REVOKE ALL ON FUNCTION rodauth_previous_password_hash_match(int8, text) FROM public"
|
48
|
-
run "GRANT INSERT, UPDATE, DELETE ON account_previous_password_hashes TO #{user}"
|
49
|
-
run "GRANT SELECT(id, account_id) ON account_previous_password_hashes TO #{user}"
|
50
|
-
run "GRANT USAGE ON account_previous_password_hashes_id_seq TO #{user}"
|
51
|
-
run "GRANT EXECUTE ON FUNCTION rodauth_get_previous_salt(int8) TO #{user}"
|
52
|
-
run "GRANT EXECUTE ON FUNCTION rodauth_previous_password_hash_match(int8, text) TO #{user}"
|
53
|
-
when :mysql
|
54
|
-
user = get(Sequel.lit('current_user')).sub(/_password@/, '@')
|
55
|
-
db_name = get(Sequel.function(:database))
|
56
|
-
run "GRANT EXECUTE ON #{db_name}.* TO #{user}"
|
57
|
-
run "GRANT INSERT, UPDATE, DELETE ON account_previous_password_hashes TO #{user}"
|
58
|
-
run "GRANT SELECT (id, account_id) ON account_previous_password_hashes TO #{user}"
|
59
|
-
when :mssql
|
60
|
-
user = get(Sequel.function(:DB_NAME))
|
61
|
-
run "GRANT EXECUTE ON rodauth_get_previous_salt TO #{user}"
|
62
|
-
run "GRANT EXECUTE ON rodauth_previous_password_hash_match TO #{user}"
|
63
|
-
run "GRANT INSERT, UPDATE, DELETE ON account_previous_password_hashes TO #{user}"
|
64
|
-
run "GRANT SELECT ON account_previous_password_hashes(id, account_id) TO #{user}"
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
down do
|
69
|
-
Rodauth.drop_database_previous_password_check_functions(self)
|
70
|
-
Rodauth.drop_database_authentication_functions(self)
|
71
|
-
drop_table(:account_previous_password_hashes, :account_password_hashes)
|
72
|
-
end
|
73
|
-
end
|
@@ -1,141 +0,0 @@
|
|
1
|
-
require 'rodauth/migrations'
|
2
|
-
|
3
|
-
Sequel.migration do
|
4
|
-
up do
|
5
|
-
extension :date_arithmetic
|
6
|
-
|
7
|
-
create_table(:account_statuses) do
|
8
|
-
Integer :id, :primary_key=>true
|
9
|
-
String :name, :null=>false, :unique=>true
|
10
|
-
end
|
11
|
-
from(:account_statuses).import([:id, :name], [[1, 'Unverified'], [2, 'Verified'], [3, 'Closed']])
|
12
|
-
|
13
|
-
db = self
|
14
|
-
create_table(:accounts) do
|
15
|
-
primary_key :id, :type=>:Bignum
|
16
|
-
foreign_key :status_id, :account_statuses, :null=>false, :default=>1
|
17
|
-
if db.database_type == :postgres
|
18
|
-
citext :email, :null=>false
|
19
|
-
constraint :valid_email, :email=>/^[^,;@ \r\n]+@[^,@; \r\n]+\.[^,@; \r\n]+$/
|
20
|
-
index :email, :unique=>true, :where=>{:status_id=>[1, 2]}
|
21
|
-
else
|
22
|
-
String :email, :null=>false
|
23
|
-
index :email, :unique=>true
|
24
|
-
end
|
25
|
-
|
26
|
-
String :ph
|
27
|
-
end
|
28
|
-
|
29
|
-
create_table(:account_password_hashes) do
|
30
|
-
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
31
|
-
String :password_hash, :null=>false
|
32
|
-
end
|
33
|
-
Rodauth.create_database_authentication_functions(self)
|
34
|
-
|
35
|
-
deadline_opts = proc do |days|
|
36
|
-
if database_type == :mysql
|
37
|
-
{:null=>false}
|
38
|
-
else
|
39
|
-
{:null=>false, :default=>Sequel.date_add(Sequel::CURRENT_TIMESTAMP, :days=>days)}
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
create_table(:account_password_reset_keys) do
|
44
|
-
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
45
|
-
String :key, :null=>false
|
46
|
-
DateTime :deadline, deadline_opts[1]
|
47
|
-
DateTime :email_last_sent, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
|
48
|
-
end
|
49
|
-
|
50
|
-
# Used by the refresh token feature
|
51
|
-
create_table(:account_jwt_refresh_keys) do
|
52
|
-
primary_key :id, :type=>:Bignum
|
53
|
-
foreign_key :account_id, :accounts, :type=>:Bignum
|
54
|
-
String :key, :null=>false
|
55
|
-
DateTime :deadline, deadline_opts[1]
|
56
|
-
end
|
57
|
-
|
58
|
-
create_table(:account_verification_keys) do
|
59
|
-
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
60
|
-
String :key, :null=>false
|
61
|
-
DateTime :requested_at, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
|
62
|
-
DateTime :email_last_sent, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
|
63
|
-
end
|
64
|
-
|
65
|
-
create_table(:account_login_change_keys) do
|
66
|
-
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
67
|
-
String :key, :null=>false
|
68
|
-
String :login, :null=>false
|
69
|
-
DateTime :deadline, deadline_opts[1]
|
70
|
-
end
|
71
|
-
|
72
|
-
create_table(:account_remember_keys) do
|
73
|
-
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
74
|
-
String :key, :null=>false
|
75
|
-
DateTime :deadline, deadline_opts[14]
|
76
|
-
end
|
77
|
-
|
78
|
-
create_table(:account_email_auth_keys) do
|
79
|
-
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
80
|
-
String :key, :null=>false
|
81
|
-
DateTime :deadline, deadline_opts[1]
|
82
|
-
DateTime :email_last_sent, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
|
83
|
-
end
|
84
|
-
|
85
|
-
create_table(:account_login_failures) do
|
86
|
-
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
87
|
-
Integer :number, :null=>false, :default=>1
|
88
|
-
end
|
89
|
-
create_table(:account_lockouts) do
|
90
|
-
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
91
|
-
String :key, :null=>false
|
92
|
-
DateTime :deadline, deadline_opts[1]
|
93
|
-
DateTime :email_last_sent
|
94
|
-
end
|
95
|
-
|
96
|
-
create_table(:account_password_change_times) do
|
97
|
-
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
98
|
-
DateTime :changed_at, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
|
99
|
-
end
|
100
|
-
|
101
|
-
create_table(:account_activity_times) do
|
102
|
-
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
103
|
-
DateTime :last_activity_at, :null=>false
|
104
|
-
DateTime :last_login_at, :null=>false
|
105
|
-
DateTime :expired_at
|
106
|
-
end
|
107
|
-
|
108
|
-
create_table(:account_session_keys) do
|
109
|
-
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
110
|
-
String :key, :null=>false
|
111
|
-
end
|
112
|
-
|
113
|
-
create_table(:account_otp_keys) do
|
114
|
-
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
115
|
-
String :key, :null=>false
|
116
|
-
Integer :num_failures, :null=>false, :default=>0
|
117
|
-
Time :last_use, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
|
118
|
-
end
|
119
|
-
|
120
|
-
create_table(:account_recovery_codes) do
|
121
|
-
foreign_key :id, :accounts, :type=>:Bignum
|
122
|
-
String :code
|
123
|
-
primary_key [:id, :code]
|
124
|
-
end
|
125
|
-
|
126
|
-
create_table(:account_sms_codes) do
|
127
|
-
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
128
|
-
String :phone_number, :null=>false
|
129
|
-
Integer :num_failures
|
130
|
-
String :code
|
131
|
-
DateTime :code_issued_at, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
|
132
|
-
end
|
133
|
-
|
134
|
-
create_table(:account_previous_password_hashes) do
|
135
|
-
primary_key :id, :type=>:Bignum
|
136
|
-
foreign_key :account_id, :accounts, :type=>:Bignum
|
137
|
-
String :password_hash, :null=>false
|
138
|
-
end
|
139
|
-
Rodauth.create_database_previous_password_check_functions(self)
|
140
|
-
end
|
141
|
-
end
|
@@ -1,109 +0,0 @@
|
|
1
|
-
require File.expand_path("spec_helper", File.dirname(__FILE__))
|
2
|
-
|
3
|
-
describe 'Rodauth password complexity feature' do
|
4
|
-
it "should do additional password complexity checks" do
|
5
|
-
rodauth do
|
6
|
-
enable :login, :change_password, :password_complexity
|
7
|
-
change_password_requires_password? false
|
8
|
-
password_dictionary_file 'spec/words'
|
9
|
-
end
|
10
|
-
roda do |r|
|
11
|
-
r.rodauth
|
12
|
-
r.root{view :content=>""}
|
13
|
-
end
|
14
|
-
|
15
|
-
login
|
16
|
-
page.current_path.must_equal '/'
|
17
|
-
|
18
|
-
visit '/change-password'
|
19
|
-
|
20
|
-
bad_passwords = [
|
21
|
-
["minimum 6 characters", %w"a1OX"],
|
22
|
-
["does not include uppercase letters, lowercase letters, and numbers",
|
23
|
-
%w'sdflksdfl sdflks!fl Sdflksdfl dfl1sdfl DFL1SDFL DFL!SDFL'],
|
24
|
-
["includes common character sequence",
|
25
|
-
%w"Aqwerty12 Aazerty12 HA123ha HA234ha HA345ha HA456ha HA567ha HA678ha HA789ha HA890ha"],
|
26
|
-
["contains 3 or more of the same character in a row", %w"Helll0 Hellllll0"],
|
27
|
-
["is a word in a dictionary",
|
28
|
-
%w"Password1 1Password1 1PaSSword1 1P@$5w0Rd1 2398|3@$+7809 2|!7+1e l4$7$124 N!88|e56"]
|
29
|
-
]
|
30
|
-
|
31
|
-
|
32
|
-
bad_passwords.each do |message, passwords|
|
33
|
-
passwords.each do |pass|
|
34
|
-
fill_in 'New Password', :with=>pass
|
35
|
-
fill_in 'Confirm Password', :with=>pass
|
36
|
-
click_button 'Change Password'
|
37
|
-
page.html.must_include("invalid password, does not meet requirements (#{message})")
|
38
|
-
page.find('#error_flash').text.must_equal "There was an error changing your password"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
fill_in 'New Password', :with=>'footpassword'
|
43
|
-
fill_in 'Confirm Password', :with=>'footpassword'
|
44
|
-
click_button 'Change Password'
|
45
|
-
page.find('#notice_flash').text.must_equal "Your password has been changed"
|
46
|
-
end
|
47
|
-
|
48
|
-
it "should support default dictionary" do
|
49
|
-
default_dictionary = '/usr/share/dict/words'
|
50
|
-
skip("#{default_dictionary} not present") unless File.file?(default_dictionary)
|
51
|
-
pass = File.read(default_dictionary).split.sort_by{|w| w.length}.last
|
52
|
-
skip("#{default_dictionary} empty") unless pass
|
53
|
-
pass = pass.downcase.gsub(/[^a-z]/, '')
|
54
|
-
|
55
|
-
rodauth do
|
56
|
-
enable :login, :change_password, :password_complexity
|
57
|
-
change_password_requires_password? false
|
58
|
-
end
|
59
|
-
roda do |r|
|
60
|
-
r.rodauth
|
61
|
-
r.root{view :content=>""}
|
62
|
-
end
|
63
|
-
|
64
|
-
login
|
65
|
-
page.current_path.must_equal '/'
|
66
|
-
|
67
|
-
visit '/change-password'
|
68
|
-
fill_in 'New Password', :with=>"135#{pass}135"
|
69
|
-
fill_in 'Confirm Password', :with=>"135#{pass}135"
|
70
|
-
click_button 'Change Password'
|
71
|
-
page.html.must_include("invalid password")
|
72
|
-
page.find('#error_flash').text.must_equal "There was an error changing your password"
|
73
|
-
|
74
|
-
fill_in 'New Password', :with=>'footpassword'
|
75
|
-
fill_in 'Confirm Password', :with=>'footpassword'
|
76
|
-
click_button 'Change Password'
|
77
|
-
page.find('#notice_flash').text.must_equal "Your password has been changed"
|
78
|
-
end
|
79
|
-
|
80
|
-
it "should support no dictionary" do
|
81
|
-
default_dictionary = '/usr/share/dict/words'
|
82
|
-
skip("#{default_dictionary} not present") unless File.file?(default_dictionary)
|
83
|
-
|
84
|
-
rodauth do
|
85
|
-
enable :login, :change_password, :password_complexity
|
86
|
-
change_password_requires_password? false
|
87
|
-
password_dictionary_file false
|
88
|
-
end
|
89
|
-
roda do |r|
|
90
|
-
r.rodauth
|
91
|
-
r.root{view :content=>""}
|
92
|
-
end
|
93
|
-
|
94
|
-
login
|
95
|
-
page.current_path.must_equal '/'
|
96
|
-
|
97
|
-
visit '/change-password'
|
98
|
-
fill_in 'New Password', :with=>"password123"
|
99
|
-
fill_in 'Confirm Password', :with=>"password123"
|
100
|
-
click_button 'Change Password'
|
101
|
-
page.html.must_include("invalid password")
|
102
|
-
page.find('#error_flash').text.must_equal "There was an error changing your password"
|
103
|
-
|
104
|
-
fill_in 'New Password', :with=>'Password1'
|
105
|
-
fill_in 'Confirm Password', :with=>'Password1'
|
106
|
-
click_button 'Change Password'
|
107
|
-
page.find('#notice_flash').text.must_equal "Your password has been changed"
|
108
|
-
end
|
109
|
-
end
|
@@ -1,244 +0,0 @@
|
|
1
|
-
require File.expand_path("spec_helper", File.dirname(__FILE__))
|
2
|
-
|
3
|
-
describe 'Rodauth password expiration feature' do
|
4
|
-
it "should force password changes after x number of days" do
|
5
|
-
rodauth do
|
6
|
-
enable :login, :logout, :change_password, :reset_password, :password_expiration
|
7
|
-
allow_password_change_after 1000
|
8
|
-
change_password_requires_password? false
|
9
|
-
end
|
10
|
-
roda do |r|
|
11
|
-
r.rodauth
|
12
|
-
rodauth.require_current_password if rodauth.logged_in?
|
13
|
-
r.root{view :content=>""}
|
14
|
-
end
|
15
|
-
|
16
|
-
login(:pass=>'01234567')
|
17
|
-
click_button 'Request Password Reset'
|
18
|
-
link = email_link(/(\/reset-password\?key=.+)$/)
|
19
|
-
|
20
|
-
visit link
|
21
|
-
page.current_path.must_equal '/reset-password'
|
22
|
-
|
23
|
-
login
|
24
|
-
page.current_path.must_equal '/'
|
25
|
-
|
26
|
-
visit '/change-password'
|
27
|
-
fill_in 'New Password', :with=>'banana'
|
28
|
-
fill_in 'Confirm Password', :with=>'banana'
|
29
|
-
click_button 'Change Password'
|
30
|
-
page.current_path.must_equal '/'
|
31
|
-
|
32
|
-
visit '/change-password'
|
33
|
-
page.current_path.must_equal '/'
|
34
|
-
page.find('#error_flash').text.must_equal "Your password cannot be changed yet"
|
35
|
-
|
36
|
-
logout
|
37
|
-
|
38
|
-
visit link
|
39
|
-
page.current_path.must_equal '/'
|
40
|
-
page.find('#error_flash').text.must_equal "Your password cannot be changed yet"
|
41
|
-
|
42
|
-
DB[:account_password_change_times].update(:changed_at=>Time.now - 1100)
|
43
|
-
|
44
|
-
visit link
|
45
|
-
page.current_path.must_equal '/reset-password'
|
46
|
-
|
47
|
-
login(:pass=>'banana')
|
48
|
-
page.current_path.must_equal '/'
|
49
|
-
|
50
|
-
visit '/change-password'
|
51
|
-
page.current_path.must_equal '/change-password'
|
52
|
-
|
53
|
-
logout
|
54
|
-
|
55
|
-
DB[:account_password_change_times].update(:changed_at=>Time.now - 91*86400)
|
56
|
-
|
57
|
-
login(:pass=>'banana')
|
58
|
-
page.current_path.must_equal '/change-password'
|
59
|
-
page.find('#error_flash').text.must_equal "Your password has expired and needs to be changed"
|
60
|
-
|
61
|
-
visit '/foo'
|
62
|
-
page.current_path.must_equal '/change-password'
|
63
|
-
page.find('#error_flash').text.must_equal "Your password has expired and needs to be changed"
|
64
|
-
|
65
|
-
fill_in 'New Password', :with=>'banana2'
|
66
|
-
fill_in 'Confirm Password', :with=>'banana2'
|
67
|
-
click_button 'Change Password'
|
68
|
-
page.current_path.must_equal '/'
|
69
|
-
|
70
|
-
visit '/change-password'
|
71
|
-
page.current_path.must_equal '/'
|
72
|
-
page.find('#error_flash').text.must_equal "Your password cannot be changed yet"
|
73
|
-
|
74
|
-
logout
|
75
|
-
|
76
|
-
visit link
|
77
|
-
page.current_path.must_equal '/'
|
78
|
-
page.find('#error_flash').text.must_equal "Your password cannot be changed yet"
|
79
|
-
end
|
80
|
-
|
81
|
-
it "should update password changed at when creating accounts" do
|
82
|
-
rodauth do
|
83
|
-
enable :login, :change_password, :password_expiration
|
84
|
-
password_expiration_default true
|
85
|
-
change_password_requires_password? false
|
86
|
-
end
|
87
|
-
roda do |r|
|
88
|
-
r.rodauth
|
89
|
-
rodauth.require_current_password
|
90
|
-
r.root{view :content=>""}
|
91
|
-
end
|
92
|
-
|
93
|
-
login
|
94
|
-
page.current_path.must_equal '/change-password'
|
95
|
-
|
96
|
-
visit '/'
|
97
|
-
page.current_path.must_equal '/change-password'
|
98
|
-
fill_in 'New Password', :with=>'banana'
|
99
|
-
fill_in 'Confirm Password', :with=>'banana'
|
100
|
-
click_button 'Change Password'
|
101
|
-
page.current_path.must_equal '/'
|
102
|
-
end
|
103
|
-
|
104
|
-
it "should update password changed at when creating accounts" do
|
105
|
-
rodauth do
|
106
|
-
enable :login, :create_account, :password_expiration
|
107
|
-
allow_password_change_after 1000
|
108
|
-
account_password_hash_column :ph
|
109
|
-
end
|
110
|
-
roda do |r|
|
111
|
-
r.rodauth
|
112
|
-
r.root{view :content=>""}
|
113
|
-
end
|
114
|
-
|
115
|
-
visit '/create-account'
|
116
|
-
fill_in 'Login', :with=>'foo2@example.com'
|
117
|
-
fill_in 'Confirm Login', :with=>'foo2@example.com'
|
118
|
-
fill_in 'Password', :with=>'apple2'
|
119
|
-
fill_in 'Confirm Password', :with=>'apple2'
|
120
|
-
click_button 'Create Account'
|
121
|
-
|
122
|
-
visit '/change-password'
|
123
|
-
page.current_path.must_equal '/'
|
124
|
-
page.find('#error_flash').text.must_equal "Your password cannot be changed yet"
|
125
|
-
end
|
126
|
-
|
127
|
-
it "should remove password expiration data when closing accounts" do
|
128
|
-
rodauth do
|
129
|
-
enable :create_account, :close_account, :password_expiration
|
130
|
-
close_account_requires_password? false
|
131
|
-
create_account_autologin? true
|
132
|
-
end
|
133
|
-
roda do |r|
|
134
|
-
r.rodauth
|
135
|
-
r.root{view :content=>""}
|
136
|
-
end
|
137
|
-
|
138
|
-
visit '/create-account'
|
139
|
-
fill_in 'Login', :with=>'foo2@example.com'
|
140
|
-
fill_in 'Confirm Login', :with=>'foo2@example.com'
|
141
|
-
fill_in 'Password', :with=>'apple2'
|
142
|
-
fill_in 'Confirm Password', :with=>'apple2'
|
143
|
-
click_button 'Create Account'
|
144
|
-
|
145
|
-
DB[:account_password_change_times].count.must_equal 1
|
146
|
-
visit '/close-account'
|
147
|
-
click_button 'Close Account'
|
148
|
-
DB[:account_password_change_times].count.must_equal 0
|
149
|
-
end
|
150
|
-
|
151
|
-
it "should handle the case where the password is expired while the user has logged in" do
|
152
|
-
rodauth do
|
153
|
-
enable :login, :change_password, :password_expiration
|
154
|
-
password_expiration_default true
|
155
|
-
allow_password_change_after(-1000)
|
156
|
-
change_password_requires_password? false
|
157
|
-
require_password_change_after 3600
|
158
|
-
end
|
159
|
-
roda do |r|
|
160
|
-
r.rodauth
|
161
|
-
rodauth.require_current_password
|
162
|
-
r.get("expire", :d){|d| session[:password_changed_at] = Time.now.to_i - d.to_i; r.redirect '/'}
|
163
|
-
r.root{view :content=>""}
|
164
|
-
end
|
165
|
-
|
166
|
-
login
|
167
|
-
page.current_path.must_equal '/change-password'
|
168
|
-
|
169
|
-
visit '/'
|
170
|
-
page.current_path.must_equal '/change-password'
|
171
|
-
fill_in 'New Password', :with=>'banana'
|
172
|
-
fill_in 'Confirm Password', :with=>'banana'
|
173
|
-
click_button 'Change Password'
|
174
|
-
page.current_path.must_equal '/'
|
175
|
-
|
176
|
-
visit "/expire/90"
|
177
|
-
page.current_path.must_equal '/'
|
178
|
-
|
179
|
-
visit "/expire/7200"
|
180
|
-
page.current_path.must_equal '/change-password'
|
181
|
-
end
|
182
|
-
|
183
|
-
it "should force password changes via jwt" do
|
184
|
-
rodauth do
|
185
|
-
enable :login, :logout, :change_password, :reset_password, :password_expiration
|
186
|
-
allow_password_change_after 1000
|
187
|
-
change_password_requires_password? false
|
188
|
-
reset_password_email_body{reset_password_email_link}
|
189
|
-
end
|
190
|
-
roda(:jwt) do |r|
|
191
|
-
r.rodauth
|
192
|
-
rodauth.require_current_password
|
193
|
-
if rodauth.authenticated?
|
194
|
-
[1]
|
195
|
-
else
|
196
|
-
[2]
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
json_request.must_equal [200, [2]]
|
201
|
-
|
202
|
-
res = json_request('/reset-password-request', :login=>'foo@example.com')
|
203
|
-
res.must_equal [200, {"success"=>"An email has been sent to you with a link to reset the password for your account"}]
|
204
|
-
link = email_link(/key=.+$/)
|
205
|
-
|
206
|
-
json_login
|
207
|
-
|
208
|
-
res = json_request('/change-password', :password=>'0123456789', "new-password"=>'0123456', "password-confirm"=>'0123456')
|
209
|
-
res.must_equal [200, {'success'=>"Your password has been changed"}]
|
210
|
-
|
211
|
-
json_request.must_equal [200, [1]]
|
212
|
-
|
213
|
-
res = json_request('/change-password', :password=>'0123456', "new-password"=>'01234567', "password-confirm"=>'01234567')
|
214
|
-
res.must_equal [400, {'error'=>"Your password cannot be changed yet"}]
|
215
|
-
|
216
|
-
json_logout
|
217
|
-
|
218
|
-
res = json_request('/reset-password', :key=>link[4..-1], :password=>'01234567', "password-confirm"=>'01234567')
|
219
|
-
res.must_equal [400, {'error'=>"Your password cannot be changed yet"}]
|
220
|
-
|
221
|
-
DB[:account_password_change_times].update(:changed_at=>Time.now - 1100)
|
222
|
-
res = json_request('/reset-password', :key=>link[4..-1], :password=>'01234567', "password-confirm"=>'01234567')
|
223
|
-
res.must_equal [200, {"success"=>"Your password has been reset"}]
|
224
|
-
|
225
|
-
DB[:account_password_change_times].update(:changed_at=>Time.now - 1100)
|
226
|
-
json_login(:pass=>'01234567')
|
227
|
-
res = json_request('/change-password', :password=>'01234567', "new-password"=>'012345678', "password-confirm"=>'012345678')
|
228
|
-
res.must_equal [200, {'success'=>"Your password has been changed"}]
|
229
|
-
|
230
|
-
DB[:account_password_change_times].update(:changed_at=>Time.now - 91*86400)
|
231
|
-
|
232
|
-
json_logout
|
233
|
-
json_request.must_equal [200, [2]]
|
234
|
-
|
235
|
-
res = json_login(:pass=>'012345678', :no_check=>true)
|
236
|
-
res.must_equal [400, {'error'=>"Your password has expired and needs to be changed"}]
|
237
|
-
json_request.must_equal [400, {'error'=>"Your password has expired and needs to be changed"}]
|
238
|
-
|
239
|
-
res = json_request('/change-password', :password=>'012345678', "new-password"=>'012345678a', "password-confirm"=>'012345678a')
|
240
|
-
res.must_equal [200, {'success'=>"Your password has been changed"}]
|
241
|
-
|
242
|
-
json_request.must_equal [200, [1]]
|
243
|
-
end
|
244
|
-
end
|