rodauth 1.21.0 → 2.2.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.
Files changed (200) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +182 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +211 -79
  5. data/doc/account_expiration.rdoc +12 -26
  6. data/doc/active_sessions.rdoc +49 -0
  7. data/doc/audit_logging.rdoc +44 -0
  8. data/doc/base.rdoc +75 -128
  9. data/doc/change_login.rdoc +7 -14
  10. data/doc/change_password.rdoc +9 -13
  11. data/doc/change_password_notify.rdoc +2 -2
  12. data/doc/close_account.rdoc +9 -16
  13. data/doc/confirm_password.rdoc +12 -5
  14. data/doc/create_account.rdoc +11 -22
  15. data/doc/disallow_password_reuse.rdoc +6 -13
  16. data/doc/email_auth.rdoc +15 -14
  17. data/doc/email_base.rdoc +6 -15
  18. data/doc/guides/admin_activation.rdoc +46 -0
  19. data/doc/guides/already_authenticated.rdoc +10 -0
  20. data/doc/guides/alternative_login.rdoc +46 -0
  21. data/doc/guides/create_account_programmatically.rdoc +38 -0
  22. data/doc/guides/delay_password.rdoc +25 -0
  23. data/doc/guides/email_only.rdoc +16 -0
  24. data/doc/guides/i18n.rdoc +26 -0
  25. data/doc/{internals.rdoc → guides/internals.rdoc} +0 -0
  26. data/doc/guides/links.rdoc +12 -0
  27. data/doc/guides/login_return.rdoc +37 -0
  28. data/doc/guides/password_column.rdoc +25 -0
  29. data/doc/guides/password_confirmation.rdoc +37 -0
  30. data/doc/guides/password_requirements.rdoc +30 -0
  31. data/doc/guides/paths.rdoc +36 -0
  32. data/doc/guides/query_params.rdoc +9 -0
  33. data/doc/guides/redirects.rdoc +17 -0
  34. data/doc/guides/registration_field.rdoc +68 -0
  35. data/doc/guides/require_mfa.rdoc +30 -0
  36. data/doc/guides/reset_password_autologin.rdoc +21 -0
  37. data/doc/guides/status_column.rdoc +28 -0
  38. data/doc/guides/totp_or_recovery.rdoc +16 -0
  39. data/doc/http_basic_auth.rdoc +10 -1
  40. data/doc/jwt.rdoc +22 -22
  41. data/doc/jwt_cors.rdoc +22 -0
  42. data/doc/jwt_refresh.rdoc +18 -8
  43. data/doc/lockout.rdoc +17 -15
  44. data/doc/login.rdoc +10 -2
  45. data/doc/login_password_requirements_base.rdoc +15 -37
  46. data/doc/logout.rdoc +2 -2
  47. data/doc/otp.rdoc +25 -19
  48. data/doc/password_complexity.rdoc +10 -26
  49. data/doc/password_expiration.rdoc +11 -25
  50. data/doc/password_grace_period.rdoc +16 -2
  51. data/doc/recovery_codes.rdoc +18 -12
  52. data/doc/release_notes/1.22.0.txt +11 -0
  53. data/doc/release_notes/1.23.0.txt +32 -0
  54. data/doc/release_notes/2.0.0.txt +361 -0
  55. data/doc/release_notes/2.1.0.txt +31 -0
  56. data/doc/release_notes/2.2.0.txt +39 -0
  57. data/doc/remember.rdoc +40 -64
  58. data/doc/reset_password.rdoc +12 -9
  59. data/doc/session_expiration.rdoc +1 -0
  60. data/doc/single_session.rdoc +16 -25
  61. data/doc/sms_codes.rdoc +24 -14
  62. data/doc/two_factor_base.rdoc +60 -22
  63. data/doc/verify_account.rdoc +14 -12
  64. data/doc/verify_account_grace_period.rdoc +6 -2
  65. data/doc/verify_login_change.rdoc +9 -8
  66. data/doc/webauthn.rdoc +115 -0
  67. data/doc/webauthn_login.rdoc +15 -0
  68. data/doc/webauthn_verify_account.rdoc +9 -0
  69. data/javascript/webauthn_auth.js +45 -0
  70. data/javascript/webauthn_setup.js +35 -0
  71. data/lib/roda/plugins/rodauth.rb +1 -1
  72. data/lib/rodauth.rb +36 -28
  73. data/lib/rodauth/features/account_expiration.rb +5 -5
  74. data/lib/rodauth/features/active_sessions.rb +158 -0
  75. data/lib/rodauth/features/audit_logging.rb +98 -0
  76. data/lib/rodauth/features/base.rb +144 -43
  77. data/lib/rodauth/features/change_password_notify.rb +2 -2
  78. data/lib/rodauth/features/confirm_password.rb +40 -2
  79. data/lib/rodauth/features/create_account.rb +8 -13
  80. data/lib/rodauth/features/disallow_common_passwords.rb +1 -1
  81. data/lib/rodauth/features/disallow_password_reuse.rb +1 -1
  82. data/lib/rodauth/features/email_auth.rb +31 -30
  83. data/lib/rodauth/features/email_base.rb +9 -4
  84. data/lib/rodauth/features/http_basic_auth.rb +55 -35
  85. data/lib/rodauth/features/jwt.rb +63 -16
  86. data/lib/rodauth/features/jwt_cors.rb +53 -0
  87. data/lib/rodauth/features/jwt_refresh.rb +32 -9
  88. data/lib/rodauth/features/lockout.rb +12 -14
  89. data/lib/rodauth/features/login.rb +54 -10
  90. data/lib/rodauth/features/login_password_requirements_base.rb +4 -4
  91. data/lib/rodauth/features/otp.rb +77 -80
  92. data/lib/rodauth/features/password_complexity.rb +8 -13
  93. data/lib/rodauth/features/password_expiration.rb +2 -2
  94. data/lib/rodauth/features/password_grace_period.rb +17 -10
  95. data/lib/rodauth/features/recovery_codes.rb +49 -53
  96. data/lib/rodauth/features/remember.rb +11 -27
  97. data/lib/rodauth/features/reset_password.rb +26 -26
  98. data/lib/rodauth/features/session_expiration.rb +6 -4
  99. data/lib/rodauth/features/single_session.rb +8 -6
  100. data/lib/rodauth/features/sms_codes.rb +62 -72
  101. data/lib/rodauth/features/two_factor_base.rb +134 -30
  102. data/lib/rodauth/features/verify_account.rb +29 -21
  103. data/lib/rodauth/features/verify_account_grace_period.rb +18 -9
  104. data/lib/rodauth/features/verify_login_change.rb +12 -11
  105. data/lib/rodauth/features/webauthn.rb +505 -0
  106. data/lib/rodauth/features/webauthn_login.rb +70 -0
  107. data/lib/rodauth/features/webauthn_verify_account.rb +46 -0
  108. data/lib/rodauth/version.rb +2 -2
  109. data/templates/button.str +1 -3
  110. data/templates/change-login.str +1 -2
  111. data/templates/change-password.str +3 -5
  112. data/templates/close-account.str +2 -2
  113. data/templates/confirm-password.str +1 -1
  114. data/templates/create-account.str +1 -1
  115. data/templates/email-auth-email.str +1 -1
  116. data/templates/email-auth-request-form.str +2 -3
  117. data/templates/email-auth.str +1 -1
  118. data/templates/global-logout-field.str +6 -0
  119. data/templates/login-confirm-field.str +2 -4
  120. data/templates/login-display.str +3 -2
  121. data/templates/login-field.str +2 -4
  122. data/templates/login-form-footer.str +6 -0
  123. data/templates/login-form.str +7 -0
  124. data/templates/login.str +1 -9
  125. data/templates/logout.str +1 -1
  126. data/templates/multi-phase-login.str +3 -0
  127. data/templates/otp-auth-code-field.str +5 -3
  128. data/templates/otp-auth.str +1 -1
  129. data/templates/otp-disable.str +1 -1
  130. data/templates/otp-setup.str +3 -3
  131. data/templates/password-confirm-field.str +2 -4
  132. data/templates/password-field.str +2 -4
  133. data/templates/recovery-auth.str +3 -6
  134. data/templates/recovery-codes.str +1 -1
  135. data/templates/remember.str +15 -20
  136. data/templates/reset-password-email.str +1 -1
  137. data/templates/reset-password-request.str +3 -3
  138. data/templates/reset-password.str +1 -2
  139. data/templates/sms-auth.str +1 -1
  140. data/templates/sms-code-field.str +5 -3
  141. data/templates/sms-confirm.str +1 -2
  142. data/templates/sms-disable.str +1 -2
  143. data/templates/sms-request.str +1 -1
  144. data/templates/sms-setup.str +6 -4
  145. data/templates/two-factor-auth.str +5 -0
  146. data/templates/two-factor-disable.str +6 -0
  147. data/templates/two-factor-manage.str +16 -0
  148. data/templates/unlock-account-email.str +1 -1
  149. data/templates/unlock-account-request.str +4 -4
  150. data/templates/unlock-account.str +1 -1
  151. data/templates/verify-account-email.str +1 -1
  152. data/templates/verify-account-resend.str +3 -3
  153. data/templates/verify-account.str +1 -2
  154. data/templates/verify-login-change-email.str +2 -1
  155. data/templates/verify-login-change.str +1 -1
  156. data/templates/webauthn-auth.str +11 -0
  157. data/templates/webauthn-remove.str +14 -0
  158. data/templates/webauthn-setup.str +12 -0
  159. metadata +110 -52
  160. data/Rakefile +0 -179
  161. data/doc/verify_change_login.rdoc +0 -11
  162. data/lib/rodauth/features/verify_change_login.rb +0 -20
  163. data/spec/account_expiration_spec.rb +0 -225
  164. data/spec/all.rb +0 -1
  165. data/spec/change_login_spec.rb +0 -156
  166. data/spec/change_password_notify_spec.rb +0 -33
  167. data/spec/change_password_spec.rb +0 -202
  168. data/spec/close_account_spec.rb +0 -162
  169. data/spec/confirm_password_spec.rb +0 -70
  170. data/spec/create_account_spec.rb +0 -127
  171. data/spec/disallow_common_passwords_spec.rb +0 -93
  172. data/spec/disallow_password_reuse_spec.rb +0 -179
  173. data/spec/email_auth_spec.rb +0 -285
  174. data/spec/http_basic_auth_spec.rb +0 -143
  175. data/spec/jwt_refresh_spec.rb +0 -256
  176. data/spec/jwt_spec.rb +0 -235
  177. data/spec/lockout_spec.rb +0 -250
  178. data/spec/login_spec.rb +0 -328
  179. data/spec/migrate/001_tables.rb +0 -184
  180. data/spec/migrate/002_account_password_hash_column.rb +0 -11
  181. data/spec/migrate_password/001_tables.rb +0 -73
  182. data/spec/migrate_travis/001_tables.rb +0 -141
  183. data/spec/password_complexity_spec.rb +0 -109
  184. data/spec/password_expiration_spec.rb +0 -244
  185. data/spec/password_grace_period_spec.rb +0 -93
  186. data/spec/remember_spec.rb +0 -451
  187. data/spec/reset_password_spec.rb +0 -229
  188. data/spec/rodauth_spec.rb +0 -343
  189. data/spec/session_expiration_spec.rb +0 -58
  190. data/spec/single_session_spec.rb +0 -127
  191. data/spec/spec_helper.rb +0 -327
  192. data/spec/two_factor_spec.rb +0 -1462
  193. data/spec/update_password_hash_spec.rb +0 -40
  194. data/spec/verify_account_grace_period_spec.rb +0 -171
  195. data/spec/verify_account_spec.rb +0 -240
  196. data/spec/verify_change_login_spec.rb +0 -46
  197. data/spec/verify_login_change_spec.rb +0 -232
  198. data/spec/views/layout-other.str +0 -11
  199. data/spec/views/layout.str +0 -11
  200. data/spec/views/login.str +0 -21
@@ -1,184 +0,0 @@
1
- Sequel.migration do
2
- up do
3
- extension :date_arithmetic
4
-
5
- # Used by the account verification and close account features
6
- create_table(:account_statuses) do
7
- Integer :id, :primary_key=>true
8
- String :name, :null=>false, :unique=>true
9
- end
10
- from(:account_statuses).import([:id, :name], [[1, 'Unverified'], [2, 'Verified'], [3, 'Closed']])
11
-
12
- db = self
13
- create_table(:accounts) do
14
- primary_key :id, :type=>:Bignum
15
- foreign_key :status_id, :account_statuses, :null=>false, :default=>1
16
- if db.database_type == :postgres
17
- citext :email, :null=>false
18
- constraint :valid_email, :email=>/^[^,;@ \r\n]+@[^,@; \r\n]+\.[^,@; \r\n]+$/
19
- index :email, :unique=>true, :where=>{:status_id=>[1, 2]}
20
- else
21
- String :email, :null=>false
22
- index :email, :unique=>true
23
- end
24
- end
25
-
26
- deadline_opts = proc do |days|
27
- if database_type == :mysql
28
- {:null=>false}
29
- else
30
- {:null=>false, :default=>Sequel.date_add(Sequel::CURRENT_TIMESTAMP, :days=>days)}
31
- end
32
- end
33
-
34
- # Used by the password reset feature
35
- create_table(:account_password_reset_keys) do
36
- foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
37
- String :key, :null=>false
38
- DateTime :deadline, deadline_opts[1]
39
- DateTime :email_last_sent, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
40
- end
41
-
42
- # Used by the refresh token feature
43
- create_table(:account_jwt_refresh_keys) do
44
- primary_key :id, :type=>:Bignum
45
- foreign_key :account_id, :accounts, :type=>:Bignum
46
- String :key, :null=>false
47
- DateTime :deadline, deadline_opts[1]
48
- end
49
-
50
- # Used by the account verification feature
51
- create_table(:account_verification_keys) do
52
- foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
53
- String :key, :null=>false
54
- DateTime :requested_at, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
55
- DateTime :email_last_sent, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
56
- end
57
-
58
- # Used by the verify login change feature
59
- create_table(:account_login_change_keys) do
60
- foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
61
- String :key, :null=>false
62
- String :login, :null=>false
63
- DateTime :deadline, deadline_opts[1]
64
- end
65
-
66
- # Used by the remember me feature
67
- create_table(:account_remember_keys) do
68
- foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
69
- String :key, :null=>false
70
- DateTime :deadline, deadline_opts[14]
71
- end
72
-
73
- # Used by the lockout feature
74
- create_table(:account_login_failures) do
75
- foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
76
- Integer :number, :null=>false, :default=>1
77
- end
78
- create_table(:account_lockouts) 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
83
- end
84
-
85
- # Used by the email auth feature
86
- create_table(:account_email_auth_keys) do
87
- foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
88
- String :key, :null=>false
89
- DateTime :deadline, deadline_opts[1]
90
- DateTime :email_last_sent, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
91
- end
92
-
93
- # Used by the password expiration feature
94
- create_table(:account_password_change_times) do
95
- foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
96
- DateTime :changed_at, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
97
- end
98
-
99
- # Used by the account expiration feature
100
- create_table(:account_activity_times) do
101
- foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
102
- DateTime :last_activity_at, :null=>false
103
- DateTime :last_login_at, :null=>false
104
- DateTime :expired_at
105
- end
106
-
107
- # Used by the single session feature
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
- # Used by the otp feature
114
- create_table(:account_otp_keys) do
115
- foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
116
- String :key, :null=>false
117
- Integer :num_failures, :null=>false, :default=>0
118
- Time :last_use, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
119
- end
120
-
121
- # Used by the recovery codes feature
122
- create_table(:account_recovery_codes) do
123
- foreign_key :id, :accounts, :type=>:Bignum
124
- String :code
125
- primary_key [:id, :code]
126
- end
127
-
128
- # Used by the sms codes feature
129
- create_table(:account_sms_codes) do
130
- foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
131
- String :phone_number, :null=>false
132
- Integer :num_failures
133
- String :code
134
- DateTime :code_issued_at, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
135
- end
136
-
137
- case database_type
138
- when :postgres
139
- user = get(Sequel.lit('current_user')) + '_password'
140
- run "GRANT REFERENCES ON accounts TO #{user}"
141
- when :mysql, :mssql
142
- user = if database_type == :mysql
143
- get(Sequel.lit('current_user')).sub(/_password@/, '@')
144
- else
145
- get(Sequel.function(:DB_NAME))
146
- end
147
- run "GRANT ALL ON account_statuses TO #{user}"
148
- run "GRANT ALL ON accounts TO #{user}"
149
- run "GRANT ALL ON account_password_reset_keys TO #{user}"
150
- run "GRANT ALL ON account_jwt_refresh_keys TO #{user}"
151
- run "GRANT ALL ON account_verification_keys TO #{user}"
152
- run "GRANT ALL ON account_login_change_keys TO #{user}"
153
- run "GRANT ALL ON account_remember_keys TO #{user}"
154
- run "GRANT ALL ON account_login_failures TO #{user}"
155
- run "GRANT ALL ON account_email_auth_keys TO #{user}"
156
- run "GRANT ALL ON account_lockouts TO #{user}"
157
- run "GRANT ALL ON account_password_change_times TO #{user}"
158
- run "GRANT ALL ON account_activity_times TO #{user}"
159
- run "GRANT ALL ON account_session_keys TO #{user}"
160
- run "GRANT ALL ON account_otp_keys TO #{user}"
161
- run "GRANT ALL ON account_recovery_codes TO #{user}"
162
- run "GRANT ALL ON account_sms_codes TO #{user}"
163
- end
164
- end
165
-
166
- down do
167
- drop_table(:account_sms_codes,
168
- :account_recovery_codes,
169
- :account_otp_keys,
170
- :account_session_keys,
171
- :account_activity_times,
172
- :account_password_change_times,
173
- :account_email_auth_keys,
174
- :account_lockouts,
175
- :account_login_failures,
176
- :account_remember_keys,
177
- :account_login_change_keys,
178
- :account_verification_keys,
179
- :account_jwt_refresh_keys,
180
- :account_password_reset_keys,
181
- :accounts,
182
- :account_statuses)
183
- end
184
- end
@@ -1,11 +0,0 @@
1
- Sequel.migration do
2
- up do
3
- # Only for testing of account_password_hash_column, not recommended for new
4
- # applications
5
- add_column :accounts, :ph, String
6
- end
7
-
8
- down do
9
- drop_column :accounts, :ph
10
- end
11
- end
@@ -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