Methods
Public Class
- configure
- create_database_authentication_functions
- create_database_previous_password_check_functions
- drop_database_authentication_functions
- drop_database_previous_password_check_functions
- load_dependencies
- new
- version
Public Instance
- _account_from_email_auth_key
- _account_from_login
- _account_from_refresh_token
- _account_from_reset_password_key
- _account_from_session
- _account_from_unlock_key
- _account_from_verify_account_key
- _account_from_verify_login_change_key
- _account_refresh_token_split
- _around_rodauth
- _email_auth_request
- _email_auth_request_and_redirect
- _field_attributes
- _field_error_attributes
- _formatted_field_error
- _json_response_body
- _jwt_decode_opts
- _login
- _login_form_footer
- _login_form_footer_links
- _multi_phase_login_forms
- _new_account
- _otp
- _otp_add_key
- _otp_key
- _otp_tmp_key
- _recovery_codes
- _sms
- _two_factor_auth_links
- _two_factor_remove_all_from_session
- _two_factor_remove_links
- _two_factor_setup_links
- _update_login
- _view
- _view_opts
- account_activity_ds
- account_ds
- account_expired?
- account_expired_at
- account_from_email_auth_key
- account_from_key
- account_from_login
- account_from_refresh_token
- account_from_reset_password_key
- account_from_session
- account_from_unlock_key
- account_from_verify_account_key
- account_from_verify_login_change_key
- account_id
- account_in_unverified_grace_period?
- account_initial_status_value
- account_lockouts_ds
- account_login_failures_ds
- account_password_hash_column
- account_session_status_filter
- account_webauthn_ids
- account_webauthn_usage
- account_webauthn_user_id
- active_remember_key_ds
- active_sessions_ds
- add_active_session
- add_audit_log
- add_field_error_class
- add_previous_password_hash
- add_recovery_code
- add_recovery_codes
- add_remember_key
- add_webauthn_credential
- after_change_password
- after_close_account
- after_create_account
- after_login
- after_login_entered_during_multi_phase_login
- after_login_failure
- after_logout
- after_otp_disable
- after_refresh_token
- after_reset_password
- after_sms_disable
- after_webauthn_remove
- allow_email_auth?
- allow_resending_verify_account_email?
- already_logged_in
- audit_log_ds
- audit_log_insert_hash
- audit_log_message
- audit_log_message_default
- audit_log_metadata
- auth_class_eval
- authenticated?
- authenticated_by
- authenticated_webauthn_id
- auto_add_missing_recovery_codes
- auto_remove_recovery_codes
- autocomplete_for_field?
- autologin_session
- autologin_type
- base32_encode
- base_url
- before_change_login_route
- before_change_password_route
- before_login_attempt
- before_logout
- before_otp_setup_route
- before_reset_password
- before_reset_password_request
- before_rodauth
- before_unlock_account
- before_unlock_account_request
- before_verify_account
- before_view_recovery_codes
- before_webauthn_auth_route
- before_webauthn_login_route
- before_webauthn_remove_route
- before_webauthn_setup_route
- button
- button_opts
- can_add_recovery_codes?
- catch_error
- change_login
- change_login_notice_flash
- change_login_requires_password?
- change_password_requires_password?
- check_account_expiration
- check_active_session
- check_already_logged_in
- check_csrf
- check_csrf?
- check_password_change_allowed
- check_session_expiration
- check_single_session
- clear_cached_otp
- clear_invalid_login_attempts
- clear_session
- close_account
- close_account_requires_password?
- compute_hmac
- compute_raw_hmac
- confirm_password
- confirm_password_redirect
- convert_email_token_key
- convert_session_key
- convert_timestamp
- convert_token_key
- create_account_autologin?
- create_account_notice_flash
- create_account_set_password?
- create_email
- create_email_auth_email
- create_email_auth_key
- create_email_to
- create_password_changed_email
- create_reset_password_email
- create_reset_password_key
- create_unlock_account_email
- create_verify_account_email
- create_verify_account_key
- create_verify_login_change_email
- create_verify_login_change_key
- csrf_tag
- currently_active_session?
- database_function_password_match?
- db
- delete_account
- delete_account_on_close?
- disable_remember_login
- domain
- email_auth_ds
- email_auth_email_body
- email_auth_email_link
- email_auth_email_recently_sent?
- email_auth_key_insert_hash
- email_auth_request_form
- email_from
- email_to
- expire_session
- features
- field_attributes
- field_error
- field_error_attributes
- flash
- forget_login
- formatted_field_error
- function_name
- generate_email_auth_key_value
- generate_refresh_token
- generate_remember_key_value
- generate_reset_password_key_value
- generate_unlock_account_key
- generate_verify_account_key_value
- generate_verify_login_change_key_value
- get_active_refresh_token
- get_activity_timestamp
- get_email_auth_email_last_sent
- get_email_auth_key
- get_password_changed_at
- get_password_hash
- get_password_reset_key
- get_remember_key
- get_reset_password_email_last_sent
- get_unlock_account_email_last_sent
- get_unlock_account_key
- get_verify_account_email_last_sent
- get_verify_account_key
- get_verify_login_change_login_and_key
- handle_duplicate_active_session_id
- handle_webauthn_sign_count_verification_error
- has_password?
- hook_action
- http_basic_auth
- inactive_session_cond
- include_success_messages?
- input_field_string
- inputmode_for_field?
- invalid_login_attempted
- invalid_previous_password_message
- json_request?
- json_response
- jwt_cors_allow?
- jwt_payload
- jwt_refresh_token_account_ds
- jwt_refresh_token_account_token_ds
- jwt_refresh_token_ds
- jwt_refresh_token_insert_hash
- jwt_refresh_token_match?
- jwt_secret
- jwt_session_hash
- jwt_token
- last_account_activity_at
- last_account_login_at
- load_memory
- loaded_templates
- locked_out?
- logged_in_via_remember_key?
- login
- login_confirm_label
- login_does_not_meet_requirements_message
- login_failed_reset_password_request_form
- login_hidden_field
- login_input_type
- login_meets_email_requirements?
- login_meets_length_requirements?
- login_meets_requirements?
- login_required
- login_return_to_requested_location_path
- login_session
- login_too_long_message
- login_too_short_message
- login_uses_email?
- login_valid_email?
- logout
- logout_additional_form_tags
- modifications_require_password?
- new_account
- new_recovery_code
- new_webauthn_credential
- no_longer_active_session
- only_json?
- open_account?
- otp_add_key
- otp_exists?
- otp_hmac_secret
- otp_issuer
- otp_key_ds
- otp_keys_use_hmac?
- otp_last_use
- otp_locked_out?
- otp_new_secret
- otp_provisioning_name
- otp_provisioning_uri
- otp_qr_code
- otp_record_authentication_failure
- otp_remove
- otp_remove_auth_failures
- otp_tmp_key
- otp_update_last_use
- otp_user_key
- otp_valid_code?
- otp_valid_key?
- param
- param_or_nil
- password_changed_email_body
- password_confirm_label
- password_does_not_contain_null_byte?
- password_does_not_meet_requirements_message
- password_doesnt_match_previous_password?
- password_expiration_ds
- password_expired?
- password_field_autocomplete_value
- password_has_enough_character_groups?
- password_has_no_invalid_pattern?
- password_hash
- password_hash_cost
- password_hash_ds
- password_hash_match?
- password_match?
- password_meets_length_requirements?
- password_meets_requirements?
- password_not_in_dictionary?
- password_not_one_of_the_most_common?
- password_not_too_many_repeating_characters?
- password_one_of_most_common?
- password_recently_entered?
- password_reset_ds
- password_too_short_message
- possible_authentication_methods
- post_configure
- previous_password_ds
- raises_uniqueness_violation?
- random_key
- raw_param
- recovery_code_match?
- recovery_codes_ds
- recovery_codes_primary?
- recovery_codes_remove
- redirect
- redirect_two_factor_authenticated
- remember_key_ds
- remember_login
- remove_all_active_sessions
- remove_all_webauthn_keys_and_user_ids
- remove_current_session
- remove_email_auth_key
- remove_inactive_sessions
- remove_jwt_refresh_token_key
- remove_lockout_metadata
- remove_remember_key
- remove_reset_password_key
- remove_session_value
- remove_verify_account_key
- remove_verify_login_change_key
- remove_webauthn_key
- render
- render_multi_phase_login_forms
- request
- require_account
- require_account_session
- require_authentication
- require_current_password
- require_http_basic_auth
- require_login
- require_login_confirmation?
- require_otp_setup
- require_password_authentication
- require_password_authentication?
- require_sms_available
- require_sms_not_setup
- require_sms_setup
- require_two_factor_authenticated
- require_two_factor_not_authenticated
- require_two_factor_setup
- require_webauthn_setup
- rescue_jwt_payload
- reset_password_email_body
- reset_password_email_link
- reset_password_email_recently_sent?
- reset_password_key_insert_hash
- reset_single_session_key
- response
- retry_on_uniqueness_violation
- return_json_response
- route!
- route_path
- route_url
- save_account
- send_email
- send_email_auth_email
- send_password_changed_email
- send_reset_password_email
- send_unlock_account_email
- send_verify_account_email
- send_verify_login_change_email
- serialize_audit_log_metadata
- session
- session_inactivity_deadline_condition
- session_jwt
- session_lifetime_deadline_condition
- session_value
- set_deadline_value
- set_deadline_values?
- set_email_auth_email_last_sent
- set_error_flash
- set_expired
- set_field_error
- set_http_basic_auth_error_response
- set_jwt
- set_jwt_refresh_token_hmac_session_key
- set_jwt_token
- set_last_password_entry
- set_new_account_password
- set_notice_flash
- set_notice_now_flash
- set_password
- set_redirect_error_flash
- set_redirect_error_status
- set_reset_password_email_last_sent
- set_response_error_status
- set_session_value
- set_single_session_key
- set_title
- set_unlock_account_email_last_sent
- set_verify_account_email_last_sent
- setup_account_verification
- show_lockout_page
- single_session_ds
- skip_login_field_on_login?
- skip_password_field_on_login?
- skip_status_checks?
- sms_auth_message
- sms_available?
- sms_code
- sms_code_issued_at
- sms_code_match?
- sms_codes_primary?
- sms_confirm
- sms_confirm_failure
- sms_confirm_message
- sms_confirmation_match?
- sms_current_auth?
- sms_disable
- sms_ds
- sms_failures
- sms_locked_out?
- sms_needs_confirmation?
- sms_new_auth_code
- sms_new_confirm_code
- sms_normalize_phone
- sms_phone
- sms_record_failure
- sms_remove_failures
- sms_send
- sms_send_auth_code
- sms_send_confirm_code
- sms_set_code
- sms_setup
- sms_setup?
- sms_valid_phone?
- split_token
- template_path
- throw_basic_auth_error
- throw_error
- throw_error_status
- timing_safe_eql?
- token_link
- transaction
- translate
- two_factor_authenticate
- two_factor_authenticated?
- two_factor_authentication_setup?
- two_factor_login_type_match?
- two_factor_modifications_require_password?
- two_factor_password_match?
- two_factor_remove
- two_factor_remove_auth_failures
- two_factor_remove_session
- two_factor_update_session
- unique_constraint_violation_class
- unlock_account
- unlock_account_email_body
- unlock_account_email_link
- unlock_account_email_recently_sent?
- update_account
- update_activity
- update_hash_ds
- update_last_activity
- update_last_login
- update_login
- update_password_changed_at
- update_password_hash?
- update_session
- update_single_session_key
- update_sms
- use_database_authentication_functions?
- use_date_arithmetic?
- use_jwt?
- use_multi_phase_login?
- use_request_specific_csrf_tokens?
- uses_two_factor_authentication?
- valid_jwt?
- valid_login_entered?
- valid_new_webauthn_credential?
- valid_webauthn_credential_auth?
- verified_account?
- verify_account
- verify_account_check_already_logged_in
- verify_account_ds
- verify_account_email_body
- verify_account_email_link
- verify_account_email_recently_sent?
- verify_account_email_resend
- verify_account_key_insert_hash
- verify_account_set_password?
- verify_account_view
- verify_login_change
- verify_login_change_ds
- verify_login_change_email_body
- verify_login_change_email_link
- verify_login_change_key_insert_hash
- verify_login_change_old_login
- view
- webauth_credential_options_for_get
- webauthn_account_id
- webauthn_auth_additional_form_tags
- webauthn_auth_credential_from_form_submission
- webauthn_auth_form_path
- webauthn_authenticator_selection
- webauthn_extensions
- webauthn_keys_ds
- webauthn_origin
- webauthn_remove_authenticated_session
- webauthn_rp_id
- webauthn_rp_name
- webauthn_setup?
- webauthn_setup_credential_from_form_submission
- webauthn_update_session
- webauthn_user_ids_ds
- webauthn_user_name
Classes and Modules
Constants
FEATURES | = | {} | ||
MAJOR | = | 2 |
The major version of |
|
MINOR | = | 8 |
The minor version of |
|
TINY | = | 0 |
The patch version of |
|
VERSION | = | "#{MAJOR}.#{MINOR}.#{TINY}".freeze |
The full version of |
|
VERSION_NUMBER | = | MAJOR*10000 + MINOR*100 + TINY |
Public Instance Aliases
account_session_value | -> | account_id | |
ignore_uniqueness_violation | -> | raises_uniqueness_violation? |
If you just want to ignore uniqueness violations, this alias makes more sense. |
logged_in? | -> | session_value | |
raised_uniqueness_violation | -> | raises_uniqueness_violation? |
If you would like to operate/reraise the exception, this alias makes more sense. |
Public Class methods
# File lib/rodauth.rb 33 def self.configure(app, opts={}, &block) 34 json_opt = app.opts[:rodauth_json] = opts.fetch(:json, app.opts[:rodauth_json]) 35 csrf = app.opts[:rodauth_csrf] = opts.fetch(:csrf, app.opts[:rodauth_csrf]) 36 app.opts[:rodauth_route_csrf] = case csrf 37 when false, :rack_csrf 38 false 39 else 40 json_opt != :only 41 end 42 auth_class = (app.opts[:rodauths] ||= {})[opts[:name]] ||= Class.new(Auth) 43 if !auth_class.roda_class 44 auth_class.roda_class = app 45 elsif auth_class.roda_class != app 46 auth_class = app.opts[:rodauths][opts[:name]] = Class.new(auth_class) 47 auth_class.roda_class = app 48 end 49 auth_class.configure(&block) 50 end
# File lib/rodauth/migrations.rb 4 def self.create_database_authentication_functions(db, opts={}) 5 table_name = opts[:table_name] || :account_password_hashes 6 get_salt_name = opts[:get_salt_name] || :rodauth_get_salt 7 valid_hash_name = opts[:valid_hash_name] || :rodauth_valid_password_hash 8 9 case db.database_type 10 when :postgres 11 search_path = opts[:search_path] || 'public, pg_temp' 12 primary_key_type = 13 case db.schema(table_name).find { |row| row.first == :id }[1][:db_type] 14 when 'uuid' then :uuid 15 else :int8 16 end 17 18 db.run <<END 19 CREATE OR REPLACE FUNCTION #{get_salt_name}(acct_id #{primary_key_type}) RETURNS text AS $$ 20 DECLARE salt text; 21 BEGIN 22 SELECT substr(password_hash, 0, 30) INTO salt 23 FROM #{table_name} 24 WHERE acct_id = id; 25 RETURN salt; 26 END; 27 $$ LANGUAGE plpgsql 28 SECURITY DEFINER 29 SET search_path = #{search_path}; 30 END 31 32 db.run <<END 33 CREATE OR REPLACE FUNCTION #{valid_hash_name}(acct_id #{primary_key_type}, hash text) RETURNS boolean AS $$ 34 DECLARE valid boolean; 35 BEGIN 36 SELECT password_hash = hash INTO valid 37 FROM #{table_name} 38 WHERE acct_id = id; 39 RETURN valid; 40 END; 41 $$ LANGUAGE plpgsql 42 SECURITY DEFINER 43 SET search_path = #{search_path}; 44 END 45 when :mysql 46 db.run <<END 47 CREATE FUNCTION #{get_salt_name}(acct_id int8) RETURNS varchar(255) 48 SQL SECURITY DEFINER 49 READS SQL DATA 50 BEGIN 51 RETURN (SELECT substr(password_hash, 1, 30) 52 FROM #{table_name} 53 WHERE acct_id = id); 54 END; 55 END 56 57 db.run <<END 58 CREATE FUNCTION #{valid_hash_name}(acct_id int8, hash varchar(255)) RETURNS tinyint(1) 59 SQL SECURITY DEFINER 60 READS SQL DATA 61 BEGIN 62 DECLARE valid tinyint(1); 63 DECLARE csr CURSOR FOR 64 SELECT password_hash = hash 65 FROM #{table_name} 66 WHERE acct_id = id; 67 OPEN csr; 68 FETCH csr INTO valid; 69 CLOSE csr; 70 RETURN valid; 71 END; 72 END 73 when :mssql 74 db.run <<END 75 CREATE FUNCTION #{get_salt_name}(@account_id bigint) RETURNS nvarchar(255) 76 WITH EXECUTE AS OWNER 77 AS 78 BEGIN 79 DECLARE @salt nvarchar(255); 80 SELECT @salt = substring(password_hash, 0, 30) 81 FROM #{table_name} 82 WHERE id = @account_id; 83 RETURN @salt; 84 END; 85 END 86 87 db.run <<END 88 CREATE FUNCTION #{valid_hash_name}(@account_id bigint, @hash nvarchar(255)) RETURNS bit 89 WITH EXECUTE AS OWNER 90 AS 91 BEGIN 92 DECLARE @valid bit; 93 DECLARE @ph nvarchar(255); 94 SELECT @ph = password_hash 95 FROM #{table_name} 96 WHERE id = @account_id; 97 IF(@hash = @ph) 98 SET @valid = 1; 99 ELSE 100 SET @valid = 0 101 RETURN @valid; 102 END; 103 END 104 end 105 end
# File lib/rodauth/migrations.rb 127 def self.create_database_previous_password_check_functions(db, opts={}) 128 create_database_authentication_functions(db, {:table_name=>:account_previous_password_hashes, :get_salt_name=>:rodauth_get_previous_salt, :valid_hash_name=>:rodauth_previous_password_hash_match}.merge(opts)) 129 end
# File lib/rodauth/migrations.rb 107 def self.drop_database_authentication_functions(db, opts={}) 108 table_name = opts[:table_name] || :account_password_hashes 109 get_salt_name = opts[:get_salt_name] || :rodauth_get_salt 110 valid_hash_name = opts[:valid_hash_name] || :rodauth_valid_password_hash 111 112 case db.database_type 113 when :postgres 114 primary_key_type = 115 case db.schema(table_name).find { |row| row.first == :id }[1][:db_type] 116 when 'uuid' then :uuid 117 else :int8 118 end 119 db.run "DROP FUNCTION #{get_salt_name}(#{primary_key_type})" 120 db.run "DROP FUNCTION #{valid_hash_name}(#{primary_key_type}, text)" 121 when :mysql, :mssql 122 db.run "DROP FUNCTION #{get_salt_name}" 123 db.run "DROP FUNCTION #{valid_hash_name}" 124 end 125 end
# File lib/rodauth/migrations.rb 131 def self.drop_database_previous_password_check_functions(db, opts={}) 132 drop_database_authentication_functions(db, {:table_name=>:account_previous_password_hashes, :get_salt_name=>:rodauth_get_previous_salt, :valid_hash_name=>:rodauth_previous_password_hash_match}.merge(opts)) 133 end
# File lib/rodauth.rb 6 def self.load_dependencies(app, opts={}) 7 json_opt = opts.fetch(:json, app.opts[:rodauth_json]) 8 if json_opt 9 app.plugin :json 10 app.plugin :json_parser 11 end 12 13 unless json_opt == :only 14 require 'tilt/string' 15 app.plugin :render 16 17 case opts.fetch(:csrf, app.opts[:rodauth_csrf]) 18 when false 19 # nothing 20 when :rack_csrf 21 # :nocov: 22 app.plugin :csrf 23 # :nocov: 24 else 25 app.plugin :route_csrf 26 end 27 28 app.plugin :flash unless opts[:flash] == false 29 app.plugin :h 30 end 31 end
# File lib/rodauth/features/base.rb 126 def initialize(scope) 127 @scope = scope 128 end
Public Instance methods
# File lib/rodauth/features/email_auth.rb 252 def _account_from_email_auth_key(token) 253 account_from_key(token, account_open_status_value){|id| get_email_auth_key(id)} 254 end
# File lib/rodauth/features/base.rb 610 def _account_from_login(login) 611 ds = db[accounts_table].where(login_column=>login) 612 ds = ds.select(*account_select) if account_select 613 ds = ds.where(account_status_column=>[account_unverified_status_value, account_open_status_value]) unless skip_status_checks? 614 ds.first 615 end
# File lib/rodauth/features/jwt_refresh.rb 114 def _account_from_refresh_token(token) 115 id, token_id, key = _account_refresh_token_split(token) 116 117 unless key && 118 (id == session_value.to_s) && 119 (actual = get_active_refresh_token(id, token_id)) && 120 timing_safe_eql?(key, convert_token_key(actual)) && 121 jwt_refresh_token_match?(key) 122 return 123 end 124 125 ds = account_ds(id) 126 ds = ds.where(account_status_column=>account_open_status_value) unless skip_status_checks? 127 ds.first 128 end
# File lib/rodauth/features/reset_password.rb 265 def _account_from_reset_password_key(token) 266 account_from_key(token, account_open_status_value){|id| get_password_reset_key(id)} 267 end
# File lib/rodauth/features/base.rb 617 def _account_from_session 618 ds = account_ds(session_value) 619 ds = ds.where(account_session_status_filter) unless skip_status_checks? 620 ds.first 621 end
# File lib/rodauth/features/lockout.rb 304 def _account_from_unlock_key(token) 305 account_from_key(token){|id| account_lockouts_ds(id).get(account_lockouts_key_column)} 306 end
# File lib/rodauth/features/verify_account.rb 321 def _account_from_verify_account_key(token) 322 account_from_key(token, account_unverified_status_value){|id| get_verify_account_key(id)} 323 end
# File lib/rodauth/features/verify_login_change.rb 208 def _account_from_verify_login_change_key(token) 209 account_from_key(token) do |id| 210 @verify_login_change_new_login, key = get_verify_login_change_login_and_key(id) 211 key 212 end 213 end
# File lib/rodauth/features/jwt_refresh.rb 130 def _account_refresh_token_split(token) 131 id, token = split_token(token) 132 return unless id && token 133 134 token_id, key = split_token(token) 135 return unless token_id && key 136 137 [id, token_id, key] 138 end
# File lib/rodauth/features/base.rb 463 def _around_rodauth 464 yield 465 end
# File lib/rodauth/features/email_auth.rb 186 def _email_auth_request 187 if email_auth_email_recently_sent? 188 set_redirect_error_flash email_auth_email_recently_sent_error_flash 189 redirect email_auth_email_recently_sent_redirect 190 end 191 192 generate_email_auth_key_value 193 transaction do 194 before_email_auth_request 195 create_email_auth_key 196 send_email_auth_email 197 after_email_auth_request 198 end 199 200 set_notice_flash email_auth_email_sent_notice_flash 201 end
# File lib/rodauth/features/email_auth.rb 181 def _email_auth_request_and_redirect 182 _email_auth_request 183 redirect email_auth_email_sent_redirect 184 end
# File lib/rodauth/features/base.rb 627 def _field_attributes(field) 628 nil 629 end
# File lib/rodauth/features/base.rb 631 def _field_error_attributes(field) 632 " aria-invalid=\"true\" aria-describedby=\"#{field}_error_message\" " 633 end
# File lib/rodauth/features/base.rb 635 def _formatted_field_error(field, error) 636 "<span class=\"#{input_field_error_message_class}\" id=\"#{field}_error_message\">#{error}</span>" 637 end
# File lib/rodauth/features/jwt.rb 275 def _json_response_body(hash) 276 request.send(:convert_to_json, hash) 277 end
# File lib/rodauth/features/jwt.rb 235 def _jwt_decode_opts 236 jwt_decode_opts 237 end
# File lib/rodauth/features/login.rb 146 def _login(auth_type) 147 warn("Deprecated #_login method called, use #login instead.") 148 login(auth_type) 149 end
# File lib/rodauth/features/email_auth.rb 171 def _multi_phase_login_forms 172 forms = super 173 forms << [30, email_auth_request_form, :_email_auth_request_and_redirect] if valid_login_entered? && allow_email_auth? 174 forms 175 end
# File lib/rodauth/features/create_account.rb 119 def _new_account(login) 120 acc = {login_column=>login} 121 unless skip_status_checks? 122 acc[account_status_column] = account_initial_status_value 123 end 124 acc 125 end
# File lib/rodauth/features/otp.rb 401 def _otp 402 otp_class.new(otp_user_key, :issuer=>otp_issuer, :digits=>otp_digits, :interval=>otp_interval) 403 end
# File lib/rodauth/features/otp.rb 390 def _otp_add_key(secret) 391 # Uniqueness errors can't be handled here, as we can't be sure the secret provided 392 # is the same as the current secret. 393 otp_key_ds.insert(otp_keys_id_column=>session_value, otp_keys_column=>secret) 394 end
# File lib/rodauth/features/otp.rb 396 def _otp_key 397 @otp_user_key = nil 398 otp_key_ds.get(otp_keys_column) 399 end
# File lib/rodauth/features/otp.rb 384 def _otp_tmp_key(secret) 385 @otp_tmp_key = true 386 @otp_user_key = nil 387 @otp_key = secret 388 end
# File lib/rodauth/features/recovery_codes.rb 251 def _recovery_codes 252 recovery_codes_ds.select_map(recovery_codes_column) 253 end
# File lib/rodauth/features/sms_codes.rb 487 def _sms 488 sms_ds.first 489 end
# File lib/rodauth/features/confirm_password.rb 78 def _two_factor_auth_links 79 links = (super if defined?(super)) || [] 80 if authenticated_by.length == 1 && !authenticated_by.include?('password') && has_password? 81 links << [5, confirm_password_path, confirm_password_link_text] 82 end 83 links 84 end
# File lib/rodauth/features/otp.rb 340 def _two_factor_remove_all_from_session 341 two_factor_remove_session('totp') 342 super 343 end
# File lib/rodauth/features/otp.rb 334 def _two_factor_remove_links 335 links = super 336 links << [20, otp_disable_path, otp_disable_link_text] if otp_exists? 337 links 338 end
# File lib/rodauth/features/otp.rb 328 def _two_factor_setup_links 329 links = super 330 links << [20, otp_setup_path, otp_setup_link_text] unless otp_exists? 331 links 332 end
# File lib/rodauth/features/change_login.rb 80 def _update_login(login) 81 updated = nil 82 raised = raises_uniqueness_violation?{updated = update_account({login_column=>login}, account_ds.exclude(login_column=>login)) == 1} 83 if raised 84 @login_requirement_message = already_an_account_with_this_login_message 85 end 86 updated && !raised 87 end
# File lib/rodauth/features/base.rb 755 def _view(meth, page) 756 scope.send(meth, _view_opts(page)) 757 end
# File lib/rodauth/features/base.rb 740 def _view_opts(page) 741 opts = template_opts.dup 742 opts[:locals] = opts[:locals] ? opts[:locals].dup : {} 743 opts[:locals][:rodauth] = self 744 opts[:cache] = cache_templates 745 opts[:cache_key] = :"rodauth_#{page}" 746 747 opts = scope.send(:find_template, scope.send(:parse_template_opts, page, opts)) 748 unless File.file?(scope.send(:template_path, opts)) 749 opts[:path] = template_path(page) 750 end 751 752 opts 753 end
# File lib/rodauth/features/account_expiration.rb 104 def account_activity_ds(account_id) 105 db[account_activity_table]. 106 where(account_activity_id_column=>account_id) 107 end
# File lib/rodauth/features/base.rb 647 def account_ds(id=account_id) 648 raise ArgumentError, "invalid account id passed to account_ds" unless id 649 ds = db[accounts_table].where(account_id_column=>id) 650 ds = ds.select(*account_select) if account_select 651 ds 652 end
# File lib/rodauth/features/account_expiration.rb 54 def account_expired? 55 columns = [account_activity_last_activity_column, account_activity_last_login_column, account_activity_expired_column] 56 last_activity, last_login, expired = account_activity_ds(account_id).get(columns) 57 return true if expired 58 timestamp = convert_timestamp(expire_account_on_last_activity? ? last_activity : last_login) 59 return false unless timestamp 60 timestamp < Time.now - expire_account_after 61 end
# File lib/rodauth/features/account_expiration.rb 35 def account_expired_at 36 get_activity_timestamp(account_id, account_activity_expired_column) 37 end
# File lib/rodauth/features/email_auth.rb 130 def account_from_email_auth_key(key) 131 @account = _account_from_email_auth_key(key) 132 end
# File lib/rodauth/features/email_base.rb 61 def account_from_key(token, status_id=nil) 62 id, key = split_token(token) 63 return unless id && key 64 65 return unless actual = yield(id) 66 67 unless timing_safe_eql?(key, convert_email_token_key(actual)) 68 if hmac_secret && allow_raw_email_token? 69 return unless timing_safe_eql?(key, actual) 70 else 71 return 72 end 73 end 74 75 ds = account_ds(id) 76 ds = ds.where(account_status_column=>status_id) if status_id && !skip_status_checks? 77 ds.first 78 end
# File lib/rodauth/features/base.rb 247 def account_from_login(login) 248 @account = _account_from_login(login) 249 end
# File lib/rodauth/features/jwt_refresh.rb 91 def account_from_refresh_token(token) 92 @account = _account_from_refresh_token(token) 93 end
# File lib/rodauth/features/password_expiration.rb 45 def account_from_reset_password_key(key) 46 if a = super 47 check_password_change_allowed 48 end 49 a 50 end
# File lib/rodauth/features/base.rb 339 def account_from_session 340 @account = _account_from_session 341 end
# File lib/rodauth/features/lockout.rb 214 def account_from_unlock_key(key) 215 @account = _account_from_unlock_key(key) 216 end
# File lib/rodauth/features/verify_account.rb 202 def account_from_verify_account_key(key) 203 @account = _account_from_verify_account_key(key) 204 end
# File lib/rodauth/features/verify_login_change.rb 118 def account_from_verify_login_change_key(key) 119 @account = _account_from_verify_login_change_key(key) 120 end
# File lib/rodauth/features/base.rb 237 def account_id 238 account[account_id_column] 239 end
# File lib/rodauth/features/verify_account_grace_period.rb 74 def account_in_unverified_grace_period? 75 account || account_from_session 76 account[account_status_column] == account_unverified_status_value && 77 verify_account_grace_period && 78 !verify_account_ds.where(Sequel.date_add(verification_requested_at_column, :seconds=>verify_account_grace_period) > Sequel::CURRENT_TIMESTAMP).empty? 79 end
# File lib/rodauth/features/base.rb 335 def account_initial_status_value 336 account_open_status_value 337 end
# File lib/rodauth/features/lockout.rb 300 def account_lockouts_ds(id=account_id) 301 db[account_lockouts_table].where(account_lockouts_id_column=>id) 302 end
# File lib/rodauth/features/lockout.rb 296 def account_login_failures_ds 297 db[account_login_failures_table].where(account_login_failures_id_column=>account_id) 298 end
If the account_password_hash_column
is set, the password hash is verified in ruby, it will not use a database function to do so, it will check the password hash using bcrypt.
# File lib/rodauth/features/base.rb 267 def account_password_hash_column 268 nil 269 end
# File lib/rodauth/features/base.rb 639 def account_session_status_filter 640 {account_status_column=>account_open_status_value} 641 end
# File lib/rodauth/features/webauthn.rb 262 def account_webauthn_ids 263 webauthn_keys_ds.select_map(webauthn_keys_webauthn_id_column) 264 end
# File lib/rodauth/features/webauthn.rb 266 def account_webauthn_usage 267 webauthn_keys_ds.select_hash(webauthn_keys_webauthn_id_column, webauthn_keys_last_use_column) 268 end
# File lib/rodauth/features/webauthn.rb 270 def account_webauthn_user_id 271 unless webauthn_id = webauthn_user_ids_ds.get(webauthn_user_ids_webauthn_id_column) 272 webauthn_id = WebAuthn.generate_user_id 273 if e = raised_uniqueness_violation do 274 webauthn_user_ids_ds.insert( 275 webauthn_user_ids_account_id_column => webauthn_account_id, 276 webauthn_user_ids_webauthn_id_column => webauthn_id 277 ) 278 end 279 # If two requests to create a webauthn user id are sent at the same time and an insert 280 # is attempted for both, one will fail with a unique constraint violation. In that case 281 # it is safe for the second one to use the webauthn user id inserted by the other request. 282 # If there is still no webauthn user id at this point, then we'll just reraise the 283 # exception. 284 # :nocov: 285 raise e unless webauthn_id = webauthn_user_ids_ds.get(webauthn_user_ids_webauthn_id_column) 286 # :nocov: 287 end 288 end 289 290 webauthn_id 291 end
# File lib/rodauth/features/remember.rb 206 def active_remember_key_ds(id=account_id) 207 remember_key_ds(id).where(Sequel.expr(remember_deadline_column) > Sequel::CURRENT_TIMESTAMP) 208 end
# File lib/rodauth/features/active_sessions.rb 148 def active_sessions_ds 149 db[active_sessions_table]. 150 where(active_sessions_account_id_column=>session_value) 151 end
# File lib/rodauth/features/active_sessions.rb 59 def add_active_session 60 key = random_key 61 set_session_value(session_id_session_key, key) 62 if e = raises_uniqueness_violation? do 63 active_sessions_ds.insert(active_sessions_account_id_column => session_value, active_sessions_session_id_column => compute_hmac(key)) 64 end 65 handle_duplicate_active_session_id(e) 66 end 67 nil 68 end
# File lib/rodauth/features/audit_logging.rb 39 def add_audit_log(account_id, action) 40 if hash = audit_log_insert_hash(account_id, action) 41 audit_log_ds.insert(hash) 42 end 43 end
# File lib/rodauth/features/base.rb 167 def add_field_error_class(field) 168 if field_error(field) 169 " #{input_field_error_class}" 170 end 171 end
# File lib/rodauth/features/disallow_password_reuse.rb 25 def add_previous_password_hash(hash) 26 ds = previous_password_ds 27 keep_before = ds.reverse(previous_password_id_column). 28 limit(nil, previous_passwords_to_check). 29 get(previous_password_id_column) 30 31 if keep_before 32 ds.where(Sequel.expr(previous_password_id_column) <= keep_before). 33 delete 34 end 35 36 # This should never raise uniqueness violations, as it uses a serial primary key 37 ds.insert(previous_password_account_id_column=>account_id, previous_password_hash_column=>hash) 38 end
# File lib/rodauth/features/recovery_codes.rb 182 def add_recovery_code 183 # This should never raise uniqueness violations unless the recovery code is the same, and the odds of that 184 # are 1/256**32 assuming a good random number generator. Still, attempt to handle that case by retrying 185 # on such a uniqueness violation. 186 retry_on_uniqueness_violation do 187 recovery_codes_ds.insert(recovery_codes_id_column=>session_value, recovery_codes_column=>new_recovery_code) 188 end 189 end
# File lib/rodauth/features/recovery_codes.rb 172 def add_recovery_codes(number) 173 return if number <= 0 174 transaction do 175 number.times do 176 add_recovery_code 177 end 178 end 179 remove_instance_variable(:@recovery_codes) 180 end
# File lib/rodauth/features/remember.rb 161 def add_remember_key 162 hash = {remember_id_column=>account_id, remember_key_column=>remember_key_value} 163 set_deadline_value(hash, remember_deadline_column, remember_deadline_interval) 164 165 if e = raised_uniqueness_violation{remember_key_ds.insert(hash)} 166 # If inserting into the remember key table causes a violation, we can pull the 167 # existing row from the table. If there is no invalid row, we can then reraise. 168 raise e unless @remember_key_value = active_remember_key_ds.get(remember_key_column) 169 end 170 end
# File lib/rodauth/features/recovery_codes.rb 146 def add_webauthn_credential(_) 147 super if defined?(super) 148 auto_add_missing_recovery_codes 149 end
# File lib/rodauth/features/change_password_notify.rb 31 def after_change_password 32 super 33 send_password_changed_email 34 end
# File lib/rodauth/features/account_expiration.rb 99 def after_close_account 100 super if defined?(super) 101 account_activity_ds(account_id).delete 102 end
# File lib/rodauth/features/disallow_password_reuse.rb 74 def after_create_account 75 if account_password_hash_column && !(respond_to?(:verify_account_set_password?) && verify_account_set_password?) 76 add_previous_password_hash(password_hash(param(password_param))) 77 end 78 super if defined?(super) 79 end
# File lib/rodauth/features/email_auth.rb 209 def after_login 210 # Remove the email auth key after any login, even if 211 # it is a password login. This is done to invalidate 212 # the email login when a user has a password and requests 213 # email authentication, but then remembers their password 214 # and doesn't need the link. At that point, the link 215 # that allows login access to the account becomes a 216 # security liability, and it is best to remove it. 217 remove_email_auth_key 218 super 219 end
# File lib/rodauth/features/email_auth.rb 152 def after_login_entered_during_multi_phase_login 153 # If forcing email auth, just send the email link. 154 _email_auth_request_and_redirect if force_email_auth? 155 156 super 157 end
# File lib/rodauth/features/lockout.rb 254 def after_login_failure 255 invalid_login_attempted 256 super 257 end
# File lib/rodauth/features/remember.rb 182 def after_logout 183 forget_login 184 super if defined?(super) 185 end
# File lib/rodauth/features/recovery_codes.rb 216 def after_otp_disable 217 super if defined?(super) 218 auto_remove_recovery_codes 219 end
# File lib/rodauth/features/active_sessions.rb 104 def after_refresh_token 105 super if defined?(super) 106 if prev_key = session[session_id_session_key] 107 key = random_key 108 set_session_value(session_id_session_key, key) 109 active_sessions_ds. 110 where(active_sessions_session_id_column => compute_hmac(prev_key)). 111 update(active_sessions_session_id_column => compute_hmac(key)) 112 end 113 end
# File lib/rodauth/features/password_grace_period.rb 39 def after_reset_password 40 super if defined?(super) 41 @last_password_entry = Time.now.to_i 42 end
# File lib/rodauth/features/recovery_codes.rb 221 def after_sms_disable 222 super if defined?(super) 223 auto_remove_recovery_codes 224 end
# File lib/rodauth/features/recovery_codes.rb 226 def after_webauthn_remove 227 super if defined?(super) 228 auto_remove_recovery_codes 229 end
# File lib/rodauth/features/email_auth.rb 205 def allow_email_auth? 206 defined?(super) ? super : true 207 end
# File lib/rodauth/features/verify_account.rb 168 def allow_resending_verify_account_email? 169 account[account_status_column] == account_unverified_status_value 170 end
# File lib/rodauth/features/base.rb 275 def already_logged_in 276 nil 277 end
# File lib/rodauth/features/audit_logging.rb 83 def audit_log_ds 84 ds = db[audit_logging_table] 85 # :nocov: 86 if db.database_type == :postgres 87 # :nocov: 88 # For PostgreSQL, use RETURNING NULL. This allows the feature 89 # to be used with INSERT but not SELECT permissions on the 90 # table, useful for audit logging where the database user 91 # the application is running as should not need to read the 92 # logs. 93 ds = ds.returning(nil) 94 end 95 ds 96 end
# File lib/rodauth/features/audit_logging.rb 45 def audit_log_insert_hash(account_id, action) 46 if message = audit_log_message(action) 47 { 48 audit_logging_account_id_column => account_id, 49 audit_logging_message_column => message, 50 audit_logging_metadata_column => serialize_audit_log_metadata(audit_log_metadata(action)) 51 } 52 end 53 end
# File lib/rodauth/features/audit_logging.rb 63 def audit_log_message(action) 64 meth = :"audit_log_message_for_#{action}" 65 if respond_to?(meth, true) 66 send(meth) 67 else 68 audit_log_message_default(action) 69 end 70 end
# File lib/rodauth/features/audit_logging.rb 59 def audit_log_message_default(action) 60 action.to_s 61 end
# File lib/rodauth/features/audit_logging.rb 72 def audit_log_metadata(action) 73 meth = :"audit_log_metadata_for_#{action}" 74 if respond_to?(meth, true) 75 send(meth) 76 else 77 audit_log_metadata_default 78 end 79 end
# File lib/rodauth/features/base.rb 118 def auth_class_eval(&block) 119 auth.class_eval(&block) 120 end
# File lib/rodauth/features/base.rb 327 def authenticated? 328 logged_in? 329 end
# File lib/rodauth/features/base.rb 410 def authenticated_by 411 session[authenticated_by_session_key] 412 end
# File lib/rodauth/features/webauthn.rb 242 def authenticated_webauthn_id 243 session[authenticated_webauthn_id_session_key] 244 end
# File lib/rodauth/features/recovery_codes.rb 239 def auto_add_missing_recovery_codes 240 if auto_add_recovery_codes? 241 add_recovery_codes(recovery_codes_limit - recovery_codes.length) 242 end 243 end
# File lib/rodauth/features/recovery_codes.rb 245 def auto_remove_recovery_codes 246 if auto_remove_recovery_codes? && (%w'totp webauthn sms_code' & possible_authentication_methods).empty? 247 recovery_codes_remove 248 end 249 end
# File lib/rodauth/features/base.rb 197 def autocomplete_for_field?(_param) 198 mark_input_fields_with_autocomplete? 199 end
# File lib/rodauth/features/base.rb 423 def autologin_session(autologin_type) 424 login_session('autologin') 425 set_session_value(autologin_type_session_key, autologin_type) 426 end
# File lib/rodauth/features/base.rb 419 def autologin_type 420 session[autologin_type_session_key] 421 end
# File lib/rodauth/features/otp.rb 379 def base32_encode(data, length) 380 chars = 'abcdefghijklmnopqrstuvwxyz234567' 381 length.times.map{|i|chars[data[i].ord % 32]}.join 382 end
# File lib/rodauth/features/base.rb 445 def base_url 446 request.base_url 447 end
# File lib/rodauth/features/verify_account_grace_period.rb 47 def before_change_login_route 48 unless verified_account? 49 set_redirect_error_flash unverified_change_login_error_flash 50 redirect unverified_change_login_redirect 51 end 52 super if defined?(super) 53 end
# File lib/rodauth/features/password_expiration.rb 90 def before_change_password_route 91 check_password_change_allowed 92 super 93 end
# File lib/rodauth/features/lockout.rb 242 def before_login_attempt 243 if locked_out? 244 show_lockout_page 245 end 246 super 247 end
# File lib/rodauth/features/active_sessions.rb 120 def before_logout 121 if param_or_nil(global_logout_param) 122 remove_all_active_sessions 123 else 124 remove_current_session 125 end 126 super 127 end
# File lib/rodauth/features/jwt.rb 226 def before_otp_setup_route 227 super if defined?(super) 228 if use_jwt? && otp_keys_use_hmac? && !param_or_nil(otp_setup_raw_param) 229 _otp_tmp_key(otp_new_secret) 230 json_response[otp_setup_param] = otp_user_key 231 json_response[otp_setup_raw_param] = otp_key 232 end 233 end
# File lib/rodauth/features/account_expiration.rb 79 def before_reset_password 80 check_account_expiration 81 super if defined?(super) 82 end
# File lib/rodauth/features/account_expiration.rb 84 def before_reset_password_request 85 check_account_expiration 86 super if defined?(super) 87 end
# File lib/rodauth/features/jwt.rb 156 def before_rodauth 157 if json_request? 158 if jwt_check_accept? && (accept = request.env['HTTP_ACCEPT']) && accept !~ json_accept_regexp 159 response.status = 406 160 json_response[json_response_error_key] = json_not_accepted_error_message 161 response['Content-Type'] ||= json_response_content_type 162 response.write(_json_response_body(json_response)) 163 request.halt 164 end 165 166 unless request.post? 167 response.status = 405 168 response.headers['Allow'] = 'POST' 169 json_response[json_response_error_key] = json_non_post_error_message 170 return_json_response 171 end 172 elsif only_json? 173 response.status = json_response_error_status 174 response.write non_json_request_error_message 175 request.halt 176 end 177 178 super 179 end
# File lib/rodauth/features/account_expiration.rb 89 def before_unlock_account 90 check_account_expiration 91 super if defined?(super) 92 end
# File lib/rodauth/features/account_expiration.rb 94 def before_unlock_account_request 95 check_account_expiration 96 super if defined?(super) 97 end
# File lib/rodauth/features/webauthn_verify_account.rb 30 def before_verify_account 31 super 32 if features.include?(:jwt) && use_jwt? && !param_or_nil(webauthn_setup_param) 33 cred = new_webauthn_credential 34 json_response[webauthn_setup_param] = cred.as_json 35 json_response[webauthn_setup_challenge_param] = cred.challenge 36 json_response[webauthn_setup_challenge_hmac_param] = compute_hmac(cred.challenge) 37 end 38 @webauthn_credential = webauthn_setup_credential_from_form_submission 39 add_webauthn_credential(@webauthn_credential) 40 end
# File lib/rodauth/features/jwt.rb 181 def before_view_recovery_codes 182 super if defined?(super) 183 if use_jwt? 184 json_response[:codes] = recovery_codes 185 json_response[json_response_success_key] ||= "" if include_success_messages? 186 end 187 end
# File lib/rodauth/features/jwt.rb 199 def before_webauthn_auth_route 200 super if defined?(super) 201 if use_jwt? && !param_or_nil(webauthn_auth_param) 202 cred = webauth_credential_options_for_get 203 json_response[webauthn_auth_param] = cred.as_json 204 json_response[webauthn_auth_challenge_param] = cred.challenge 205 json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge) 206 end 207 end
# File lib/rodauth/features/jwt.rb 209 def before_webauthn_login_route 210 super if defined?(super) 211 if use_jwt? && !param_or_nil(webauthn_auth_param) && account_from_login(param(login_param)) 212 cred = webauth_credential_options_for_get 213 json_response[webauthn_auth_param] = cred.as_json 214 json_response[webauthn_auth_challenge_param] = cred.challenge 215 json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge) 216 end 217 end
# File lib/rodauth/features/jwt.rb 219 def before_webauthn_remove_route 220 super if defined?(super) 221 if use_jwt? && !param_or_nil(webauthn_remove_param) 222 json_response[webauthn_remove_param] = account_webauthn_usage 223 end 224 end
# File lib/rodauth/features/jwt.rb 189 def before_webauthn_setup_route 190 super if defined?(super) 191 if use_jwt? && !param_or_nil(webauthn_setup_param) 192 cred = new_webauthn_credential 193 json_response[webauthn_setup_param] = cred.as_json 194 json_response[webauthn_setup_challenge_param] = cred.challenge 195 json_response[webauthn_setup_challenge_hmac_param] = compute_hmac(cred.challenge) 196 end 197 end
# File lib/rodauth/features/base.rb 368 def button(value, opts={}) 369 scope.render(button_opts(value, opts)) 370 end
# File lib/rodauth/features/base.rb 359 def button_opts(value, opts) 360 opts = Hash[template_opts].merge!(opts) 361 opts[:locals] = {:value=>value, :opts=>opts} 362 opts[:path] = template_path('button') 363 opts[:cache] = cache_templates 364 opts[:cache_key] = :rodauth_button 365 opts 366 end
# File lib/rodauth/features/recovery_codes.rb 168 def can_add_recovery_codes? 169 recovery_codes.length < recovery_codes_limit 170 end
# File lib/rodauth/features/base.rb 531 def catch_error(&block) 532 catch(:rodauth_error, &block) 533 end
# File lib/rodauth/features/change_login.rb 65 def change_login(login) 66 if account_ds.get(login_column).downcase == login.downcase 67 @login_requirement_message = 'same as current login' 68 return false 69 end 70 71 update_login(login) 72 end
# File lib/rodauth/features/verify_login_change.rb 134 def change_login_notice_flash 135 change_login_needs_verification_notice_flash 136 end
# File lib/rodauth/features/change_login.rb 61 def change_login_requires_password? 62 modifications_require_password? 63 end
# File lib/rodauth/features/change_password.rb 66 def change_password_requires_password? 67 modifications_require_password? 68 end
# File lib/rodauth/features/account_expiration.rb 63 def check_account_expiration 64 if account_expired? 65 set_expired unless account_expired_at 66 set_redirect_error_flash account_expiration_error_flash 67 redirect account_expiration_redirect 68 end 69 update_last_login 70 end
# File lib/rodauth/features/active_sessions.rb 46 def check_active_session 47 if logged_in? && !currently_active_session? 48 no_longer_active_session 49 end 50 end
# File lib/rodauth/features/base.rb 271 def check_already_logged_in 272 already_logged_in if logged_in? 273 end
# File lib/rodauth/features/base.rb 343 def check_csrf 344 scope.check_csrf!(check_csrf_opts, &check_csrf_block) 345 end
# File lib/rodauth/features/base.rb 576 def check_csrf? 577 scope.opts[:rodauth_route_csrf] 578 end
# File lib/rodauth/features/password_expiration.rb 30 def check_password_change_allowed 31 if password_changed_at = get_password_changed_at 32 if password_changed_at > Time.now - allow_password_change_after 33 set_redirect_error_flash password_not_changeable_yet_error_flash 34 redirect password_not_changeable_yet_redirect 35 end 36 end 37 end
# File lib/rodauth/features/session_expiration.rb 15 def check_session_expiration 16 return unless logged_in? 17 18 unless session.has_key?(session_last_activity_session_key) && session.has_key?(session_created_session_key) 19 if session_expiration_default 20 expire_session 21 end 22 23 return 24 end 25 26 time = Time.now.to_i 27 28 if session[session_last_activity_session_key] + session_inactivity_timeout < time 29 expire_session 30 end 31 set_session_value(session_last_activity_session_key, time) 32 33 if session[session_created_session_key] + max_session_lifetime < time 34 expire_session 35 end 36 end
# File lib/rodauth/features/single_session.rb 51 def check_single_session 52 if logged_in? && !currently_active_session? 53 no_longer_active_session 54 end 55 end
# File lib/rodauth/features/otp.rb 345 def clear_cached_otp 346 remove_instance_variable(:@otp) if defined?(@otp) 347 end
# File lib/rodauth/features/lockout.rb 164 def clear_invalid_login_attempts 165 unlock_account 166 end
# File lib/rodauth/features/base.rb 287 def clear_session 288 if scope.respond_to?(:clear_session) 289 scope.clear_session 290 else 291 session.clear 292 end 293 end
# File lib/rodauth/features/close_account.rb 64 def close_account 65 unless skip_status_checks? 66 update_account(account_status_column=>account_closed_status_value) 67 end 68 69 unless account_password_hash_column 70 password_hash_ds.delete 71 end 72 end
# File lib/rodauth/features/close_account.rb 60 def close_account_requires_password? 61 modifications_require_password? 62 end
Return urlsafe base64 HMAC for data, assumes hmac_secret is set.
# File lib/rodauth/features/base.rb 231 def compute_hmac(data) 232 s = [compute_raw_hmac(data)].pack('m').chomp!("=\n") 233 s.tr!('+/', '-_') 234 s 235 end
# File lib/rodauth/features/base.rb 623 def compute_raw_hmac(data) 624 OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, hmac_secret, data) 625 end
# File lib/rodauth/features/confirm_password.rb 62 def confirm_password 63 authenticated_by.delete('autologin') 64 authenticated_by.delete('remember') 65 authenticated_by.delete('email_auth') 66 authenticated_by.delete('password') 67 authenticated_by.unshift("password") 68 remove_session_value(autologin_type_session_key) 69 nil 70 end
# File lib/rodauth/features/confirm_password.rb 72 def confirm_password_redirect 73 remove_session_value(confirm_password_redirect_session_key) || default_redirect 74 end
# File lib/rodauth/features/email_base.rb 57 def convert_email_token_key(key) 58 convert_token_key(key) 59 end
# File lib/rodauth/features/base.rb 509 def convert_session_key(key) 510 key = "#{session_key_prefix}#{key}".to_sym if session_key_prefix 511 scope.opts[:sessions_convert_symbols] ? key.to_s : key 512 end
This is needed for jdbc/sqlite, which returns timestamp columns as strings
# File lib/rodauth/features/base.rb 659 def convert_timestamp(timestamp) 660 timestamp = db.to_application_timestamp(timestamp) if timestamp.is_a?(String) 661 timestamp 662 end
# File lib/rodauth/features/base.rb 475 def convert_token_key(key) 476 if key && hmac_secret 477 compute_hmac(key) 478 else 479 key 480 end 481 end
# File lib/rodauth/features/verify_account.rb 226 def create_account_autologin? 227 false 228 end
# File lib/rodauth/features/verify_account.rb 188 def create_account_notice_flash 189 verify_account_email_sent_notice_flash 190 end
# File lib/rodauth/features/verify_account.rb 230 def create_account_set_password? 231 return false if verify_account_set_password? 232 super 233 end
# File lib/rodauth/features/email_base.rb 32 def create_email(subject, body) 33 create_email_to(email_to, subject, body) 34 end
# File lib/rodauth/features/email_auth.rb 230 def create_email_auth_email 231 create_email(email_auth_email_subject, email_auth_email_body) 232 end
# File lib/rodauth/features/email_auth.rb 101 def create_email_auth_key 102 transaction do 103 if email_auth_key_value = get_email_auth_key(account_id) 104 set_email_auth_email_last_sent 105 @email_auth_key_value = email_auth_key_value 106 elsif e = raised_uniqueness_violation{email_auth_ds.insert(email_auth_key_insert_hash)} 107 # If inserting into the email auth table causes a violation, we can pull the 108 # existing email auth key from the table, or reraise. 109 raise e unless @email_auth_key_value = get_email_auth_key(account_id) 110 end 111 end 112 end
# File lib/rodauth/features/email_base.rb 36 def create_email_to(to, subject, body) 37 m = Mail.new 38 m.from = email_from 39 m.to = to 40 m.subject = "#{email_subject_prefix}#{subject}" 41 m.body = body 42 m 43 end
# File lib/rodauth/features/change_password_notify.rb 23 def create_password_changed_email 24 create_email(password_changed_email_subject, password_changed_email_body) 25 end
# File lib/rodauth/features/reset_password.rb 239 def create_reset_password_email 240 create_email(reset_password_email_subject, reset_password_email_body) 241 end
# File lib/rodauth/features/reset_password.rb 164 def create_reset_password_key 165 transaction do 166 if reset_password_key_value = get_password_reset_key(account_id) 167 set_reset_password_email_last_sent 168 @reset_password_key_value = reset_password_key_value 169 elsif e = raised_uniqueness_violation{password_reset_ds.insert(reset_password_key_insert_hash)} 170 # If inserting into the reset password table causes a violation, we can pull the 171 # existing reset password key from the table, or reraise. 172 raise e unless @reset_password_key_value = get_password_reset_key(account_id) 173 end 174 end 175 end
# File lib/rodauth/features/lockout.rb 280 def create_unlock_account_email 281 create_email(unlock_account_email_subject, unlock_account_email_body) 282 end
# File lib/rodauth/features/verify_account.rb 309 def create_verify_account_email 310 create_email(verify_account_email_subject, verify_account_email_body) 311 end
# File lib/rodauth/features/verify_account.rb 292 def create_verify_account_key 293 ds = verify_account_ds 294 transaction do 295 if ds.empty? 296 if e = raised_uniqueness_violation{ds.insert(verify_account_key_insert_hash)} 297 # If inserting into the verify account table causes a violation, we can pull the 298 # key from the verify account table, or reraise. 299 raise e unless @verify_account_key_value = get_verify_account_key(account_id) 300 end 301 end 302 end 303 end
# File lib/rodauth/features/verify_login_change.rb 196 def create_verify_login_change_email(login) 197 create_email_to(login, verify_login_change_email_subject, verify_login_change_email_body) 198 end
# File lib/rodauth/features/verify_login_change.rb 174 def create_verify_login_change_key(login) 175 ds = verify_login_change_ds 176 transaction do 177 ds.where((Sequel::CURRENT_TIMESTAMP > verify_login_change_deadline_column) | ~Sequel.expr(verify_login_change_login_column=>login)).delete 178 if e = raised_uniqueness_violation{ds.insert(verify_login_change_key_insert_hash(login))} 179 old_login, key = get_verify_login_change_login_and_key(account_id) 180 # If inserting into the verify login change table causes a violation, we can pull the 181 # key from the verify login change table if the logins match, or reraise. 182 @verify_login_change_key_value = if old_login.downcase == login.downcase 183 key 184 end 185 raise e unless @verify_login_change_key_value 186 end 187 end 188 end
# File lib/rodauth/features/base.rb 347 def csrf_tag(path=request.path) 348 return unless scope.respond_to?(:csrf_tag) 349 350 if use_request_specific_csrf_tokens? 351 scope.csrf_tag(path) 352 else 353 # :nocov: 354 scope.csrf_tag 355 # :nocov: 356 end 357 end
# File lib/rodauth/features/active_sessions.rb 32 def currently_active_session? 33 return false unless session_id = session[session_id_session_key] 34 35 remove_inactive_sessions 36 ds = active_sessions_ds. 37 where(active_sessions_session_id_column => compute_hmac(session_id)) 38 39 if session_inactivity_deadline 40 ds.update(active_sessions_last_use_column => Sequel::CURRENT_TIMESTAMP) == 1 41 else 42 ds.count == 1 43 end 44 end
# File lib/rodauth/features/base.rb 467 def database_function_password_match?(name, hash_id, password, salt) 468 db.get(Sequel.function(function_name(name), hash_id, BCrypt::Engine.hash_secret(password, salt))) 469 end
# File lib/rodauth/features/base.rb 255 def db 256 Sequel::DATABASES.first 257 end
# File lib/rodauth/features/close_account.rb 74 def delete_account 75 account_ds.delete 76 end
# File lib/rodauth/features/close_account.rb 78 def delete_account_on_close? 79 skip_status_checks? 80 end
# File lib/rodauth/features/remember.rb 157 def disable_remember_login 158 remove_remember_key 159 end
# File lib/rodauth/features/email_auth.rb 248 def email_auth_ds(id=account_id) 249 db[email_auth_table].where(email_auth_id_column=>id) 250 end
# File lib/rodauth/features/email_auth.rb 234 def email_auth_email_body 235 render('email-auth-email') 236 end
# File lib/rodauth/features/email_auth.rb 138 def email_auth_email_link 139 token_link(email_auth_route, email_auth_key_param, email_auth_key_value) 140 end
# File lib/rodauth/features/email_auth.rb 177 def email_auth_email_recently_sent? 178 (email_last_sent = get_email_auth_email_last_sent) && (Time.now - email_last_sent < email_auth_skip_resend_email_within) 179 end
# File lib/rodauth/features/email_auth.rb 242 def email_auth_key_insert_hash 243 hash = {email_auth_id_column=>account_id, email_auth_key_column=>email_auth_key_value} 244 set_deadline_value(hash, email_auth_deadline_column, email_auth_deadline_interval) 245 hash 246 end
# File lib/rodauth/features/email_auth.rb 148 def email_auth_request_form 149 render('email-auth-request-form') 150 end
# File lib/rodauth/features/email_base.rb 45 def email_from 46 "webmaster@#{domain}" 47 end
# File lib/rodauth/features/email_base.rb 49 def email_to 50 account[login_column] 51 end
# File lib/rodauth/features/session_expiration.rb 38 def expire_session 39 clear_session 40 set_redirect_error_status session_expiration_error_status 41 set_redirect_error_flash session_expiration_error_flash 42 redirect session_expiration_redirect 43 end
# File lib/rodauth/features/base.rb 130 def features 131 self.class.features 132 end
# File lib/rodauth/features/base.rb 205 def field_attributes(field) 206 _field_attributes(field) || default_field_attributes 207 end
# File lib/rodauth/features/base.rb 162 def field_error(field) 163 return nil unless @field_errors 164 @field_errors[field] 165 end
# File lib/rodauth/features/base.rb 209 def field_error_attributes(field) 210 if field_error(field) 211 _field_error_attributes(field) 212 end 213 end
# File lib/rodauth/features/remember.rb 140 def forget_login 141 opts = Hash[remember_cookie_options] 142 opts[:path] = "/" unless opts.key?(:path) 143 ::Rack::Utils.delete_cookie_header!(response.headers, remember_cookie_key, opts) 144 end
# File lib/rodauth/features/base.rb 215 def formatted_field_error(field) 216 if error = field_error(field) 217 _formatted_field_error(field, error) 218 end 219 end
# File lib/rodauth/features/base.rb 580 def function_name(name) 581 if db.database_type == :mssql 582 # :nocov: 583 "dbo.#{name}" 584 # :nocov: 585 else 586 name 587 end 588 end
# File lib/rodauth/features/email_auth.rb 226 def generate_email_auth_key_value 227 @email_auth_key_value = random_key 228 end
# File lib/rodauth/features/jwt_refresh.rb 184 def generate_refresh_token 185 hash = jwt_refresh_token_insert_hash 186 [account_id, jwt_refresh_token_ds.insert(hash), convert_token_key(hash[jwt_refresh_token_key_column])].join(token_separator) 187 end
# File lib/rodauth/features/remember.rb 194 def generate_remember_key_value 195 @remember_key_value = random_key 196 end
# File lib/rodauth/features/reset_password.rb 235 def generate_reset_password_key_value 236 @reset_password_key_value = random_key 237 end
# File lib/rodauth/features/lockout.rb 264 def generate_unlock_account_key 265 random_key 266 end
# File lib/rodauth/features/verify_account.rb 288 def generate_verify_account_key_value 289 @verify_account_key_value = random_key 290 end
# File lib/rodauth/features/verify_login_change.rb 170 def generate_verify_login_change_key_value 171 @verify_login_change_key_value = random_key 172 end
# File lib/rodauth/features/jwt_refresh.rb 157 def get_active_refresh_token(account_id, token_id) 158 jwt_refresh_token_account_ds(account_id). 159 where(Sequel::CURRENT_TIMESTAMP > jwt_refresh_token_deadline_column). 160 delete 161 162 jwt_refresh_token_account_token_ds(account_id, token_id). 163 get(jwt_refresh_token_key_column) 164 end
# File lib/rodauth/features/account_expiration.rb 109 def get_activity_timestamp(account_id, column) 110 convert_timestamp(account_activity_ds(account_id).get(column)) 111 end
# File lib/rodauth/features/email_auth.rb 118 def get_email_auth_email_last_sent 119 if column = email_auth_email_last_sent_column 120 if ts = email_auth_ds.get(column) 121 convert_timestamp(ts) 122 end 123 end 124 end
# File lib/rodauth/features/email_auth.rb 142 def get_email_auth_key(id) 143 ds = email_auth_ds(id) 144 ds.where(Sequel::CURRENT_TIMESTAMP > email_auth_deadline_column).delete 145 ds.get(email_auth_key_column) 146 end
# File lib/rodauth/features/password_expiration.rb 26 def get_password_changed_at 27 convert_timestamp(password_expiration_ds.get(password_expiration_changed_at_column)) 28 end
Get the password hash for the user. When using database authentication functions, note that only the salt is returned.
# File lib/rodauth/features/base.rb 598 def get_password_hash 599 if account_password_hash_column 600 (account || account_from_session)[account_password_hash_column] 601 elsif use_database_authentication_functions? 602 db.get(Sequel.function(function_name(:rodauth_get_salt), account ? account_id : session_value)) 603 else 604 # :nocov: 605 password_hash_ds.get(password_hash_column) 606 # :nocov: 607 end 608 end
# File lib/rodauth/features/reset_password.rb 193 def get_password_reset_key(id) 194 ds = password_reset_ds(id) 195 ds.where(Sequel::CURRENT_TIMESTAMP > reset_password_deadline_column).delete 196 ds.get(reset_password_key_column) 197 end
# File lib/rodauth/features/remember.rb 146 def get_remember_key 147 unless @remember_key_value = active_remember_key_ds.get(remember_key_column) 148 generate_remember_key_value 149 transaction do 150 remove_remember_key 151 add_remember_key 152 end 153 end 154 nil 155 end
# File lib/rodauth/features/reset_password.rb 203 def get_reset_password_email_last_sent 204 if column = reset_password_email_last_sent_column 205 if ts = password_reset_ds.get(column) 206 convert_timestamp(ts) 207 end 208 end 209 end
# File lib/rodauth/features/lockout.rb 226 def get_unlock_account_email_last_sent 227 if column = account_lockouts_email_last_sent_column 228 if ts = account_lockouts_ds.get(column) 229 convert_timestamp(ts) 230 end 231 end 232 end
# File lib/rodauth/features/lockout.rb 210 def get_unlock_account_key 211 account_lockouts_ds.get(account_lockouts_key_column) 212 end
# File lib/rodauth/features/verify_account.rb 239 def get_verify_account_email_last_sent 240 if column = verify_account_email_last_sent_column 241 if ts = verify_account_ds.get(column) 242 convert_timestamp(ts) 243 end 244 end 245 end
# File lib/rodauth/features/verify_account.rb 218 def get_verify_account_key(id) 219 verify_account_ds(id).get(verify_account_key_column) 220 end
# File lib/rodauth/features/verify_login_change.rb 130 def get_verify_login_change_login_and_key(id) 131 verify_login_change_ds(id).get([verify_login_change_login_column, verify_login_change_key_column]) 132 end
# File lib/rodauth/features/active_sessions.rb 70 def handle_duplicate_active_session_id(_e) 71 # Do nothing by default as session is already tracked. This will result in 72 # the current session and the existing session with the same id 73 # being tracked together, so that a logout of one will logout 74 # the other, and updating the last use on one will update the other, 75 # but this should be acceptable. However, this can be overridden if different 76 # behavior is desired. 77 end
# File lib/rodauth/features/webauthn.rb 344 def handle_webauthn_sign_count_verification_error 345 throw_error_status(invalid_field_error_status, webauthn_auth_param, webauthn_invalid_sign_count_message) 346 end
# File lib/rodauth/features/base.rb 590 def has_password? 591 return @has_password if defined?(@has_password) 592 return false unless account || session_value 593 @has_password = !!get_password_hash 594 end
# File lib/rodauth/features/audit_logging.rb 31 def hook_action(hook_type, action) 32 super 33 # In after_logout, session is already cleared, so use before_logout in that case 34 if (hook_type == :after || action == :logout) && (id = account ? account_id : session_value) 35 add_audit_log(id, action) 36 end 37 end
# File lib/rodauth/features/http_basic_auth.rb 34 def http_basic_auth 35 return @checked_http_basic_auth if defined?(@checked_http_basic_auth) 36 37 @checked_http_basic_auth = nil 38 return unless token = ((v = request.env['HTTP_AUTHORIZATION']) && v[/\A *Basic (.*)\Z/, 1]) 39 40 username, password = token.unpack("m*").first.split(/:/, 2) 41 return unless username && password 42 43 catch_error do 44 unless account_from_login(username) 45 throw_basic_auth_error(login_param, no_matching_login_message) 46 end 47 48 before_login_attempt 49 50 unless open_account? 51 throw_basic_auth_error(login_param, no_matching_login_message) 52 end 53 54 unless password_match?(password) 55 after_login_failure 56 throw_basic_auth_error(password_param, invalid_password_message) 57 end 58 59 transaction do 60 before_login 61 login_session('password') 62 after_login 63 end 64 65 @checked_http_basic_auth = true 66 return true 67 end 68 69 nil 70 end
# File lib/rodauth/features/active_sessions.rb 141 def inactive_session_cond 142 cond = session_inactivity_deadline_condition 143 cond2 = session_lifetime_deadline_condition 144 return false unless cond || cond2 145 Sequel.|(*[cond, cond2].compact) 146 end
# File lib/rodauth/features/jwt.rb 255 def include_success_messages? 256 !json_response_success_key.nil? 257 end
# File lib/rodauth/features/base.rb 173 def input_field_string(param, id, opts={}) 174 type = opts.fetch(:type, "text") 175 176 unless type == "password" 177 value = opts.fetch(:value){scope.h param(param)} 178 end 179 180 field_class = opts.fetch(:class, "form-control") 181 182 if autocomplete_for_field?(param) && opts[:autocomplete] 183 autocomplete = "autocomplete=\"#{opts[:autocomplete]}\"" 184 end 185 186 if inputmode_for_field?(param) && opts[:inputmode] 187 inputmode = "inputmode=\"#{opts[:inputmode]}\"" 188 end 189 190 if mark_input_fields_as_required? && opts[:required] != false 191 required = "required=\"required\"" 192 end 193 194 "<input #{opts[:attr]} #{autocomplete} #{inputmode} #{required} #{field_attributes(param)} #{field_error_attributes(param)} type=\"#{type}\" class=\"#{field_class}#{add_field_error_class(param)}\" name=\"#{param}\" id=\"#{id}\" value=\"#{value}\"/> #{formatted_field_error(param) unless opts[:skip_error_message]}" 195 end
# File lib/rodauth/features/base.rb 201 def inputmode_for_field?(_param) 202 mark_input_fields_with_inputmode? 203 end
# File lib/rodauth/features/lockout.rb 168 def invalid_login_attempted 169 ds = account_login_failures_ds. 170 where(account_login_failures_id_column=>account_id) 171 172 number = if db.database_type == :postgres 173 ds.returning(account_login_failures_number_column). 174 with_sql(:update_sql, account_login_failures_number_column=>Sequel.expr(account_login_failures_number_column)+1). 175 single_value 176 else 177 # :nocov: 178 if ds.update(account_login_failures_number_column=>Sequel.expr(account_login_failures_number_column)+1) > 0 179 ds.get(account_login_failures_number_column) 180 end 181 # :nocov: 182 end 183 184 unless number 185 # Ignoring the violation is safe here. It may allow slightly more than max_invalid_logins invalid logins before 186 # lockout, but allowing a few extra is OK if the race is lost. 187 ignore_uniqueness_violation{account_login_failures_ds.insert(account_login_failures_id_column=>account_id)} 188 number = 1 189 end 190 191 if number >= max_invalid_logins 192 @unlock_account_key_value = generate_unlock_account_key 193 hash = {account_lockouts_id_column=>account_id, account_lockouts_key_column=>unlock_account_key_value} 194 set_deadline_value(hash, account_lockouts_deadline_column, account_lockouts_deadline_interval) 195 196 if e = raised_uniqueness_violation{account_lockouts_ds.insert(hash)} 197 # If inserting into the lockout table raises a violation, we should just be able to pull the already inserted 198 # key out of it. If that doesn't return a valid key, we should reraise the error. 199 raise e unless @unlock_account_key_value = account_lockouts_ds.get(account_lockouts_key_column) 200 201 after_account_lockout 202 show_lockout_page 203 else 204 after_account_lockout 205 e 206 end 207 end 208 end
# File lib/rodauth/features/change_password.rb 70 def invalid_previous_password_message 71 invalid_password_message 72 end
# File lib/rodauth/features/jwt.rb 107 def json_request? 108 return @json_request if defined?(@json_request) 109 @json_request = request.content_type =~ json_request_content_type_regexp 110 end
# File lib/rodauth/features/jwt.rb 271 def json_response 272 @json_response ||= {} 273 end
# File lib/rodauth/features/jwt_cors.rb 15 def jwt_cors_allow? 16 return false unless origin = request.env['HTTP_ORIGIN'] 17 18 case allowed = jwt_cors_allow_origin 19 when String 20 timing_safe_eql?(origin, allowed) 21 when Array 22 allowed.any?{|s| timing_safe_eql?(origin, s)} 23 when Regexp 24 allowed =~ origin 25 when true 26 true 27 else 28 false 29 end 30 end
# File lib/rodauth/features/jwt.rb 239 def jwt_payload 240 return @jwt_payload if defined?(@jwt_payload) 241 @jwt_payload = JWT.decode(jwt_token, jwt_secret, true, _jwt_decode_opts.merge(:algorithm=>jwt_algorithm))[0] 242 rescue JWT::DecodeError => e 243 rescue_jwt_payload(e) 244 end
# File lib/rodauth/features/jwt_refresh.rb 166 def jwt_refresh_token_account_ds(account_id) 167 jwt_refresh_token_ds.where(jwt_refresh_token_account_id_column => account_id) 168 end
# File lib/rodauth/features/jwt_refresh.rb 170 def jwt_refresh_token_account_token_ds(account_id, token_id) 171 jwt_refresh_token_account_ds(account_id). 172 where(jwt_refresh_token_id_column=>token_id) 173 end
# File lib/rodauth/features/jwt_refresh.rb 175 def jwt_refresh_token_ds 176 db[jwt_refresh_token_table] 177 end
# File lib/rodauth/features/jwt_refresh.rb 189 def jwt_refresh_token_insert_hash 190 hash = {jwt_refresh_token_account_id_column => account_id, jwt_refresh_token_key_column => random_key} 191 set_deadline_value(hash, jwt_refresh_token_deadline_column, jwt_refresh_token_deadline_interval) 192 hash 193 end
# File lib/rodauth/features/jwt_refresh.rb 148 def jwt_refresh_token_match?(key) 149 # We don't need to match tokens if we are requiring a valid current access token 150 return true unless allow_refresh_with_expired_jwt_access_token? 151 152 # If allowing with expired jwt access token, check the expired session contains 153 # hmac matching submitted and active refresh token. 154 timing_safe_eql?(compute_hmac(session[jwt_refresh_token_data_session_key].to_s + key), session[jwt_refresh_token_hmac_session_key].to_s) 155 end
# File lib/rodauth/features/jwt.rb 112 def jwt_secret 113 raise ArgumentError, "jwt_secret not set" 114 end
# File lib/rodauth/features/jwt.rb 116 def jwt_session_hash 117 jwt_session_key ? {jwt_session_key=>session} : session 118 end
# File lib/rodauth/features/jwt.rb 124 def jwt_token 125 return @jwt_token if defined?(@jwt_token) 126 127 if (v = request.env['HTTP_AUTHORIZATION']) && v !~ jwt_authorization_ignore 128 @jwt_token = v.sub(jwt_authorization_remove, '') 129 end 130 end
# File lib/rodauth/features/account_expiration.rb 27 def last_account_activity_at 28 get_activity_timestamp(session_value, account_activity_last_activity_column) 29 end
# File lib/rodauth/features/account_expiration.rb 31 def last_account_login_at 32 get_activity_timestamp(session_value, account_activity_last_login_column) 33 end
# File lib/rodauth/features/remember.rb 84 def load_memory 85 return if session[session_key] 86 return unless cookie = request.cookies[remember_cookie_key] 87 id, key = cookie.split('_', 2) 88 return unless id && key 89 90 actual, deadline = active_remember_key_ds(id).get([remember_key_column, remember_deadline_column]) 91 unless actual 92 forget_login 93 return 94 end 95 96 if hmac_secret 97 unless valid = timing_safe_eql?(key, compute_hmac(actual)) 98 unless raw_remember_token_deadline && raw_remember_token_deadline > convert_timestamp(deadline) 99 forget_login 100 return 101 end 102 end 103 end 104 105 unless valid || timing_safe_eql?(key, actual) 106 forget_login 107 return 108 end 109 110 set_session_value(session_key, id) 111 account = account_from_session 112 remove_session_value(session_key) 113 114 unless account 115 remove_remember_key(id) 116 forget_login 117 return 118 end 119 120 before_load_memory 121 login_session('remember') 122 123 if extend_remember_deadline? 124 active_remember_key_ds(id).update(remember_deadline_column=>Sequel.date_add(Sequel::CURRENT_TIMESTAMP, remember_period)) 125 remember_login 126 end 127 after_load_memory 128 end
# File lib/rodauth/features/base.rb 664 def loaded_templates 665 [] 666 end
# File lib/rodauth/features/lockout.rb 145 def locked_out? 146 if t = convert_timestamp(account_lockouts_ds.get(account_lockouts_deadline_column)) 147 if Time.now < t 148 true 149 else 150 unlock_account 151 false 152 end 153 else 154 false 155 end 156 end
# File lib/rodauth/features/remember.rb 176 def logged_in_via_remember_key? 177 authenticated_by.include?('remember') 178 end
# File lib/rodauth/features/login.rb 77 def login(auth_type) 78 saved_login_redirect = remove_session_value(login_redirect_session_key) 79 transaction do 80 before_login 81 login_session(auth_type) 82 yield if block_given? 83 after_login 84 end 85 set_notice_flash login_notice_flash 86 redirect(saved_login_redirect || login_redirect) 87 end
# File lib/rodauth/features/login_password_requirements_base.rb 39 def login_confirm_label 40 "Confirm #{login_label}" 41 end
# File lib/rodauth/features/login_password_requirements_base.rb 84 def login_does_not_meet_requirements_message 85 "invalid login#{", #{login_requirement_message}" if login_requirement_message}" 86 end
# File lib/rodauth/features/reset_password.rb 243 def login_failed_reset_password_request_form 244 render("reset-password-request") 245 end
# File lib/rodauth/features/base.rb 279 def login_input_type 280 login_uses_email? ? 'email' : 'text' 281 end
# File lib/rodauth/features/login_password_requirements_base.rb 108 def login_meets_email_requirements?(login) 109 return true unless require_email_address_logins? 110 return true if login_valid_email?(login) 111 @login_requirement_message = login_not_valid_email_message 112 return false 113 end
# File lib/rodauth/features/login_password_requirements_base.rb 96 def login_meets_length_requirements?(login) 97 if login_minimum_length > login.length 98 @login_requirement_message = login_too_short_message 99 false 100 elsif login_maximum_length < login.length 101 @login_requirement_message = login_too_long_message 102 false 103 else 104 true 105 end 106 end
# File lib/rodauth/features/login_password_requirements_base.rb 47 def login_meets_requirements?(login) 48 login_meets_length_requirements?(login) && \ 49 login_meets_email_requirements?(login) 50 end
# File lib/rodauth/features/base.rb 295 def login_required 296 set_redirect_error_status(login_required_error_status) 297 set_redirect_error_flash require_login_error_flash 298 redirect require_login_redirect 299 end
# File lib/rodauth/features/login.rb 96 def login_return_to_requested_location_path 97 request.fullpath if request.get? 98 end
# File lib/rodauth/features/base.rb 414 def login_session(auth_type) 415 update_session 416 set_session_value(authenticated_by_session_key, [auth_type]) 417 end
# File lib/rodauth/features/login_password_requirements_base.rb 88 def login_too_long_message 89 "maximum #{login_maximum_length} characters" 90 end
# File lib/rodauth/features/login_password_requirements_base.rb 92 def login_too_short_message 93 "minimum #{login_minimum_length} characters" 94 end
# File lib/rodauth/features/base.rb 283 def login_uses_email? 284 login_column == :email 285 end
# File lib/rodauth/features/login_password_requirements_base.rb 115 def login_valid_email?(login) 116 login =~ login_email_regexp 117 end
# File lib/rodauth/features/active_sessions.rb 93 def logout_additional_form_tags 94 super.to_s + render('global-logout-field') 95 end
# File lib/rodauth/features/base.rb 453 def modifications_require_password? 454 has_password? 455 end
# File lib/rodauth/features/create_account.rb 94 def new_account(login) 95 @account = _new_account(login) 96 end
# File lib/rodauth/features/recovery_codes.rb 231 def new_recovery_code 232 random_key 233 end
# File lib/rodauth/features/webauthn.rb 293 def new_webauthn_credential 294 WebAuthn::Credential.options_for_create( 295 :timeout => webauthn_setup_timeout, 296 :rp => {:name=>webauthn_rp_name, :id=>webauthn_rp_id}, 297 :user => {:id=>account_webauthn_user_id, :name=>webauthn_user_name}, 298 :authenticator_selection => webauthn_authenticator_selection, 299 :attestation => webauthn_attestation, 300 :extensions => webauthn_extensions, 301 :exclude => account_webauthn_ids, 302 ) 303 end
# File lib/rodauth/features/active_sessions.rb 52 def no_longer_active_session 53 clear_session 54 set_redirect_error_status inactive_session_error_status 55 set_redirect_error_flash active_sessions_error_flash 56 redirect active_sessions_redirect 57 end
# File lib/rodauth/features/base.rb 381 def only_json? 382 scope.class.opts[:rodauth_json] == :only 383 end
# File lib/rodauth/features/base.rb 251 def open_account? 252 skip_status_checks? || account[account_status_column] == account_open_status_value 253 end
# File lib/rodauth/features/otp.rb 259 def otp_add_key 260 _otp_add_key(otp_key) 261 super if defined?(super) 262 end
# File lib/rodauth/features/otp.rb 234 def otp_exists? 235 !otp_key.nil? 236 end
# File lib/rodauth/features/otp.rb 354 def otp_hmac_secret(key) 355 base32_encode(compute_raw_hmac(ROTP::Base32.decode(key)), key.bytesize) 356 end
# File lib/rodauth/features/otp.rb 290 def otp_issuer 291 domain 292 end
# File lib/rodauth/features/otp.rb 405 def otp_key_ds 406 db[otp_keys_table].where(otp_keys_id_column=>session_value) 407 end
# File lib/rodauth/features/otp.rb 310 def otp_keys_use_hmac? 311 !!hmac_secret 312 end
# File lib/rodauth/features/otp.rb 270 def otp_last_use 271 convert_timestamp(otp_key_ds.get(otp_keys_last_use_column)) 272 end
# File lib/rodauth/features/otp.rb 282 def otp_locked_out? 283 otp_key_ds.get(otp_keys_failures_column) >= otp_auth_failures_limit 284 end
# File lib/rodauth/features/otp.rb 368 def otp_new_secret 369 ROTP::Base32.random_base32.downcase 370 end
# File lib/rodauth/features/otp.rb 294 def otp_provisioning_name 295 account[login_column] 296 end
# File lib/rodauth/features/otp.rb 286 def otp_provisioning_uri 287 otp.provisioning_uri(otp_provisioning_name) 288 end
# File lib/rodauth/features/otp.rb 298 def otp_qr_code 299 RQRCode::QRCode.new(otp_provisioning_uri).as_svg(:module_size=>8) 300 end
# File lib/rodauth/features/otp.rb 274 def otp_record_authentication_failure 275 otp_key_ds.update(otp_keys_failures_column=>Sequel.identifier(otp_keys_failures_column) + 1) 276 end
# File lib/rodauth/features/otp.rb 254 def otp_remove 255 otp_key_ds.delete 256 @otp_key = nil 257 end
# File lib/rodauth/features/otp.rb 278 def otp_remove_auth_failures 279 otp_key_ds.update(otp_keys_failures_column=>0) 280 end
# File lib/rodauth/features/otp.rb 349 def otp_tmp_key(secret) 350 _otp_tmp_key(secret) 351 clear_cached_otp 352 end
# File lib/rodauth/features/otp.rb 264 def otp_update_last_use 265 otp_key_ds. 266 where(Sequel.date_add(otp_keys_last_use_column, :seconds=>(otp_interval||30)) < Sequel::CURRENT_TIMESTAMP). 267 update(otp_keys_last_use_column=>Sequel::CURRENT_TIMESTAMP) == 1 268 end
# File lib/rodauth/features/otp.rb 302 def otp_user_key 303 @otp_user_key ||= if otp_keys_use_hmac? 304 otp_hmac_secret(otp_key) 305 else 306 otp_key 307 end 308 end
# File lib/rodauth/features/otp.rb 238 def otp_valid_code?(ot_pass) 239 return false unless otp_exists? 240 ot_pass = ot_pass.gsub(/\s+/, '') 241 if drift = otp_drift 242 if otp.respond_to?(:verify_with_drift) 243 # :nocov: 244 otp.verify_with_drift(ot_pass, drift) 245 # :nocov: 246 else 247 otp.verify(ot_pass, :drift_behind=>drift, :drift_ahead=>drift) 248 end 249 else 250 otp.verify(ot_pass) 251 end 252 end
# File lib/rodauth/features/otp.rb 358 def otp_valid_key?(secret) 359 return false unless secret =~ /\A([a-z2-7]{16}|[a-z2-7]{32})\z/ 360 if otp_keys_use_hmac? 361 timing_safe_eql?(otp_hmac_secret(param(otp_setup_raw_param)), secret) 362 else 363 true 364 end 365 end
Return a string for the parameter name. This will be an empty string if the parameter doesn't exist.
# File lib/rodauth/features/base.rb 430 def param(key) 431 param_or_nil(key).to_s 432 end
Return a string for the parameter name, or nil if there is no parameter with that name.
# File lib/rodauth/features/base.rb 436 def param_or_nil(key) 437 value = raw_param(key) 438 value.to_s unless value.nil? 439 end
# File lib/rodauth/features/change_password_notify.rb 27 def password_changed_email_body 28 render('password-changed-email') 29 end
# File lib/rodauth/features/login_password_requirements_base.rb 43 def password_confirm_label 44 "Confirm #{password_label}" 45 end
# File lib/rodauth/features/login_password_requirements_base.rb 125 def password_does_not_contain_null_byte?(password) 126 return true unless password.include?("\0") 127 @password_requirement_message = 'contains null byte' 128 false 129 end
# File lib/rodauth/features/login_password_requirements_base.rb 76 def password_does_not_meet_requirements_message 77 "invalid password, does not meet requirements#{" (#{password_requirement_message})" if password_requirement_message}" 78 end
# File lib/rodauth/features/disallow_password_reuse.rb 47 def password_doesnt_match_previous_password?(password) 48 match = if use_database_authentication_functions? 49 salts = previous_password_ds. 50 select_map([previous_password_id_column, Sequel.function(function_name(:rodauth_get_previous_salt), previous_password_id_column).as(:salt)]) 51 return true if salts.empty? 52 53 salts.any? do |hash_id, salt| 54 database_function_password_match?(:rodauth_previous_password_hash_match, hash_id, password, salt) 55 end 56 else 57 # :nocov: 58 previous_password_ds.select_map(previous_password_hash_column).any? do |hash| 59 password_hash_match?(hash, password) 60 end 61 # :nocov: 62 end 63 64 return true unless match 65 @password_requirement_message = password_same_as_previous_password_message 66 false 67 end
# File lib/rodauth/features/password_expiration.rb 107 def password_expiration_ds 108 db[password_expiration_table].where(password_expiration_id_column=>account_id) 109 end
# File lib/rodauth/features/password_expiration.rb 68 def password_expired? 69 if password_changed_at = session[password_changed_at_session_key] 70 return password_changed_at + require_password_change_after < Time.now.to_i 71 end 72 73 account_from_session 74 if password_changed_at = get_password_changed_at 75 set_session_value(password_changed_at_session_key, password_changed_at.to_i) 76 password_changed_at + require_password_change_after < Time.now 77 else 78 set_session_value(password_changed_at_session_key, password_expiration_default ? 0 : 2147483647) 79 password_expiration_default 80 end 81 end
# File lib/rodauth/features/base.rb 259 def password_field_autocomplete_value 260 @password_field_autocomplete_value || 'current-password' 261 end
# File lib/rodauth/features/password_complexity.rb 54 def password_has_enough_character_groups?(password) 55 return true if password.length > password_max_length_for_groups_check 56 return true if password_character_groups.select{|re| password =~ re}.length >= password_min_groups 57 @password_requirement_message = password_not_enough_character_groups_message 58 false 59 end
# File lib/rodauth/features/password_complexity.rb 61 def password_has_no_invalid_pattern?(password) 62 return true unless password_invalid_pattern 63 return true if password !~ password_invalid_pattern 64 @password_requirement_message = password_invalid_pattern_message 65 false 66 end
# File lib/rodauth/features/login_password_requirements_base.rb 143 def password_hash(password) 144 BCrypt::Password.create(password, :cost=>password_hash_cost) 145 end
# File lib/rodauth/features/login_password_requirements_base.rb 132 def password_hash_cost 133 BCrypt::Engine::MIN_COST 134 end
# File lib/rodauth/features/base.rb 654 def password_hash_ds 655 db[password_hash_table].where(password_hash_id_column=>account ? account_id : session_value) 656 end
# File lib/rodauth/features/base.rb 471 def password_hash_match?(hash, password) 472 BCrypt::Password.new(hash) == password 473 end
# File lib/rodauth/features/base.rb 395 def password_match?(password) 396 if hash = get_password_hash 397 if account_password_hash_column || !use_database_authentication_functions? 398 password_hash_match?(hash, password) 399 else 400 database_function_password_match?(:rodauth_valid_password_hash, account_id, password, hash) 401 end 402 end 403 end
# File lib/rodauth/features/login_password_requirements_base.rb 119 def password_meets_length_requirements?(password) 120 return true if password_minimum_length <= password.length 121 @password_requirement_message = password_too_short_message 122 false 123 end
# File lib/rodauth/features/disallow_common_passwords.rb 13 def password_meets_requirements?(password) 14 super && password_not_one_of_the_most_common?(password) 15 end
# File lib/rodauth/features/password_complexity.rb 75 def password_not_in_dictionary?(password) 76 return true unless dict = password_dictionary 77 return true unless password =~ /\A(?:\d*)([A-Za-z!@$+|][A-Za-z!@$+|0134578]+[A-Za-z!@$+|])(?:\d*)\z/ 78 word = $1.downcase.tr('!@$+|0134578', 'iastloleastb') 79 return true if !dict.include?(word) 80 @password_requirement_message = password_in_dictionary_message 81 false 82 end
# File lib/rodauth/features/disallow_common_passwords.rb 33 def password_not_one_of_the_most_common?(password) 34 return true unless password_one_of_most_common?(password) 35 @password_requirement_message = password_is_one_of_the_most_common_message 36 false 37 end
# File lib/rodauth/features/password_complexity.rb 68 def password_not_too_many_repeating_characters?(password) 69 return true if password_max_repeating_characters < 2 70 return true if password !~ /(.)(\1){#{password_max_repeating_characters-1}}/ 71 @password_requirement_message = password_too_many_repeating_characters_message 72 false 73 end
# File lib/rodauth/features/disallow_common_passwords.rb 27 def password_one_of_most_common?(password) 28 most_common_passwords.include?(password) 29 end
# File lib/rodauth/features/password_grace_period.rb 22 def password_recently_entered? 23 return false unless last_password_entry = session[last_password_entry_session_key] 24 last_password_entry + password_grace_period > Time.now.to_i 25 end
# File lib/rodauth/features/reset_password.rb 261 def password_reset_ds(id=account_id) 262 db[reset_password_table].where(reset_password_id_column=>id) 263 end
# File lib/rodauth/features/login_password_requirements_base.rb 80 def password_too_short_message 81 "minimum #{password_minimum_length} characters" 82 end
# File lib/rodauth/features/base.rb 457 def possible_authentication_methods 458 has_password? ? ['password'] : [] 459 end
# File lib/rodauth/features/base.rb 385 def post_configure 386 require 'bcrypt' if require_bcrypt? 387 db.extension :date_arithmetic if use_date_arithmetic? 388 route_hash= {} 389 self.class.routes.each do |meth| 390 route_hash["/#{send("#{meth.to_s.sub(/\Ahandle_/, '')}_route")}"] = meth 391 end 392 self.class.route_hash = route_hash.freeze 393 end
# File lib/rodauth/features/disallow_password_reuse.rb 81 def previous_password_ds 82 db[previous_password_hash_table].where(previous_password_account_id_column=>account_id) 83 end
In cases where retrying on uniqueness violations cannot work, this will detect whether a uniqueness violation is raised by the block and return the exception if so. This method should be used if you don't care about the exception itself.
# File lib/rodauth/features/base.rb 683 def raises_uniqueness_violation?(&block) 684 transaction(:savepoint=>:only, &block) 685 false 686 rescue unique_constraint_violation_class => e 687 e 688 end
# File lib/rodauth/features/base.rb 505 def random_key 506 SecureRandom.urlsafe_base64(32) 507 end
# File lib/rodauth/features/base.rb 441 def raw_param(key) 442 request.params[key] 443 end
# File lib/rodauth/features/recovery_codes.rb 155 def recovery_code_match?(code) 156 recovery_codes.each do |s| 157 if timing_safe_eql?(code, s) 158 recovery_codes_ds.where(recovery_codes_column=>code).delete 159 if recovery_codes_primary? 160 add_recovery_code 161 end 162 return true 163 end 164 end 165 false 166 end
# File lib/rodauth/features/recovery_codes.rb 255 def recovery_codes_ds 256 db[recovery_codes_table].where(recovery_codes_id_column=>session_value) 257 end
# File lib/rodauth/features/recovery_codes.rb 235 def recovery_codes_primary? 236 (features & [:otp, :sms_codes, :webauthn]).empty? 237 end
# File lib/rodauth/features/recovery_codes.rb 151 def recovery_codes_remove 152 recovery_codes_ds.delete 153 end
# File lib/rodauth/features/base.rb 487 def redirect(path) 488 request.redirect(path) 489 end
# File lib/rodauth/features/two_factor_base.rb 235 def redirect_two_factor_authenticated 236 saved_two_factor_auth_redirect = remove_session_value(two_factor_auth_redirect_session_key) 237 redirect saved_two_factor_auth_redirect || two_factor_auth_redirect 238 end
# File lib/rodauth/features/remember.rb 202 def remember_key_ds(id=account_id) 203 db[remember_table].where(remember_id_column=>id) 204 end
# File lib/rodauth/features/remember.rb 130 def remember_login 131 get_remember_key 132 opts = Hash[remember_cookie_options] 133 opts[:value] = "#{account_id}_#{convert_token_key(remember_key_value)}" 134 opts[:expires] = convert_timestamp(active_remember_key_ds.get(remember_deadline_column)) 135 opts[:path] = "/" unless opts.key?(:path) 136 opts[:httponly] = true unless opts.key?(:httponly) 137 ::Rack::Utils.set_cookie_header!(response.headers, remember_cookie_key, opts) 138 end
# File lib/rodauth/features/active_sessions.rb 83 def remove_all_active_sessions 84 active_sessions_ds.delete 85 end
# File lib/rodauth/features/webauthn.rb 383 def remove_all_webauthn_keys_and_user_ids 384 webauthn_user_ids_ds.delete 385 webauthn_keys_ds.delete 386 end
# File lib/rodauth/features/active_sessions.rb 79 def remove_current_session 80 active_sessions_ds.where(active_sessions_session_id_column=>compute_hmac(session[session_id_session_key])).delete 81 end
# File lib/rodauth/features/email_auth.rb 126 def remove_email_auth_key 127 email_auth_ds.delete 128 end
# File lib/rodauth/features/active_sessions.rb 87 def remove_inactive_sessions 88 if cond = inactive_session_cond 89 active_sessions_ds.where(cond).delete 90 end 91 end
# File lib/rodauth/features/jwt_refresh.rb 179 def remove_jwt_refresh_token_key(token) 180 account_id, token_id, _ = _account_refresh_token_split(token) 181 jwt_refresh_token_account_token_ds(account_id, token_id).delete 182 end
# File lib/rodauth/features/lockout.rb 268 def remove_lockout_metadata 269 account_login_failures_ds.delete 270 account_lockouts_ds.delete 271 end
# File lib/rodauth/features/remember.rb 172 def remove_remember_key(id=account_id) 173 remember_key_ds(id).delete 174 end
# File lib/rodauth/features/reset_password.rb 177 def remove_reset_password_key 178 password_reset_ds.delete 179 end
# File lib/rodauth/features/base.rb 722 def remove_session_value(key) 723 session.delete(key) 724 end
# File lib/rodauth/features/verify_account.rb 172 def remove_verify_account_key 173 verify_account_ds.delete 174 end
# File lib/rodauth/features/verify_login_change.rb 106 def remove_verify_login_change_key 107 verify_login_change_ds.delete 108 end
# File lib/rodauth/features/webauthn.rb 379 def remove_webauthn_key(webauthn_id) 380 webauthn_keys_ds.where(webauthn_keys_webauthn_id_column=>webauthn_id).delete == 1 381 end
# File lib/rodauth/features/base.rb 377 def render(page) 378 _view(:render, page) 379 end
# File lib/rodauth/features/login.rb 125 def render_multi_phase_login_forms 126 multi_phase_login_forms.sort.map{|_, form, _| form}.join("\n") 127 end
# File lib/rodauth/features/base.rb 134 def request 135 scope.request 136 end
# File lib/rodauth/features/base.rb 519 def require_account 520 require_authentication 521 require_account_session 522 end
# File lib/rodauth/features/base.rb 524 def require_account_session 525 unless account_from_session 526 clear_session 527 login_required 528 end 529 end
# File lib/rodauth/features/base.rb 331 def require_authentication 332 require_login 333 end
# File lib/rodauth/features/password_expiration.rb 61 def require_current_password 62 if authenticated? && password_expired? && password_change_needed_redirect != request.path_info 63 set_redirect_error_flash password_expiration_error_flash 64 redirect password_change_needed_redirect 65 end 66 end
# File lib/rodauth/features/http_basic_auth.rb 27 def require_http_basic_auth 28 unless http_basic_auth 29 set_http_basic_auth_error_response 30 request.halt 31 end 32 end
# File lib/rodauth/features/base.rb 323 def require_login 324 login_required unless logged_in? 325 end
# File lib/rodauth/features/verify_account.rb 164 def require_login_confirmation? 165 false 166 end
# File lib/rodauth/features/otp.rb 226 def require_otp_setup 227 unless otp_exists? 228 set_redirect_error_status(two_factor_not_setup_error_status) 229 set_redirect_error_flash two_factor_not_setup_error_flash 230 redirect two_factor_need_setup_redirect 231 end 232 end
# File lib/rodauth/features/confirm_password.rb 51 def require_password_authentication 52 require_login 53 54 if require_password_authentication? && has_password? 55 set_redirect_error_status(password_authentication_required_error_status) 56 set_redirect_error_flash password_authentication_required_error_flash 57 set_session_value(confirm_password_redirect_session_key, request.fullpath) 58 redirect password_authentication_required_redirect 59 end 60 end
# File lib/rodauth/features/confirm_password.rb 86 def require_password_authentication? 87 return true if defined?(super) && super 88 !authenticated_by.include?('password') 89 end
# File lib/rodauth/features/sms_codes.rb 318 def require_sms_available 319 require_sms_setup 320 321 if sms_locked_out? 322 set_redirect_error_status(lockout_error_status) 323 set_redirect_error_flash sms_lockout_error_flash 324 redirect sms_lockout_redirect 325 end 326 end
# File lib/rodauth/features/sms_codes.rb 310 def require_sms_not_setup 311 if sms_setup? 312 set_redirect_error_status(sms_already_setup_error_status) 313 set_redirect_error_flash sms_already_setup_error_flash 314 redirect sms_already_setup_redirect 315 end 316 end
# File lib/rodauth/features/sms_codes.rb 302 def require_sms_setup 303 unless sms_setup? 304 set_redirect_error_status(two_factor_not_setup_error_status) 305 set_redirect_error_flash sms_not_setup_error_flash 306 redirect sms_needs_setup_redirect 307 end 308 end
# File lib/rodauth/features/two_factor_base.rb 159 def require_two_factor_authenticated 160 unless two_factor_authenticated? 161 if two_factor_auth_return_to_requested_location? 162 set_session_value(two_factor_auth_redirect_session_key, request.fullpath) 163 end 164 set_redirect_error_status(two_factor_need_authentication_error_status) 165 set_redirect_error_flash two_factor_need_authentication_error_flash 166 redirect two_factor_auth_required_redirect 167 end 168 end
# File lib/rodauth/features/two_factor_base.rb 151 def require_two_factor_not_authenticated(auth_type = nil) 152 if two_factor_authenticated? || (auth_type && two_factor_login_type_match?(auth_type)) 153 set_redirect_error_status(two_factor_already_authenticated_error_status) 154 set_redirect_error_flash two_factor_already_authenticated_error_flash 155 redirect two_factor_already_authenticated_redirect 156 end 157 end
# File lib/rodauth/features/two_factor_base.rb 140 def require_two_factor_setup 141 # Avoid database query if already authenticated via 2nd factor 142 return if two_factor_authenticated? 143 144 return if uses_two_factor_authentication? 145 146 set_redirect_error_status(two_factor_not_setup_error_status) 147 set_redirect_error_flash two_factor_not_setup_error_flash 148 redirect two_factor_need_setup_redirect 149 end
# File lib/rodauth/features/webauthn.rb 392 def require_webauthn_setup 393 unless webauthn_setup? 394 set_redirect_error_status(webauthn_not_setup_error_status) 395 set_redirect_error_flash webauthn_not_setup_error_flash 396 redirect two_factor_need_setup_redirect 397 end 398 end
# File lib/rodauth/features/jwt.rb 246 def rescue_jwt_payload(_) 247 @jwt_payload = false 248 end
# File lib/rodauth/features/reset_password.rb 247 def reset_password_email_body 248 render('reset-password-email') 249 end
# File lib/rodauth/features/reset_password.rb 189 def reset_password_email_link 190 token_link(reset_password_route, reset_password_key_param, reset_password_key_value) 191 end
# File lib/rodauth/features/reset_password.rb 217 def reset_password_email_recently_sent? 218 (email_last_sent = get_reset_password_email_last_sent) && (Time.now - email_last_sent < reset_password_skip_resend_email_within) 219 end
# File lib/rodauth/features/reset_password.rb 255 def reset_password_key_insert_hash 256 hash = {reset_password_id_column=>account_id, reset_password_key_column=>reset_password_key_value} 257 set_deadline_value(hash, reset_password_deadline_column, reset_password_deadline_interval) 258 hash 259 end
# File lib/rodauth/features/single_session.rb 22 def reset_single_session_key 23 if logged_in? 24 single_session_ds.update(single_session_key_column=>random_key) 25 end 26 end
# File lib/rodauth/features/base.rb 138 def response 139 scope.response 140 end
This is used to avoid race conditions when using the pattern of inserting when an update affects no rows. In such cases, if a row is inserted between the update and the insert, the insert will fail with a uniqueness error, but retrying will work. It is possible for it to fail again, but only if the row is deleted before the update and readded before the insert, which is very unlikely to happen. In such cases, raising an exception is acceptable.
# File lib/rodauth/features/base.rb 674 def retry_on_uniqueness_violation(&block) 675 if raises_uniqueness_violation?(&block) 676 yield 677 end 678 end
# File lib/rodauth/features/jwt.rb 279 def return_json_response 280 response.status ||= json_response_error_status if json_response[json_response_error_key] 281 set_jwt 282 response['Content-Type'] ||= json_response_content_type 283 response.write(_json_response_body(json_response)) 284 request.halt 285 end
# File lib/rodauth/features/base.rb 150 def route! 151 if meth = self.class.route_hash[request.remaining_path] 152 send(meth) 153 end 154 155 nil 156 end
# File lib/rodauth/features/base.rb 491 def route_path(route, opts={}) 492 path = "#{prefix}/#{route}" 493 path += "?#{Rack::Utils.build_nested_query(opts)}" unless opts.empty? 494 path 495 end
# File lib/rodauth/features/base.rb 497 def route_url(route, opts={}) 498 "#{base_url}#{route_path(route, opts)}" 499 end
# File lib/rodauth/features/create_account.rb 98 def save_account 99 id = nil 100 raised = raises_uniqueness_violation?{id = db[accounts_table].insert(account)} 101 102 if raised 103 @login_requirement_message = already_an_account_with_this_login_message 104 end 105 106 if id 107 account[account_id_column] = id 108 end 109 110 id && !raised 111 end
# File lib/rodauth/features/email_base.rb 28 def send_email(email) 29 email.deliver! 30 end
# File lib/rodauth/features/email_auth.rb 134 def send_email_auth_email 135 send_email(create_email_auth_email) 136 end
# File lib/rodauth/features/change_password_notify.rb 19 def send_password_changed_email 20 send_email(create_password_changed_email) 21 end
# File lib/rodauth/features/reset_password.rb 185 def send_reset_password_email 186 send_email(create_reset_password_email) 187 end
# File lib/rodauth/features/lockout.rb 218 def send_unlock_account_email 219 send_email(create_unlock_account_email) 220 end
# File lib/rodauth/features/verify_account.rb 210 def send_verify_account_email 211 send_email(create_verify_account_email) 212 end
# File lib/rodauth/features/verify_login_change.rb 122 def send_verify_login_change_email(login) 123 send_email(create_verify_login_change_email(login)) 124 end
# File lib/rodauth/features/audit_logging.rb 55 def serialize_audit_log_metadata(metadata) 56 metadata.to_json unless metadata.nil? 57 end
# File lib/rodauth/features/base.rb 142 def session 143 scope.session 144 end
# File lib/rodauth/features/active_sessions.rb 129 def session_inactivity_deadline_condition 130 if deadline = session_inactivity_deadline 131 Sequel[active_sessions_last_use_column] < Sequel.date_sub(Sequel::CURRENT_TIMESTAMP, seconds: deadline) 132 end 133 end
# File lib/rodauth/features/jwt.rb 120 def session_jwt 121 JWT.encode(jwt_session_hash, jwt_secret, jwt_algorithm) 122 end
# File lib/rodauth/features/active_sessions.rb 135 def session_lifetime_deadline_condition 136 if deadline = session_lifetime_deadline 137 Sequel[active_sessions_created_at_column] < Sequel.date_sub(Sequel::CURRENT_TIMESTAMP, seconds: deadline) 138 end 139 end
# File lib/rodauth/features/base.rb 242 def session_value 243 session[session_key] 244 end
This is needed on MySQL, which doesn't support non constant defaults other than CURRENT_TIMESTAMP.
# File lib/rodauth/features/base.rb 710 def set_deadline_value(hash, column, interval) 711 if set_deadline_values? 712 # :nocov: 713 hash[column] = Sequel.date_add(Sequel::CURRENT_TIMESTAMP, interval) 714 # :nocov: 715 end 716 end
# File lib/rodauth/features/base.rb 557 def set_deadline_values? 558 db.database_type == :mysql 559 end
# File lib/rodauth/features/email_auth.rb 114 def set_email_auth_email_last_sent 115 email_auth_ds.update(email_auth_email_last_sent_column=>Sequel::CURRENT_TIMESTAMP) if email_auth_email_last_sent_column 116 end
# File lib/rodauth/features/base.rb 307 def set_error_flash(message) 308 flash.now[flash_error_key] = message 309 end
# File lib/rodauth/features/account_expiration.rb 49 def set_expired 50 update_activity(account_id, account_activity_expired_column) 51 after_account_expiration 52 end
# File lib/rodauth/features/base.rb 158 def set_field_error(field, error) 159 (@field_errors ||= {})[field] = error 160 end
# File lib/rodauth/features/http_basic_auth.rb 74 def set_http_basic_auth_error_response 75 response.status = 401 76 response.headers["WWW-Authenticate"] = "Basic realm=\"#{http_basic_auth_realm}\"" 77 end
# File lib/rodauth/features/jwt.rb 287 def set_jwt 288 set_jwt_token(session_jwt) 289 end
# File lib/rodauth/features/jwt_refresh.rb 195 def set_jwt_refresh_token_hmac_session_key(token) 196 if allow_refresh_with_expired_jwt_access_token? 197 key = _account_refresh_token_split(token).last 198 data = random_key 199 set_session_value(jwt_refresh_token_data_session_key, data) 200 set_session_value(jwt_refresh_token_hmac_session_key, compute_hmac(data + key)) 201 end 202 end
# File lib/rodauth/features/jwt.rb 132 def set_jwt_token(token) 133 response.headers['Authorization'] = token 134 end
# File lib/rodauth/features/password_grace_period.rb 44 def set_last_password_entry 45 set_session_value(last_password_entry_session_key, Time.now.to_i) 46 end
# File lib/rodauth/features/create_account.rb 90 def set_new_account_password(password) 91 account[account_password_hash_column] = password_hash(password) 92 end
# File lib/rodauth/features/base.rb 315 def set_notice_flash(message) 316 flash[flash_notice_key] = message 317 end
# File lib/rodauth/features/base.rb 319 def set_notice_now_flash(message) 320 flash.now[flash_notice_key] = message 321 end
# File lib/rodauth/features/disallow_password_reuse.rb 19 def set_password(password) 20 hash = super 21 add_previous_password_hash(hash) 22 hash 23 end
# File lib/rodauth/features/base.rb 311 def set_redirect_error_flash(message) 312 flash[flash_error_key] = message 313 end
Don't set an error status when redirecting in an error case, as a redirect status is needed.
# File lib/rodauth/features/base.rb 536 def set_redirect_error_status(status) 537 end
# File lib/rodauth/features/reset_password.rb 199 def set_reset_password_email_last_sent 200 password_reset_ds.update(reset_password_email_last_sent_column=>Sequel::CURRENT_TIMESTAMP) if reset_password_email_last_sent_column 201 end
# File lib/rodauth/features/base.rb 539 def set_response_error_status(status) 540 response.status = status 541 end
# File lib/rodauth/features/base.rb 718 def set_session_value(key, value) 719 session[key] = value 720 end
# File lib/rodauth/features/single_session.rb 92 def set_single_session_key(data) 93 data = compute_hmac(data) if hmac_secret 94 set_session_value(single_session_session_key, data) 95 end
# File lib/rodauth/features/base.rb 301 def set_title(title) 302 if title_instance_variable 303 scope.instance_variable_set(title_instance_variable, title) 304 end 305 end
# File lib/rodauth/features/lockout.rb 234 def set_unlock_account_email_last_sent 235 account_lockouts_ds.update(account_lockouts_email_last_sent_column=>Sequel::CURRENT_TIMESTAMP) if account_lockouts_email_last_sent_column 236 end
# File lib/rodauth/features/verify_account.rb 235 def set_verify_account_email_last_sent 236 verify_account_ds.update(verify_account_email_last_sent_column=>Sequel::CURRENT_TIMESTAMP) if verify_account_email_last_sent_column 237 end
# File lib/rodauth/features/verify_account.rb 247 def setup_account_verification 248 generate_verify_account_key_value 249 create_verify_account_key 250 send_verify_account_email 251 end
# File lib/rodauth/features/lockout.rb 273 def show_lockout_page 274 set_response_error_status lockout_error_status 275 set_error_flash login_lockout_error_flash 276 response.write unlock_account_request_view 277 request.halt 278 end
# File lib/rodauth/features/single_session.rb 97 def single_session_ds 98 db[single_session_table]. 99 where(single_session_id_column=>session_value) 100 end
# File lib/rodauth/features/login.rb 107 def skip_login_field_on_login? 108 return false unless use_multi_phase_login? 109 valid_login_entered? 110 end
# File lib/rodauth/features/login.rb 112 def skip_password_field_on_login? 113 return false unless use_multi_phase_login? 114 !valid_login_entered? 115 end
# File lib/rodauth/features/close_account.rb 82 def skip_status_checks? 83 false 84 end
# File lib/rodauth/features/sms_codes.rb 378 def sms_auth_message(code) 379 "SMS authentication code for #{domain} is #{code}" 380 end
# File lib/rodauth/features/sms_codes.rb 420 def sms_available? 421 sms && !sms_needs_confirmation? && !sms_locked_out? 422 end
# File lib/rodauth/features/sms_codes.rb 399 def sms_code 400 sms[sms_code_column] 401 end
# File lib/rodauth/features/sms_codes.rb 403 def sms_code_issued_at 404 convert_timestamp(sms[sms_issued_at_column]) 405 end
# File lib/rodauth/features/sms_codes.rb 328 def sms_code_match?(code) 329 return false unless sms_current_auth? 330 timing_safe_eql?(code, sms_code) 331 end
# File lib/rodauth/features/sms_codes.rb 463 def sms_codes_primary? 464 (features & [:otp, :webauthn]).empty? 465 end
# File lib/rodauth/features/recovery_codes.rb 141 def sms_confirm 142 super if defined?(super) 143 auto_add_missing_recovery_codes 144 end
# File lib/rodauth/features/sms_codes.rb 342 def sms_confirm_failure 343 sms_ds.delete 344 end
# File lib/rodauth/features/sms_codes.rb 382 def sms_confirm_message(code) 383 "SMS confirmation code for #{domain} is #{code}" 384 end
# File lib/rodauth/features/sms_codes.rb 333 def sms_confirmation_match?(code) 334 sms_needs_confirmation? && sms_code_match?(code) 335 end
# File lib/rodauth/features/sms_codes.rb 428 def sms_current_auth? 429 sms_code && sms_code_issued_at + sms_code_allowed_seconds > Time.now 430 end
# File lib/rodauth/features/sms_codes.rb 337 def sms_disable 338 sms_ds.delete 339 @sms = nil 340 end
# File lib/rodauth/features/sms_codes.rb 491 def sms_ds 492 db[sms_codes_table].where(sms_id_column=>session_value) 493 end
# File lib/rodauth/features/sms_codes.rb 407 def sms_failures 408 sms[sms_failures_column] 409 end
# File lib/rodauth/features/sms_codes.rb 424 def sms_locked_out? 425 sms_failures >= sms_failure_limit 426 end
# File lib/rodauth/features/sms_codes.rb 416 def sms_needs_confirmation? 417 sms && sms_failures.nil? 418 end
# File lib/rodauth/features/sms_codes.rb 471 def sms_new_auth_code 472 SecureRandom.random_number(10**sms_auth_code_length).to_s.rjust(sms_auth_code_length, "0") 473 end
# File lib/rodauth/features/sms_codes.rb 475 def sms_new_confirm_code 476 SecureRandom.random_number(10**sms_confirm_code_length).to_s.rjust(sms_confirm_code_length, "0") 477 end
# File lib/rodauth/features/sms_codes.rb 467 def sms_normalize_phone(phone) 468 phone.to_s.gsub(/\D+/, '') 469 end
# File lib/rodauth/features/sms_codes.rb 395 def sms_phone 396 sms[sms_phone_column] 397 end
# File lib/rodauth/features/sms_codes.rb 390 def sms_record_failure 391 update_sms(sms_failures_column=>Sequel.expr(sms_failures_column)+1) 392 sms[sms_failures_column] = sms_ds.get(sms_failures_column) 393 end
# File lib/rodauth/features/sms_codes.rb 353 def sms_remove_failures 354 update_sms(sms_failures_column => 0, sms_code_column => nil) 355 end
# File lib/rodauth/features/sms_codes.rb 479 def sms_send(phone, message) 480 raise NotImplementedError, "sms_send needs to be defined in the Rodauth configuration for SMS sending to work" 481 end
# File lib/rodauth/features/sms_codes.rb 362 def sms_send_auth_code 363 code = sms_new_auth_code 364 sms_set_code(code) 365 sms_send(sms_phone, sms_auth_message(code)) 366 end
# File lib/rodauth/features/sms_codes.rb 368 def sms_send_confirm_code 369 code = sms_new_confirm_code 370 sms_set_code(code) 371 sms_send(sms_phone, sms_confirm_message(code)) 372 end
# File lib/rodauth/features/sms_codes.rb 386 def sms_set_code(code) 387 update_sms(sms_code_column=>code, sms_issued_at_column=>Sequel::CURRENT_TIMESTAMP) 388 end
# File lib/rodauth/features/sms_codes.rb 346 def sms_setup(phone_number) 347 # Cannot handle uniqueness violation here, as the phone number given may not match the 348 # one in the table. 349 sms_ds.insert(sms_id_column=>session_value, sms_phone_column=>phone_number) 350 remove_instance_variable(:@sms) if instance_variable_defined?(:@sms) 351 end
# File lib/rodauth/features/sms_codes.rb 411 def sms_setup? 412 return false unless sms 413 !sms_needs_confirmation? 414 end
# File lib/rodauth/features/sms_codes.rb 374 def sms_valid_phone?(phone) 375 phone.length >= sms_phone_min_length 376 end
# File lib/rodauth/features/base.rb 483 def split_token(token) 484 token.split(token_separator, 2) 485 end
# File lib/rodauth/features/base.rb 643 def template_path(page) 644 File.join(File.dirname(__FILE__), '../../../templates', "#{page}.str") 645 end
# File lib/rodauth/features/http_basic_auth.rb 79 def throw_basic_auth_error(*args) 80 set_http_basic_auth_error_response 81 throw_error(*args) 82 end
# File lib/rodauth/features/base.rb 543 def throw_error(field, error) 544 set_field_error(field, error) 545 throw :rodauth_error 546 end
# File lib/rodauth/features/base.rb 548 def throw_error_status(status, field, error) 549 set_response_error_status(status) 550 throw_error(field, error) 551 end
# File lib/rodauth/features/base.rb 514 def timing_safe_eql?(provided, actual) 515 provided = provided.to_s 516 Rack::Utils.secure_compare(provided.ljust(actual.length), actual) && provided.length == actual.length 517 end
# File lib/rodauth/features/email_base.rb 53 def token_link(route, param, key) 54 route_url(route, param => "#{account_id}#{token_separator}#{convert_email_token_key(key)}") 55 end
# File lib/rodauth/features/base.rb 501 def transaction(opts={}, &block) 502 db.transaction(opts, &block) 503 end
# File lib/rodauth/features/base.rb 225 def translate(_key, default) 226 # do not attempt to translate by default 227 default 228 end
# File lib/rodauth/features/two_factor_base.rb 227 def two_factor_authenticate(type) 228 two_factor_update_session(type) 229 two_factor_remove_auth_failures 230 after_two_factor_authentication 231 set_notice_flash two_factor_auth_notice_flash 232 redirect_two_factor_authenticated 233 end
# File lib/rodauth/features/two_factor_base.rb 182 def two_factor_authenticated? 183 authenticated_by && authenticated_by.length >= 2 184 end
# File lib/rodauth/features/two_factor_base.rb 186 def two_factor_authentication_setup? 187 possible_authentication_methods.length >= 2 188 end
# File lib/rodauth/features/two_factor_base.rb 196 def two_factor_login_type_match?(type) 197 authenticated_by && authenticated_by.include?(type) 198 end
# File lib/rodauth/features/two_factor_base.rb 116 def two_factor_modifications_require_password? 117 modifications_require_password? 118 end
# File lib/rodauth/features/two_factor_base.rb 174 def two_factor_password_match?(password) 175 if two_factor_modifications_require_password? 176 password_match?(password) 177 else 178 true 179 end 180 end
# File lib/rodauth/features/otp.rb 216 def two_factor_remove 217 super 218 otp_remove 219 end
# File lib/rodauth/features/otp.rb 221 def two_factor_remove_auth_failures 222 super 223 otp_remove_auth_failures 224 end
# File lib/rodauth/features/two_factor_base.rb 240 def two_factor_remove_session(type) 241 authenticated_by.delete(type) 242 remove_session_value(two_factor_setup_session_key) 243 if authenticated_by.empty? 244 clear_session 245 end 246 end
# File lib/rodauth/features/two_factor_base.rb 248 def two_factor_update_session(auth_type) 249 authenticated_by << auth_type 250 set_session_value(two_factor_setup_session_key, true) 251 end
Work around jdbc/sqlite issue where it only raises ConstraintViolation and not UniqueConstraintViolation.
# File lib/rodauth/features/base.rb 692 def unique_constraint_violation_class 693 if db.adapter_scheme == :jdbc && db.database_type == :sqlite 694 # :nocov: 695 Sequel::ConstraintViolation 696 # :nocov: 697 else 698 Sequel::UniqueConstraintViolation 699 end 700 end
# File lib/rodauth/features/lockout.rb 158 def unlock_account 159 transaction do 160 remove_lockout_metadata 161 end 162 end
# File lib/rodauth/features/lockout.rb 284 def unlock_account_email_body 285 render('unlock-account-email') 286 end
# File lib/rodauth/features/lockout.rb 222 def unlock_account_email_link 223 token_link(unlock_account_route, unlock_account_key_param, unlock_account_key_value) 224 end
# File lib/rodauth/features/lockout.rb 288 def unlock_account_email_recently_sent? 289 (email_last_sent = get_unlock_account_email_last_sent) && (Time.now - email_last_sent < unlock_account_skip_resend_email_within) 290 end
# File lib/rodauth/features/base.rb 736 def update_account(values, ds=account_ds) 737 update_hash_ds(account, ds, values) 738 end
# File lib/rodauth/features/account_expiration.rb 113 def update_activity(account_id, *columns) 114 ds = account_activity_ds(account_id) 115 hash = {} 116 columns.each do |c| 117 hash[c] = Sequel::CURRENT_TIMESTAMP 118 end 119 if ds.update(hash) == 0 120 hash[account_activity_id_column] = account_id 121 hash[account_activity_last_activity_column] ||= Sequel::CURRENT_TIMESTAMP 122 hash[account_activity_last_login_column] ||= Sequel::CURRENT_TIMESTAMP 123 # It is safe to ignore uniqueness violations here, as a concurrent insert would also use current timestamps. 124 ignore_uniqueness_violation{ds.insert(hash)} 125 end 126 end
# File lib/rodauth/features/base.rb 726 def update_hash_ds(hash, ds, values) 727 num = ds.update(values) 728 if num == 1 729 values.each do |k, v| 730 account[k] = v == Sequel::CURRENT_TIMESTAMP ? Time.now : v 731 end 732 end 733 num 734 end
# File lib/rodauth/features/account_expiration.rb 43 def update_last_activity 44 if session_value 45 update_activity(session_value, account_activity_last_activity_column) 46 end 47 end
# File lib/rodauth/features/account_expiration.rb 39 def update_last_login 40 update_activity(account_id, account_activity_last_login_column, account_activity_last_activity_column) 41 end
# File lib/rodauth/features/change_login.rb 76 def update_login(login) 77 _update_login(login) 78 end
# File lib/rodauth/features/password_expiration.rb 52 def update_password_changed_at 53 ds = password_expiration_ds 54 if ds.update(password_expiration_changed_at_column=>Sequel::CURRENT_TIMESTAMP) == 0 55 # Ignoring the violation is safe here, since a concurrent insert would also set it to the 56 # current timestamp. 57 ignore_uniqueness_violation{ds.insert(password_expiration_id_column=>account_id)} 58 end 59 end
# File lib/rodauth/features/update_password_hash.rb 17 def update_password_hash? 18 password_hash_cost != @current_password_hash_cost 19 end
# File lib/rodauth/features/account_expiration.rb 72 def update_session 73 check_account_expiration 74 super 75 end
# File lib/rodauth/features/single_session.rb 64 def update_single_session_key 65 key = random_key 66 set_single_session_key(key) 67 if single_session_ds.update(single_session_key_column=>key) == 0 68 # Don't handle uniqueness violations here. While we could get the stored key from the 69 # database, it could lead to two sessions sharing the same key, which this feature is 70 # designed to prevent. 71 single_session_ds.insert(single_session_id_column=>session_value, single_session_key_column=>key) 72 end 73 end
# File lib/rodauth/features/sms_codes.rb 483 def update_sms(values) 484 update_hash_ds(sms, sms_ds, values) 485 end
# File lib/rodauth/features/base.rb 561 def use_database_authentication_functions? 562 case db.database_type 563 when :postgres, :mysql, :mssql 564 true 565 else 566 # :nocov: 567 false 568 # :nocov: 569 end 570 end
# File lib/rodauth/features/active_sessions.rb 153 def use_date_arithmetic? 154 true 155 end
# File lib/rodauth/features/jwt.rb 136 def use_jwt? 137 jwt_token || only_json? || json_request? 138 end
# File lib/rodauth/features/email_auth.rb 159 def use_multi_phase_login? 160 true 161 end
# File lib/rodauth/features/base.rb 572 def use_request_specific_csrf_tokens? 573 scope.opts[:rodauth_route_csrf] && scope.use_request_specific_csrf_tokens? 574 end
# File lib/rodauth/features/two_factor_base.rb 190 def uses_two_factor_authentication? 191 return false unless logged_in? 192 set_session_value(two_factor_setup_session_key, two_factor_authentication_setup?) unless session.has_key?(two_factor_setup_session_key) 193 session[two_factor_setup_session_key] 194 end
# File lib/rodauth/features/jwt.rb 140 def valid_jwt? 141 !!(jwt_token && jwt_payload) 142 end
# File lib/rodauth/features/login.rb 117 def valid_login_entered? 118 @valid_login_entered 119 end
# File lib/rodauth/features/webauthn.rb 305 def valid_new_webauthn_credential?(webauthn_credential) 306 # Hack around inability to override expected_origin 307 origin = webauthn_origin 308 webauthn_credential.response.define_singleton_method(:verify) do |expected_challenge, expected_origin = nil, **kw| 309 super(expected_challenge, expected_origin || origin, **kw) 310 end 311 312 (challenge = param_or_nil(webauthn_setup_challenge_param)) && 313 (hmac = param_or_nil(webauthn_setup_challenge_hmac_param)) && 314 timing_safe_eql?(compute_hmac(challenge), hmac) && 315 webauthn_credential.verify(challenge) 316 end
# File lib/rodauth/features/webauthn.rb 359 def valid_webauthn_credential_auth?(webauthn_credential) 360 ds = webauthn_keys_ds.where(webauthn_keys_webauthn_id_column => webauthn_credential.id) 361 pub_key, sign_count = ds.get([webauthn_keys_public_key_column, webauthn_keys_sign_count_column]) 362 363 # Hack around inability to override expected_origin 364 origin = webauthn_origin 365 webauthn_credential.response.define_singleton_method(:verify) do |expected_challenge, expected_origin = nil, **kw| 366 super(expected_challenge, expected_origin || origin, **kw) 367 end 368 369 (challenge = param_or_nil(webauthn_auth_challenge_param)) && 370 (hmac = param_or_nil(webauthn_auth_challenge_hmac_param)) && 371 timing_safe_eql?(compute_hmac(challenge), hmac) && 372 webauthn_credential.verify(challenge, public_key: pub_key, sign_count: sign_count) && 373 ds.update( 374 webauthn_keys_sign_count_column => Integer(webauthn_credential.sign_count), 375 webauthn_keys_last_use_column => Sequel::CURRENT_TIMESTAMP 376 ) == 1 377 end
# File lib/rodauth/features/verify_account_grace_period.rb 17 def verified_account? 18 logged_in? && !session[unverified_account_session_key] 19 end
# File lib/rodauth/features/verify_account.rb 176 def verify_account 177 update_account(account_status_column=>account_open_status_value) == 1 178 end
# File lib/rodauth/features/verify_account.rb 284 def verify_account_check_already_logged_in 285 check_already_logged_in 286 end
# File lib/rodauth/features/verify_account.rb 317 def verify_account_ds(id=account_id) 318 db[verify_account_table].where(verify_account_id_column=>id) 319 end
# File lib/rodauth/features/verify_account.rb 313 def verify_account_email_body 314 render('verify-account-email') 315 end
# File lib/rodauth/features/verify_account.rb 214 def verify_account_email_link 215 token_link(verify_account_route, verify_account_key_param, verify_account_key_value) 216 end
# File lib/rodauth/features/verify_account.rb 263 def verify_account_email_recently_sent? 264 (email_last_sent = get_verify_account_email_last_sent) && (Time.now - email_last_sent < verify_account_skip_resend_email_within) 265 end
# File lib/rodauth/features/verify_account.rb 180 def verify_account_email_resend 181 if @verify_account_key_value = get_verify_account_key(account_id) 182 set_verify_account_email_last_sent 183 send_verify_account_email 184 true 185 end 186 end
# File lib/rodauth/features/verify_account.rb 305 def verify_account_key_insert_hash 306 {verify_account_id_column=>account_id, verify_account_key_column=>verify_account_key_value} 307 end
# File lib/rodauth/features/verify_account_grace_period.rb 29 def verify_account_set_password? 30 false 31 end
# File lib/rodauth/features/webauthn_verify_account.rb 7 def verify_account_view 8 webauthn_setup_view 9 end
# File lib/rodauth/features/verify_login_change.rb 110 def verify_login_change 111 unless res = _update_login(verify_login_change_new_login) 112 remove_verify_login_change_key 113 end 114 115 res 116 end
# File lib/rodauth/features/verify_login_change.rb 204 def verify_login_change_ds(id=account_id) 205 db[verify_login_change_table].where(verify_login_change_id_column=>id) 206 end
# File lib/rodauth/features/verify_login_change.rb 200 def verify_login_change_email_body 201 render('verify-login-change-email') 202 end
# File lib/rodauth/features/verify_login_change.rb 126 def verify_login_change_email_link 127 token_link(verify_login_change_route, verify_login_change_key_param, verify_login_change_key_value) 128 end
# File lib/rodauth/features/verify_login_change.rb 190 def verify_login_change_key_insert_hash(login) 191 hash = {verify_login_change_id_column=>account_id, verify_login_change_key_column=>verify_login_change_key_value, verify_login_change_login_column=>login} 192 set_deadline_value(hash, verify_login_change_deadline_column, verify_login_change_deadline_interval) 193 hash 194 end
# File lib/rodauth/features/verify_login_change.rb 138 def verify_login_change_old_login 139 account_ds.get(login_column) 140 end
# File lib/rodauth/features/base.rb 372 def view(page, title) 373 set_title(title) 374 _view(:view, page) 375 end
# File lib/rodauth/features/webauthn.rb 318 def webauth_credential_options_for_get 319 WebAuthn::Credential.options_for_get( 320 :allow => account_webauthn_ids, 321 :timeout => webauthn_auth_timeout, 322 :rp_id => webauthn_rp_id, 323 :user_verification => webauthn_user_verification, 324 :extensions => webauthn_extensions, 325 ) 326 end
# File lib/rodauth/features/webauthn.rb 435 def webauthn_account_id 436 session_value 437 end
# File lib/rodauth/features/webauthn_login.rb 35 def webauthn_auth_additional_form_tags 36 if @webauthn_login 37 super.to_s + login_hidden_field 38 else 39 super 40 end 41 end
# File lib/rodauth/features/webauthn.rb 447 def webauthn_auth_credential_from_form_submission 448 case auth_data = raw_param(webauthn_auth_param) 449 when String 450 begin 451 auth_data = JSON.parse(auth_data) 452 rescue 453 throw_error_status(invalid_field_error_status, webauthn_auth_param, webauthn_invalid_auth_param_message) 454 end 455 when Hash 456 # nothing 457 else 458 throw_error_status(invalid_field_error_status, webauthn_auth_param, webauthn_invalid_auth_param_message) 459 end 460 461 begin 462 webauthn_credential = WebAuthn::Credential.from_get(auth_data) 463 unless valid_webauthn_credential_auth?(webauthn_credential) 464 throw_error_status(invalid_key_error_status, webauthn_auth_param, webauthn_invalid_auth_param_message) 465 end 466 rescue WebAuthn::SignCountVerificationError 467 handle_webauthn_sign_count_verification_error 468 rescue WebAuthn::Error, RuntimeError, NoMethodError 469 throw_error_status(invalid_field_error_status, webauthn_auth_param, webauthn_invalid_auth_param_message) 470 end 471 472 webauthn_credential 473 end
# File lib/rodauth/features/webauthn.rb 238 def webauthn_auth_form_path 239 webauthn_auth_path 240 end
# File lib/rodauth/features/webauthn.rb 254 def webauthn_authenticator_selection 255 {'requireResidentKey' => false, 'userVerification' => webauthn_user_verification} 256 end
# File lib/rodauth/features/webauthn.rb 258 def webauthn_extensions 259 {} 260 end
# File lib/rodauth/features/webauthn.rb 443 def webauthn_keys_ds 444 db[webauthn_keys_table].where(webauthn_keys_account_id_column => webauthn_account_id) 445 end
# File lib/rodauth/features/webauthn.rb 332 def webauthn_origin 333 base_url 334 end
# File lib/rodauth/features/webauthn.rb 246 def webauthn_remove_authenticated_session 247 remove_session_value(authenticated_webauthn_id_session_key) 248 end
# File lib/rodauth/features/webauthn.rb 336 def webauthn_rp_id 337 webauthn_origin.sub(/\Ahttps?:\/\//, '') 338 end
# File lib/rodauth/features/webauthn.rb 340 def webauthn_rp_name 341 webauthn_rp_id 342 end
# File lib/rodauth/features/webauthn.rb 388 def webauthn_setup? 389 !webauthn_keys_ds.empty? 390 end
# File lib/rodauth/features/webauthn.rb 475 def webauthn_setup_credential_from_form_submission 476 case setup_data = raw_param(webauthn_setup_param) 477 when String 478 begin 479 setup_data = JSON.parse(setup_data) 480 rescue 481 throw_error_status(invalid_field_error_status, webauthn_setup_param, webauthn_invalid_setup_param_message) 482 end 483 when Hash 484 # nothing 485 else 486 throw_error_status(invalid_field_error_status, webauthn_setup_param, webauthn_invalid_setup_param_message) 487 end 488 489 unless two_factor_password_match?(param(password_param)) 490 throw_error_status(invalid_password_error_status, password_param, invalid_password_message) 491 end 492 493 begin 494 webauthn_credential = WebAuthn::Credential.from_create(setup_data) 495 unless valid_new_webauthn_credential?(webauthn_credential) 496 throw_error_status(invalid_field_error_status, webauthn_setup_param, webauthn_invalid_setup_param_message) 497 end 498 rescue WebAuthn::Error, RuntimeError, NoMethodError 499 throw_error_status(invalid_field_error_status, webauthn_setup_param, webauthn_invalid_setup_param_message) 500 end 501 502 webauthn_credential 503 end
# File lib/rodauth/features/webauthn.rb 250 def webauthn_update_session(webauthn_id) 251 set_session_value(authenticated_webauthn_id_session_key, webauthn_id) 252 end
# File lib/rodauth/features/webauthn.rb 439 def webauthn_user_ids_ds 440 db[webauthn_user_ids_table].where(webauthn_user_ids_account_id_column => webauthn_account_id) 441 end
# File lib/rodauth/features/webauthn.rb 328 def webauthn_user_name 329 (account || account_from_session)[login_column] 330 end