:nocov:
:nocov:
Methods
Public Class
- configure
- create_database_authentication_functions
- create_database_previous_password_check_functions
- drop_database_authentication_functions
- drop_database_previous_password_check_functions
- lib
- load_dependencies
- new
- version
Public Instance
- _account_from_email_auth_key
- _account_from_id
- _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
- _field_attributes
- _field_error_attributes
- _filter_links
- _formatted_field_error
- _get_remember_cookie
- _initialize_instance_variables
- _json_response_body
- _jwt_decode_opts
- _jwt_decode_secrets
- _login
- _login_form_footer
- _login_form_footer_links
- _login_response
- _merge_fixed_locals_opts
- _multi_phase_login_forms
- _new_account
- _otp
- _otp_add_key
- _otp_for_key
- _otp_interval
- _otp_key
- _otp_tmp_key
- _otp_valid_code?
- _otp_valid_code_for_old_secret
- _override_webauthn_credential_response_verify
- _process_raw_hmac
- _recovery_codes
- _return_json_response
- _set_otp_unlock_info
- _set_remember_cookie
- _setup_account_lockouts_hash
- _sms_request_response
- _template_opts
- _two_factor_auth_links
- _two_factor_auth_response
- _two_factor_remove_all_from_session
- _two_factor_remove_links
- _two_factor_setup_links
- _update_login
- _view
- _view_opts
- account!
- account_activity_ds
- account_ds
- account_expired?
- account_expired_at
- account_from_email_auth_key
- account_from_id
- account_from_key
- account_from_login
- account_from_refresh_token
- account_from_remember_cookie
- account_from_reset_password_key
- account_from_session
- account_from_unlock_key
- account_from_verify_account_key
- account_from_verify_login_change_key
- account_from_webauthn_login
- account_id
- account_id_or_session_value
- account_in_unverified_grace_period?
- account_initial_status_value
- account_lockouts_ds
- account_login_failures_ds
- account_password_hash_column
- account_reload
- account_session_status_filter
- account_table_ds
- account_webauthn_ids
- account_webauthn_usage
- account_webauthn_user_id
- active_remember_key_ds
- active_sessions_ds
- active_sessions_insert_hash
- active_sessions_update_hash
- 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_authentication_failure
- after_otp_disable
- after_otp_setup
- after_otp_unlock_auth_failure
- after_otp_unlock_auth_success
- after_otp_unlock_not_yet_available
- after_refresh_token
- after_reset_password
- after_sms_confirm
- after_sms_disable
- after_webauthn_remove
- after_webauthn_setup
- allow_email_auth?
- allow_param_fallback_for_session_param?
- allow_resending_verify_account_email?
- already_logged_in
- apply_key_for_update
- argon2_hash_algorithm?
- argon2_hash_cost
- argon2_password_hash_match?
- argon2_password_hash_using_salt_and_secret
- argon2_salt_option
- 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_create_account_route
- before_login_attempt
- before_logout
- before_otp_setup
- before_otp_setup_route
- before_reset_password
- before_reset_password_request
- before_rodauth
- before_sms_confirm
- before_two_factor_auth_route
- before_two_factor_manage_route
- before_unlock_account
- before_unlock_account_request
- before_verify_account
- before_verify_account_route
- before_view_recovery_codes
- before_webauthn_auth_route
- before_webauthn_login_route
- before_webauthn_remove_route
- before_webauthn_setup
- before_webauthn_setup_route
- button
- button_fixed_locals
- 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
- clear_tokens
- close_account
- close_account_requires_password?
- compute_hmac
- compute_hmacs
- compute_old_hmac
- compute_raw_hmac
- compute_raw_hmac_with_secret
- confirm_password
- confirm_password_redirect
- convert_email_token_key
- convert_response_header_key
- convert_session_key
- convert_timestamp
- convert_token_id
- convert_token_id_to_integer
- convert_token_key
- create_account_autologin?
- create_account_notice_flash
- create_account_set_password?
- create_email
- create_email_auth_key
- create_email_to
- create_reset_password_key
- 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_link
- email_auth_email_recently_sent?
- email_auth_key_insert_hash
- email_auth_request_form
- email_from
- email_to
- expire_session
- extend_remember_deadline
- extend_remember_deadline_while_logged_in?
- extract_password_hash_cost
- features
- field_attributes
- field_error
- field_error_attributes
- flash
- forget_login
- formatted_field_error
- function_name
- generate_active_sessions_key
- 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_reset_password_key
- 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_invalid_reset_password_key
- handle_invalid_verify_account_key
- handle_webauthn_sign_count_verification_error
- has_password?
- hmac_secret_rotation?
- hook_action
- http_basic_auth
- inactive_session_cond
- include_success_messages?
- input_field_string
- inputmode_for_field?
- instance_variables_to_inspect
- internal_request?
- internal_request_configuration
- invalid_login_attempted
- invalid_previous_password_message
- json_request?
- json_response
- json_response_error?
- 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_confirmation_matches?
- login_does_not_meet_requirements_message
- login_failed_reset_password_request_form
- login_field_autocomplete_value
- login_form_footer_links
- login_hidden_field
- login_input_type
- login_meets_email_requirements?
- login_meets_length_requirements?
- login_meets_requirements?
- login_param_value
- login_required
- login_return_to_requested_location_path
- login_session
- login_too_long_message
- login_too_many_bytes_message
- login_too_short_message
- login_uses_email?
- login_valid_email?
- logout
- logout_additional_form_tags
- missing_recommended_configuration
- modifications_require_password?
- new_account
- new_password_matches_current_password?
- new_recovery_code
- new_webauthn_credential
- no_longer_active_session
- normalize_login
- normalize_session_or_flash_key
- null_byte_parameter_value
- only_json?
- open_account?
- otp_add_key
- otp_available?
- otp_exists?
- otp_hmac_old_secret
- otp_hmac_secret
- otp_issuer
- otp_key_ds
- otp_keys_use_hmac?
- otp_last_use
- otp_locked_out?
- otp_lockout_redirect
- 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_unlock_auth_failure
- otp_unlock_auth_success
- otp_unlock_available?
- otp_unlock_data
- otp_unlock_deadline
- otp_unlock_deadline_passed?
- otp_unlock_ds
- otp_unlock_next_auth_attempt_after
- otp_unlock_not_available_set_refresh_header
- otp_unlock_num_successes
- otp_unlock_refresh_tag
- otp_unlock_reset
- otp_unlock_success_cooldown_seconds
- otp_update_last_use
- otp_user_key
- otp_valid_code?
- otp_valid_key?
- over_max_bytesize_param_value
- param
- param_or_nil
- password_bytesize
- 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_hash_using_salt
- 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_long_message
- password_too_many_bytes_message
- password_too_short_message
- possible_authentication_methods
- post_configure
- previous_password_ds
- raises_uniqueness_violation?
- random_key
- raw_param
- recovery_code_match?
- recovery_codes_available?
- recovery_codes_ds
- recovery_codes_primary?
- recovery_codes_remove
- redirect
- remember_key_ds
- remember_login
- remembered_session_id
- remove_active_session
- remove_all_active_sessions
- remove_all_active_sessions_except_current
- remove_all_active_sessions_except_for
- 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_login_redirect
- require_otp_setup
- require_password_authentication
- require_password_authentication?
- require_response
- 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_account_status_value
- reset_password_email_link
- reset_password_email_recently_sent?
- reset_password_key_insert_hash
- reset_password_request_for_unverified_account
- reset_single_session_key
- response
- retry_on_uniqueness_violation
- return_json_response
- return_response
- route!
- route_path
- route_url
- save_account
- select_key_for_update!
- send_email
- send_verify_login_change_email
- serialize_audit_log_metadata
- session
- session_inactivity_deadline_condition
- session_jwt
- session_lifetime_deadline_condition
- session_param
- session_value
- set_account
- set_deadline_value
- set_deadline_values?
- set_email_auth_email_last_sent
- set_error_flash
- set_error_reason
- 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_login_requirement_error_message
- set_new_account_password
- set_notice_flash
- set_notice_now_flash
- set_password
- set_password_requirement_error_message
- set_redirect_error_flash
- set_redirect_error_status
- set_remember_cookie
- set_reset_password_email_last_sent
- set_response_error_reason_status
- set_response_error_status
- set_response_header
- set_session_return_to_path
- 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
- show_otp_auth_link?
- single_session_ds
- skip_login_field_on_login?
- skip_password_field_on_login?
- skip_status_checks?
- sms
- 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_needs_confirmation_notice_flash
- sms_new_auth_code
- sms_new_confirm_code
- sms_normalize_phone
- sms_phone
- sms_record_failure
- sms_remove_expired_confirm_code
- 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_reason
- throw_error_status
- throw_rodauth_error
- timing_safe_eql?
- token_link
- token_param_value
- transaction
- translate
- two_factor_auth_links
- two_factor_authenticate
- two_factor_authenticated?
- two_factor_authentication_setup?
- two_factor_login_type_match?
- two_factor_modifications_require_password?
- two_factor_partially_authenticated?
- two_factor_password_match?
- two_factor_remove
- two_factor_remove_auth_failures
- two_factor_remove_links
- two_factor_remove_session
- two_factor_setup_links
- two_factor_update_session
- unique_constraint_violation_class
- unlock_account
- unlock_account_email_link
- unlock_account_email_recently_sent?
- unlock_account_key
- unlock_account_key_value
- unverified_grace_period_expired?
- update_account
- update_activity
- update_current_session?
- 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_json?
- use_jwt?
- use_multi_phase_login?
- use_request_specific_csrf_tokens?
- use_scope_clear_session?
- uses_instance_variables
- uses_two_factor_authentication?
- valid_jwt?
- valid_login_entered?
- valid_new_webauthn_credential?
- valid_return_to_path?
- valid_webauthn_credential_auth?
- verified_account?
- verify_account
- verify_account_check_already_logged_in
- verify_account_ds
- 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_account_status_value
- 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
- webauthn_account_id
- webauthn_allow
- webauthn_auth_additional_form_tags
- webauthn_auth_credential_from_form_submission
- webauthn_auth_data
- webauthn_auth_form_path
- webauthn_authenticator_selection
- webauthn_create_relying_party_opts
- webauthn_credential_options_for_get
- webauthn_extensions
- webauthn_form_submission_call
- webauthn_key_insert_hash
- webauthn_keys_ds
- webauthn_login_options?
- webauthn_login_verification_factor?
- webauthn_modification_authenticated?
- webauthn_origin
- webauthn_relying_party
- webauthn_remove_authenticated_session
- webauthn_rp_id
- webauthn_rp_name
- webauthn_setup?
- webauthn_setup_credential_from_form_submission
- webauthn_setup_data
- webauthn_update_session
- webauthn_user_ids_ds
- webauthn_user_name
- webauthn_user_verification
Classes and Modules
- Rodauth::ClassMethods
- Rodauth::InstanceMethods
- Rodauth::InternalRequestClassMethods
- Rodauth::InternalRequestMethods
- Rodauth::RequestMethods
- Rodauth::Auth
- Rodauth::Configuration
- Rodauth::ConfigurationError
- Rodauth::Error
- Rodauth::Feature
- Rodauth::FeatureConfiguration
- Rodauth::InternalRequestError
- Rodauth::SetPasswordFailure
Constants
| FEATURES | = | {} | ||
| INVALID_DOMAIN | = | "invalidurl @@.com" | ||
| MAJOR | = | 2 |
The major version of |
|
| MINOR | = | 47 |
The minor version of |
|
| OPTS | = | {}.freeze | ||
| SCOPE_INSTANCE_VARIABLES | = | [:@_rodauths, :@_rodauth].freeze | ||
| 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. |
| webauthn_get_relying_party_opts | -> | webauthn_create_relying_party_opts |
Public Class methods
# File lib/rodauth.rb 53 def self.configure(app, opts=OPTS, &block) 54 json_opt = app.opts[:rodauth_json] = opts.fetch(:json, app.opts[:rodauth_json]) 55 csrf = app.opts[:rodauth_csrf] = opts.fetch(:csrf, app.opts[:rodauth_csrf]) 56 app.opts[:rodauth_route_csrf] = case csrf 57 when false, :rack_csrf 58 false 59 else 60 json_opt != :only 61 end 62 auth_class = (app.opts[:rodauths] ||= {})[opts[:name]] ||= opts[:auth_class] || Class.new(Auth) 63 if !auth_class.roda_class 64 auth_class.roda_class = app 65 elsif auth_class.roda_class != app 66 auth_class = app.opts[:rodauths][opts[:name]] = Class.new(auth_class) 67 auth_class.roda_class = app 68 end 69 auth_class.class_eval{@configuration_name = opts[:name] unless defined?(@configuration_name)} 70 auth_class.configure(&block) if block 71 auth_class.send(:make_shape_friendly) 72 auth_class.allocate.post_configure if auth_class.method_defined?(:post_configure) 73 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 argon2 = opts[:argon2] 9 10 case db.database_type 11 when :postgres 12 search_path = opts[:search_path] || 'public, pg_temp' 13 primary_key_type = 14 case db.schema(table_name).find { |row| row.first == :id }[1][:db_type] 15 when 'uuid' then :uuid 16 else :int8 17 end 18 table_name = db.literal(table_name) unless table_name.is_a?(String) 19 20 argon_sql = <<END 21 CASE 22 WHEN password_hash ~ '^\\$argon2id' 23 THEN substring(password_hash from '\\$argon2id\\$v=\\d+\\$m=\\d+,t=\\d+,p=\\d+\\$.+\\$') 24 ELSE substr(password_hash, 0, 30) 25 END INTO salt 26 END 27 db.run <<END 28 CREATE OR REPLACE FUNCTION #{get_salt_name}(acct_id #{primary_key_type}) RETURNS text AS $$ 29 DECLARE salt text; 30 BEGIN 31 SELECT 32 #{argon2 ? argon_sql : "substr(password_hash, 0, 30) INTO salt"} 33 FROM #{table_name} 34 WHERE acct_id = id; 35 RETURN salt; 36 END; 37 $$ LANGUAGE plpgsql 38 SECURITY DEFINER 39 SET search_path = #{search_path}; 40 END 41 42 db.run <<END 43 CREATE OR REPLACE FUNCTION #{valid_hash_name}(acct_id #{primary_key_type}, hash text) RETURNS boolean AS $$ 44 DECLARE valid boolean; 45 BEGIN 46 SELECT password_hash = hash INTO valid 47 FROM #{table_name} 48 WHERE acct_id = id; 49 RETURN valid; 50 END; 51 $$ LANGUAGE plpgsql 52 SECURITY DEFINER 53 SET search_path = #{search_path}; 54 END 55 when :mysql 56 argon_sql = <<END 57 CASE 58 WHEN password_hash REGEXP '^.argon2id' 59 THEN left(password_hash, CHAR_LENGTH(password_hash) - INSTR(REVERSE(password_hash), '$')) 60 ELSE substr(password_hash, 1, 30) 61 END 62 END 63 db.run <<END 64 CREATE FUNCTION #{get_salt_name}(acct_id int8) RETURNS varchar(255) 65 SQL SECURITY DEFINER 66 READS SQL DATA 67 BEGIN 68 RETURN (SELECT 69 #{argon2 ? argon_sql : "substr(password_hash, 1, 30)"} 70 FROM #{table_name} 71 WHERE acct_id = id); 72 END; 73 END 74 75 db.run <<END 76 CREATE FUNCTION #{valid_hash_name}(acct_id int8, hash varchar(255)) RETURNS tinyint(1) 77 SQL SECURITY DEFINER 78 READS SQL DATA 79 BEGIN 80 DECLARE valid tinyint(1); 81 DECLARE csr CURSOR FOR 82 SELECT password_hash = hash 83 FROM #{table_name} 84 WHERE acct_id = id; 85 OPEN csr; 86 FETCH csr INTO valid; 87 CLOSE csr; 88 RETURN valid; 89 END; 90 END 91 when :mssql 92 argon_sql = <<END 93 CASE 94 WHEN password_hash LIKE '[$]argon2id%' 95 THEN left(password_hash, len(password_hash) - charindex('$', reverse(password_hash))) 96 ELSE substring(password_hash, 0, 30) 97 END 98 END 99 db.run <<END 100 CREATE FUNCTION #{get_salt_name}(@account_id bigint) RETURNS nvarchar(255) 101 WITH EXECUTE AS OWNER 102 AS 103 BEGIN 104 DECLARE @salt nvarchar(255); 105 SELECT @salt = 106 #{argon2 ? argon_sql : "substring(password_hash, 0, 30)"} 107 FROM #{table_name} 108 WHERE id = @account_id; 109 RETURN @salt; 110 END; 111 END 112 113 db.run <<END 114 CREATE FUNCTION #{valid_hash_name}(@account_id bigint, @hash nvarchar(255)) RETURNS bit 115 WITH EXECUTE AS OWNER 116 AS 117 BEGIN 118 DECLARE @valid bit; 119 DECLARE @ph nvarchar(255); 120 SELECT @ph = password_hash 121 FROM #{table_name} 122 WHERE id = @account_id; 123 IF(@hash = @ph) 124 SET @valid = 1; 125 ELSE 126 SET @valid = 0 127 RETURN @valid; 128 END; 129 END 130 end 131 end
# File lib/rodauth/migrations.rb 153 def self.create_database_previous_password_check_functions(db, opts={}) 154 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)) 155 end
# File lib/rodauth/migrations.rb 133 def self.drop_database_authentication_functions(db, opts={}) 134 table_name = opts[:table_name] || :account_password_hashes 135 get_salt_name = opts[:get_salt_name] || :rodauth_get_salt 136 valid_hash_name = opts[:valid_hash_name] || :rodauth_valid_password_hash 137 138 case db.database_type 139 when :postgres 140 primary_key_type = 141 case db.schema(table_name).find { |row| row.first == :id }[1][:db_type] 142 when 'uuid' then :uuid 143 else :int8 144 end 145 db.run "DROP FUNCTION #{get_salt_name}(#{primary_key_type})" 146 db.run "DROP FUNCTION #{valid_hash_name}(#{primary_key_type}, text)" 147 when :mysql, :mssql 148 db.run "DROP FUNCTION #{get_salt_name}" 149 db.run "DROP FUNCTION #{valid_hash_name}" 150 end 151 end
# File lib/rodauth/migrations.rb 157 def self.drop_database_previous_password_check_functions(db, opts={}) 158 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)) 159 end
# File lib/rodauth.rb 13 def self.lib(opts=OPTS, &block) 14 require 'roda' 15 c = Class.new(Roda) 16 c.plugin(:rodauth, opts) do 17 enable :internal_request 18 instance_exec(&block) 19 end 20 c.freeze 21 c.rodauth 22 end
# File lib/rodauth.rb 24 def self.load_dependencies(app, opts=OPTS, &_) 25 json_opt = opts.fetch(:json, app.opts[:rodauth_json]) 26 if json_opt 27 app.plugin :json 28 app.plugin :json_parser 29 end 30 31 unless json_opt == :only 32 unless opts[:render] == false 33 require 'tilt/string' 34 app.plugin :render 35 end 36 37 case opts.fetch(:csrf, app.opts[:rodauth_csrf]) 38 when false 39 # nothing 40 when :rack_csrf 41 # :nocov: 42 app.plugin :csrf 43 # :nocov: 44 else 45 app.plugin :route_csrf 46 end 47 48 app.plugin :flash unless opts[:flash] == false 49 app.plugin :h 50 end 51 end
# File lib/rodauth/features/base.rb 180 def initialize(scope) 181 @scope = scope 182 _initialize_instance_variables 183 end
Public Instance methods
# File lib/rodauth/features/email_auth.rb 247 def _account_from_email_auth_key(token) 248 account_from_key(token, account_open_status_value){|id| get_email_auth_key(id)} 249 end
# File lib/rodauth/features/base.rb 890 def _account_from_id(id, status_id=nil) 891 ds = account_ds(id) 892 ds = ds.where(account_status_column=>status_id) if status_id && !skip_status_checks? 893 ds.first 894 end
# File lib/rodauth/features/base.rb 877 def _account_from_login(login) 878 ds = account_table_ds.where(login_column=>login) 879 ds = ds.select(*account_select) if account_select 880 ds = ds.where(account_status_column=>[account_unverified_status_value, account_open_status_value]) unless skip_status_checks? 881 ds.first 882 end
# File lib/rodauth/features/jwt_refresh.rb 124 def _account_from_refresh_token(token) 125 id, token_id, key = _account_refresh_token_split(token) 126 127 unless key && 128 (id.to_s == session_value.to_s) && 129 (actual = get_active_refresh_token(id, token_id)) && 130 (timing_safe_eql?(key, convert_token_key(actual)) || (hmac_secret_rotation? && timing_safe_eql?(key, compute_old_hmac(actual)))) && 131 jwt_refresh_token_match?(key) 132 return 133 end 134 135 ds = account_ds(id) 136 ds = ds.where(account_session_status_filter) unless skip_status_checks? 137 ds.first 138 end
# File lib/rodauth/features/reset_password.rb 260 def _account_from_reset_password_key(token) 261 account_from_key(token, reset_password_account_status_value){|id| get_password_reset_key(id)} 262 end
# File lib/rodauth/features/base.rb 884 def _account_from_session 885 ds = account_ds(session_value) 886 ds = ds.where(account_session_status_filter) unless skip_status_checks? 887 ds.first 888 end
# File lib/rodauth/features/lockout.rb 315 def _account_from_unlock_key(token) 316 account_from_key(token){|id| apply_key_for_update(account_lockouts_ds(id)).get(account_lockouts_key_column)} 317 end
# File lib/rodauth/features/verify_account.rb 319 def _account_from_verify_account_key(token) 320 account_from_key(token, account_unverified_status_value){|id| get_verify_account_key(id)} 321 end
# File lib/rodauth/features/verify_login_change.rb 216 def _account_from_verify_login_change_key(token) 217 account_from_key(token, verify_login_change_account_status_value) do |id| 218 @verify_login_change_new_login, key = get_verify_login_change_login_and_key(id) 219 key 220 end 221 end
# File lib/rodauth/features/jwt_refresh.rb 140 def _account_refresh_token_split(token) 141 id, token = split_token(token) 142 return unless token && (id = convert_token_id(id)) 143 144 token_id, key = split_token(token) 145 return unless key && (token_id = convert_token_id(token_id)) 146 147 [id, token_id, key] 148 end
# File lib/rodauth/features/base.rb 599 def _around_rodauth 600 yield 601 end
# File lib/rodauth/features/email_auth.rb 194 def _email_auth_request 195 if email_auth_email_recently_sent? 196 set_redirect_error_flash email_auth_email_recently_sent_error_flash 197 redirect email_auth_email_recently_sent_redirect 198 end 199 200 generate_email_auth_key_value 201 transaction do 202 before_email_auth_request 203 create_email_auth_key 204 send_email_auth_email 205 after_email_auth_request 206 end 207 208 email_auth_email_sent_response 209 end
# File lib/rodauth/features/base.rb 909 def _field_attributes(field) 910 nil 911 end
# File lib/rodauth/features/base.rb 913 def _field_error_attributes(field) 914 " aria-invalid=\"true\" aria-describedby=\"#{field}_error_message\" " 915 end
# File lib/rodauth/features/base.rb 1004 def _filter_links(links) 1005 links.select!{|_, link| link} 1006 links.sort! 1007 links 1008 end
# File lib/rodauth/features/base.rb 917 def _formatted_field_error(field, error) 918 "<span class=\"#{input_field_error_message_class}\" id=\"#{field}_error_message\">#{error}</span>" 919 end
# File lib/rodauth/features/remember.rb 241 def _get_remember_cookie 242 request.cookies[remember_cookie_key] 243 end
# File lib/rodauth/features/base.rb 596 def _initialize_instance_variables 597 end
# File lib/rodauth/features/json.rb 228 def _json_response_body(hash) 229 request.send(:convert_to_json, hash) 230 end
# File lib/rodauth/features/jwt.rb 106 def _jwt_decode_opts 107 jwt_decode_opts 108 end
# File lib/rodauth/features/jwt.rb 111 def _jwt_decode_secrets 112 secrets = [jwt_secret, jwt_old_secret] 113 secrets.compact! 114 secrets 115 end
# File lib/rodauth/features/login.rb 186 def _login(auth_type) 187 warn("Deprecated #_login method called, use #login instead.") 188 login(auth_type) 189 end
# File lib/rodauth/features/login.rb 166 def _login_response 167 set_notice_flash login_notice_flash 168 redirect(saved_login_redirect || login_redirect) 169 end
# File lib/rodauth/features/base.rb 1075 def _merge_fixed_locals_opts(opts, fixed_locals) 1076 if use_template_fixed_locals? && !opts[:locals] 1077 fixed_locals_opts = {default_fixed_locals: fixed_locals} 1078 fixed_locals_opts.merge!(opts[:template_opts]) if opts[:template_opts] 1079 opts[:template_opts] = fixed_locals_opts 1080 end 1081 end
# File lib/rodauth/features/email_auth.rb 188 def _multi_phase_login_forms 189 forms = super 190 forms << [30, email_auth_request_form, :_email_auth_request] if valid_login_entered? && allow_email_auth? 191 forms 192 end
# File lib/rodauth/features/create_account.rb 122 def _new_account(login) 123 acc = {login_column=>login} 124 unless skip_status_checks? 125 acc[account_status_column] = account_initial_status_value 126 end 127 acc 128 end
# File lib/rodauth/features/otp.rb 457 def _otp 458 _otp_for_key(otp_user_key) 459 end
# File lib/rodauth/features/otp.rb 442 def _otp_add_key(secret) 443 # Uniqueness errors can't be handled here, as we can't be sure the secret provided 444 # is the same as the current secret. 445 otp_key_ds.insert(otp_keys_id_column=>session_value, otp_keys_column=>secret) 446 end
# File lib/rodauth/features/otp.rb 453 def _otp_for_key(key) 454 otp_class.new(key, :issuer=>otp_issuer, :digits=>otp_digits, :interval=>otp_interval) 455 end
# File lib/rodauth/features/otp.rb 434 def _otp_interval 435 otp_interval || 30 436 end
# File lib/rodauth/features/otp.rb 448 def _otp_key 449 @otp_user_key = nil 450 otp_key_ds.get(otp_keys_column) || false 451 end
# File lib/rodauth/features/otp.rb 428 def _otp_tmp_key(secret) 429 @otp_tmp_key = true 430 @otp_user_key = nil 431 @otp_key = secret 432 end
# File lib/rodauth/features/otp.rb 269 def _otp_valid_code?(ot_pass, otp) 270 return false unless otp_exists? 271 ot_pass = ot_pass.gsub(/\s+/, '') 272 if drift = otp_drift 273 # :nocov: 274 if otp.respond_to?(:verify_with_drift) 275 otp.verify_with_drift(ot_pass, drift) 276 # :nocov: 277 else 278 otp.verify(ot_pass, :drift_behind=>drift, :drift_ahead=>drift, :after=>otp_last_use) 279 end 280 # :nocov: 281 elsif otp.respond_to?(:verify_with_drift) 282 otp.verify(ot_pass) 283 # :nocov: 284 else 285 otp.verify(ot_pass, :after=>otp_last_use) 286 end 287 end
Called for valid OTP codes for old secrets
# File lib/rodauth/features/otp.rb 439 def _otp_valid_code_for_old_secret 440 end
# File lib/rodauth/features/webauthn.rb 443 def _override_webauthn_credential_response_verify(webauthn_credential) 444 # no need to override 445 end
# File lib/rodauth/features/base.rb 603 def _process_raw_hmac(hmac) 604 s = [hmac].pack('m') 605 s.chomp!("=\n") 606 s.tr!('+/', '-_') 607 s 608 end
# File lib/rodauth/features/recovery_codes.rb 265 def _recovery_codes 266 recovery_codes_ds.select_map(recovery_codes_column) 267 end
# File lib/rodauth/features/json.rb 218 def _return_json_response 219 response.status ||= json_response_error_status if json_response_error? 220 response.headers[convert_response_header_key('content-type')] ||= json_response_content_type 221 return_response _json_response_body(json_response) 222 end
# File lib/rodauth/features/json.rb 88 def _set_otp_unlock_info 89 if use_json? 90 json_response[:num_successes] = otp_unlock_num_successes 91 json_response[:required_successes] = otp_unlock_auths_required 92 json_response[:next_attempt_after] = otp_unlock_next_auth_attempt_after.to_i 93 end 94 end
# File lib/rodauth/features/remember.rb 190 def _set_remember_cookie(account_id, remember_key_value, deadline) 191 opts = Hash[remember_cookie_options] 192 opts[:value] = "#{account_id}_#{convert_token_key(remember_key_value)}" 193 opts[:expires] = convert_timestamp(deadline) 194 opts[:path] = "/" unless opts.key?(:path) 195 opts[:httponly] = true unless opts.key?(:httponly) || opts.key?(:http_only) 196 opts[:secure] = true unless opts.key?(:secure) || !request.ssl? 197 ::Rack::Utils.set_cookie_header!(response.headers, remember_cookie_key, opts) 198 end
# File lib/rodauth/features/lockout.rb 175 def _setup_account_lockouts_hash(account_id, key) 176 hash = {account_lockouts_id_column=>account_id, account_lockouts_key_column=>key} 177 set_deadline_value(hash, account_lockouts_deadline_column, account_lockouts_deadline_interval) 178 hash 179 end
# File lib/rodauth/features/sms_codes.rb 476 def _sms_request_response 477 set_notice_flash sms_request_notice_flash 478 redirect sms_auth_redirect 479 end
Set the template path only if there isn’t an overridden template in the application. Result should replace existing template opts.
# File lib/rodauth/features/base.rb 1085 def _template_opts(opts, page) 1086 opts = scope.send(:find_template, scope.send(:parse_template_opts, page, opts)) 1087 unless File.file?(scope.send(:template_path, opts)) 1088 opts[:path] = template_path(page) 1089 end 1090 opts 1091 end
# File lib/rodauth/features/confirm_password.rb 79 def _two_factor_auth_links 80 links = (super if defined?(super)) || [] 81 if authenticated_by.length == 1 && !authenticated_by.include?('password') && has_password? 82 links << [5, confirm_password_path, confirm_password_link_text] 83 end 84 links 85 end
# File lib/rodauth/features/two_factor_base.rb 250 def _two_factor_auth_response 251 saved_two_factor_auth_redirect = remove_session_value(two_factor_auth_redirect_session_key) 252 set_notice_flash two_factor_auth_notice_flash 253 redirect(saved_two_factor_auth_redirect || two_factor_auth_redirect) 254 end
# File lib/rodauth/features/otp.rb 376 def _two_factor_remove_all_from_session 377 two_factor_remove_session('totp') 378 super 379 end
# File lib/rodauth/features/otp.rb 370 def _two_factor_remove_links 371 links = super 372 links << [20, otp_disable_path, otp_disable_link_text] if otp_exists? 373 links 374 end
# File lib/rodauth/features/otp.rb 364 def _two_factor_setup_links 365 links = super 366 links << [20, otp_setup_path, otp_setup_link_text] unless otp_exists? 367 links 368 end
# File lib/rodauth/features/change_login.rb 83 def _update_login(login) 84 updated = nil 85 raised = raises_uniqueness_violation?{updated = update_account({login_column=>login}, account_ds.exclude(login_column=>login)) == 1} 86 if raised 87 set_login_requirement_error_message(:already_an_account_with_this_login, already_an_account_with_this_login_message) 88 end 89 change_made = updated && !raised 90 clear_tokens(:change_login) if change_made 91 change_made 92 end
# File lib/rodauth/features/base.rb 1093 def _view(meth, page) 1094 unless scope.respond_to?(meth) 1095 raise ConfigurationError, "attempted to render a built-in view/email template (#{page.inspect}), but rendering is disabled" 1096 end 1097 1098 scope.send(meth, _view_opts(page)) 1099 end
# File lib/rodauth/features/base.rb 1065 def _view_opts(page) 1066 opts = template_opts.dup 1067 _merge_fixed_locals_opts(opts, '(rodauth: self.rodauth)') 1068 opts[:locals] = opts[:locals] ? opts[:locals].dup : {} 1069 opts[:locals][:rodauth] = self 1070 opts[:cache] = cache_templates 1071 opts[:cache_key] = :"rodauth_#{page}" 1072 _template_opts(opts, page) 1073 end
# File lib/rodauth/features/base.rb 424 def account! 425 @account_retrieval_type ? @account : (session_value && account_from_session) 426 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 929 def account_ds(id=account_id) 930 raise ArgumentError, "invalid account id passed to account_ds" unless id 931 ds = account_table_ds.where(account_id_column=>id) 932 ds = ds.select(*account_select) if account_select 933 ds 934 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 142 def account_from_email_auth_key(key) 143 set_account(_account_from_email_auth_key(key), :email_auth) 144 end
# File lib/rodauth/features/base.rb 432 def account_from_id(id, status_id=nil) 433 set_account(_account_from_id(id, status_id), :id) 434 end
# File lib/rodauth/features/email_base.rb 100 def account_from_key(token, status_id=nil) 101 id, key = split_token(token) 102 return unless key && (id = convert_token_id(id)) 103 104 return unless actual = yield(id) 105 106 unless (hmac_secret && timing_safe_eql?(key, convert_email_token_key(actual))) || 107 (hmac_secret_rotation? && timing_safe_eql?(key, compute_old_hmac(actual))) || 108 ((!hmac_secret || allow_raw_email_token?) && timing_safe_eql?(key, actual)) 109 return 110 end 111 _account_from_id(id, status_id) 112 end
# File lib/rodauth/features/base.rb 317 def account_from_login(login) 318 set_account(_account_from_login(login), :login) 319 end
# File lib/rodauth/features/jwt_refresh.rb 96 def account_from_refresh_token(token) 97 set_account(_account_from_refresh_token(token), :jwt_refresh) 98 end
# File lib/rodauth/features/remember.rb 221 def account_from_remember_cookie 222 unless id = remembered_session_id 223 # Only set expired cookie if there is already a cookie set. 224 forget_login if _get_remember_cookie 225 return 226 end 227 228 set_session_value(session_key, id) 229 account_from_session 230 remove_session_value(session_key) 231 232 unless account 233 remove_remember_key(id) 234 forget_login 235 return 236 end 237 238 account 239 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 428 def account_from_session 429 set_account(_account_from_session, :session) 430 end
# File lib/rodauth/features/lockout.rb 226 def account_from_unlock_key(key) 227 set_account(_account_from_unlock_key(key), :unlock) 228 end
# File lib/rodauth/features/verify_account.rb 199 def account_from_verify_account_key(key) 200 set_account(_account_from_verify_account_key(key), :verify_account) 201 end
# File lib/rodauth/features/verify_login_change.rb 124 def account_from_verify_login_change_key(key) 125 set_account(_account_from_verify_login_change_key(key), :verify_login_change) 126 end
# File lib/rodauth/features/webauthn_autofill.rb 45 def account_from_webauthn_login 46 return super if param_or_nil(login_param) 47 48 credential_id = webauthn_auth_data["id"] 49 account_id = db[webauthn_keys_table] 50 .where(webauthn_keys_webauthn_id_column => credential_id) 51 .get(webauthn_keys_account_id_column) 52 53 unless account_id 54 throw_error_reason(:invalid_webauthn_id, invalid_field_error_status, webauthn_auth_param, webauthn_invalid_webauthn_id_message) 55 end 56 57 account_from_id(account_id) 58 end
# File lib/rodauth/features/base.rb 307 def account_id 308 account[account_id_column] 309 end
# File lib/rodauth/features/base.rb 610 def account_id_or_session_value 611 if @account 612 account_id 613 elsif !@account_retrieval_type 614 session_value 615 end 616 end
# File lib/rodauth/features/verify_account_grace_period.rb 85 def account_in_unverified_grace_period? 86 return false unless account! 87 account[account_status_column] == account_unverified_status_value && 88 verify_account_grace_period && 89 !verify_account_ds.where(Sequel.date_add(verification_requested_at_column, :seconds=>verify_account_grace_period) > Sequel::CURRENT_TIMESTAMP).empty? 90 end
# File lib/rodauth/features/base.rb 420 def account_initial_status_value 421 account_open_status_value 422 end
# File lib/rodauth/features/lockout.rb 311 def account_lockouts_ds(id=account_id) 312 db[account_lockouts_table].where(account_lockouts_id_column=>id) 313 end
# File lib/rodauth/features/lockout.rb 307 def account_login_failures_ds 308 db[account_login_failures_table].where(account_login_failures_id_column=>account_id) 309 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 341 def account_password_hash_column 342 nil 343 end
# File lib/rodauth/features/base.rb 674 def account_reload(current_retrieval_type, new_retrieval_type) 675 return unless @current_route 676 677 678 if current_retrieval_type == new_retrieval_type 679 warn "account retrieved multiple times during rodauth route with retrieval type #{current_retrieval_type}" 680 else 681 raise Error, "account retrieved multiple times during rodauth route, original retrieval type: #{current_retrieval_type}, new retrieval type: #{new_retrieval_type}" 682 end 683 end
# File lib/rodauth/features/base.rb 921 def account_session_status_filter 922 {account_status_column=>account_open_status_value} 923 end
# File lib/rodauth/features/base.rb 936 def account_table_ds 937 db[accounts_table] 938 end
# File lib/rodauth/features/webauthn.rb 271 def account_webauthn_ids 272 webauthn_keys_ds.select_map(webauthn_keys_webauthn_id_column) 273 end
# File lib/rodauth/features/webauthn.rb 275 def account_webauthn_usage 276 webauthn_keys_ds.select_hash(webauthn_keys_webauthn_id_column, webauthn_keys_last_use_column) 277 end
# File lib/rodauth/features/webauthn.rb 279 def account_webauthn_user_id 280 unless webauthn_id = webauthn_user_ids_ds.get(webauthn_user_ids_webauthn_id_column) 281 webauthn_id = WebAuthn.generate_user_id 282 if e = raised_uniqueness_violation do 283 webauthn_user_ids_ds.insert( 284 webauthn_user_ids_account_id_column => webauthn_account_id, 285 webauthn_user_ids_webauthn_id_column => webauthn_id 286 ) 287 end 288 # If two requests to create a webauthn user id are sent at the same time and an insert 289 # is attempted for both, one will fail with a unique constraint violation. In that case 290 # it is safe for the second one to use the webauthn user id inserted by the other request. 291 # If there is still no webauthn user id at this point, then we'll just reraise the 292 # exception. 293 # :nocov: 294 raise e unless webauthn_id = webauthn_user_ids_ds.get(webauthn_user_ids_webauthn_id_column) 295 # :nocov: 296 end 297 end 298 299 webauthn_id 300 end
# File lib/rodauth/features/remember.rb 269 def active_remember_key_ds(id=account_id) 270 remember_key_ds(id).where(Sequel.expr(remember_deadline_column) > Sequel::CURRENT_TIMESTAMP) 271 end
# File lib/rodauth/features/active_sessions.rb 236 def active_sessions_ds 237 db[active_sessions_table]. 238 where(active_sessions_account_id_column=>account_id_or_session_value) 239 end
# File lib/rodauth/features/active_sessions.rb 199 def active_sessions_insert_hash 200 {active_sessions_account_id_column => session_value, active_sessions_session_id_column => compute_hmac(active_sessions_key)} 201 end
# File lib/rodauth/features/active_sessions.rb 203 def active_sessions_update_hash 204 h = {active_sessions_last_use_column => Sequel::CURRENT_TIMESTAMP} 205 206 if hmac_secret_rotation? 207 h[active_sessions_session_id_column] = compute_hmac(session[session_id_session_key]) 208 end 209 210 h 211 end
# File lib/rodauth/features/active_sessions.rb 70 def add_active_session 71 key = generate_active_sessions_key 72 set_session_value(session_id_session_key, key) 73 if e = raises_uniqueness_violation?{active_sessions_ds.insert(active_sessions_insert_hash)} 74 handle_duplicate_active_session_id(e) 75 end 76 nil 77 end
# File lib/rodauth/features/audit_logging.rb 40 def add_audit_log(account_id, action) 41 if hash = audit_log_insert_hash(account_id, action) 42 audit_log_ds.insert(hash) 43 end 44 end
# File lib/rodauth/features/base.rb 222 def add_field_error_class(field) 223 if field_error(field) 224 " #{input_field_error_class}" 225 end 226 end
# File lib/rodauth/features/disallow_password_reuse.rb 27 def add_previous_password_hash(hash) 28 ds = previous_password_ds 29 30 unless @dont_check_previous_password 31 keep_before = ds.reverse(previous_password_id_column). 32 limit(nil, previous_passwords_to_check). 33 get(previous_password_id_column) 34 35 if keep_before 36 ds.where(Sequel.expr(previous_password_id_column) <= keep_before). 37 delete 38 end 39 end 40 41 # This should never raise uniqueness violations, as it uses a serial primary key 42 ds.insert(previous_password_account_id_column=>account_id, previous_password_hash_column=>hash) 43 end
# File lib/rodauth/features/recovery_codes.rb 192 def add_recovery_code 193 # This should never raise uniqueness violations unless the recovery code is the same, and the odds of that 194 # are 1/256**32 assuming a good random number generator. Still, attempt to handle that case by retrying 195 # on such a uniqueness violation. 196 retry_on_uniqueness_violation do 197 recovery_codes_ds.insert(recovery_codes_id_column=>session_value, recovery_codes_column=>new_recovery_code) 198 end 199 end
# File lib/rodauth/features/recovery_codes.rb 182 def add_recovery_codes(number) 183 return if number <= 0 184 transaction do 185 number.times do 186 add_recovery_code 187 end 188 end 189 @recovery_codes = nil 190 end
# File lib/rodauth/features/remember.rb 163 def add_remember_key 164 hash = {remember_id_column=>account_id, remember_key_column=>remember_key_value} 165 set_deadline_value(hash, remember_deadline_column, remember_deadline_interval) 166 167 if e = raised_uniqueness_violation{remember_key_ds.insert(hash)} 168 # If inserting into the remember key table causes a violation, we can pull the 169 # existing row from the table. If there is no invalid row, we can then reraise. 170 raise e unless @remember_key_value = active_remember_key_ds.get(remember_key_column) 171 end 172 end
# File lib/rodauth/features/recovery_codes.rb 153 def add_webauthn_credential(_) 154 super if defined?(super) 155 auto_add_missing_recovery_codes 156 end
# File lib/rodauth/features/change_password_notify.rb 11 def after_change_password 12 super 13 send_password_changed_email 14 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 89 def after_create_account 90 if account_password_hash_column && !(respond_to?(:verify_account_set_password?) && verify_account_set_password?) 91 add_previous_password_hash(password_hash(param(password_param))) 92 end 93 super if defined?(super) 94 end
# File lib/rodauth/features/email_auth.rb 217 def after_login 218 # Remove the email auth key after any login, even if 219 # it is a password login. This is done to invalidate 220 # the email login when a user has a password and requests 221 # email authentication, but then remembers their password 222 # and doesn't need the link. At that point, the link 223 # that allows login access to the account becomes a 224 # security liability, and it is best to remove it. 225 remove_email_auth_key 226 super 227 end
# File lib/rodauth/features/email_auth.rb 160 def after_login_entered_during_multi_phase_login 161 # If forcing email auth, just send the email link. 162 _email_auth_request if force_email_auth? 163 164 super 165 end
# File lib/rodauth/features/lockout.rb 278 def after_login_failure 279 invalid_login_attempted 280 super 281 end
# File lib/rodauth/features/remember.rb 245 def after_logout 246 forget_login 247 super if defined?(super) 248 end
# File lib/rodauth/features/otp_lockout_email.rb 18 def after_otp_authentication_failure 19 super 20 21 if otp_locked_out? && send_otp_locked_out_email? 22 send_otp_locked_out_email 23 end 24 end
# File lib/rodauth/features/otp_modify_email.rb 18 def after_otp_disable 19 super 20 send_otp_disabled_email 21 end
# File lib/rodauth/features/active_sessions.rb 153 def after_otp_setup 154 super if defined?(super) 155 remove_all_active_sessions_except_current if @clear_active_sessions_after_two_factor_setup 156 end
# File lib/rodauth/features/json.rb 104 def after_otp_unlock_auth_failure 105 super if defined?(super) 106 _set_otp_unlock_info 107 end
# File lib/rodauth/features/json.rb 96 def after_otp_unlock_auth_success 97 super if defined?(super) 98 if otp_locked_out? 99 _set_otp_unlock_info 100 json_response[:deadline] = otp_unlock_deadline.to_i 101 end 102 end
# File lib/rodauth/features/json.rb 109 def after_otp_unlock_not_yet_available 110 super if defined?(super) 111 _set_otp_unlock_info 112 end
# File lib/rodauth/features/active_sessions.rb 137 def after_refresh_token 138 super if defined?(super) 139 if prev_key = session[session_id_session_key] 140 key = generate_active_sessions_key 141 set_session_value(session_id_session_key, key) 142 active_sessions_ds. 143 where(active_sessions_session_id_column => compute_hmacs(prev_key)). 144 update(active_sessions_session_id_column => compute_hmac(key)) 145 end 146 end
# File lib/rodauth/features/password_grace_period.rb 48 def after_reset_password 49 super if defined?(super) 50 @last_password_entry = Time.now.to_i 51 end
# File lib/rodauth/features/active_sessions.rb 158 def after_sms_confirm 159 super if defined?(super) 160 remove_all_active_sessions_except_current if @clear_active_sessions_after_two_factor_setup 161 end
# File lib/rodauth/features/recovery_codes.rb 235 def after_sms_disable 236 super if defined?(super) 237 auto_remove_recovery_codes 238 end
# File lib/rodauth/features/recovery_codes.rb 240 def after_webauthn_remove 241 super if defined?(super) 242 auto_remove_recovery_codes 243 end
# File lib/rodauth/features/active_sessions.rb 163 def after_webauthn_setup 164 super if defined?(super) 165 remove_all_active_sessions_except_current if @clear_active_sessions_after_two_factor_setup 166 end
# File lib/rodauth/features/email_auth.rb 213 def allow_email_auth? 214 defined?(super) ? super : true 215 end
# File lib/rodauth/features/email_base.rb 78 def allow_param_fallback_for_session_param? 79 return super if defined?(super) 80 false 81 end
# File lib/rodauth/features/verify_account.rb 165 def allow_resending_verify_account_email? 166 account[account_status_column] == account_unverified_status_value 167 end
# File lib/rodauth/features/base.rb 350 def already_logged_in 351 # RODAUTH3: Move to login feature, halt or redirect by default 352 nil 353 end
# File lib/rodauth/features/email_base.rb 91 def apply_key_for_update(ds) 92 if @key_for_update 93 @key_for_update = nil 94 ds.for_update 95 else 96 ds 97 end 98 end
:nocov:
# File lib/rodauth/features/argon2.rb 107 def argon2_hash_algorithm?(hash) 108 hash.start_with?('$argon2id$') 109 end
# File lib/rodauth/features/argon2.rb 78 def argon2_hash_cost 79 { t_cost: 1, m_cost: 5, p_cost: 1 } 80 end
# File lib/rodauth/features/argon2.rb 111 def argon2_password_hash_match?(hash, password) 112 ret = ::Argon2::Password.verify_password(password, hash, argon2_secret) 113 114 if ret == false && argon2_old_secret != argon2_secret && (ret = ::Argon2::Password.verify_password(password, hash, argon2_old_secret)) 115 @update_password_hash = true 116 end 117 118 ret 119 end
# File lib/rodauth/features/argon2.rb 62 def argon2_password_hash_using_salt_and_secret(password, salt, secret) 63 argon2_params = Hash[extract_password_hash_cost(salt)] 64 argon2_params[argon2_salt_option] = salt.split('$').last.unpack("m")[0] 65 argon2_params[:secret] = secret 66 ::Argon2::Password.new(argon2_params).create(password) 67 end
# File lib/rodauth/features/argon2.rb 36 def argon2_salt_option 37 :salt_do_not_supply 38 end
# File lib/rodauth/features/audit_logging.rb 84 def audit_log_ds 85 ds = db[audit_logging_table] 86 # :nocov: 87 if db.database_type == :postgres 88 # :nocov: 89 # For PostgreSQL, use RETURNING NULL. This allows the feature 90 # to be used with INSERT but not SELECT permissions on the 91 # table, useful for audit logging where the database user 92 # the application is running as should not need to read the 93 # logs. 94 ds = ds.returning(nil) 95 end 96 ds 97 end
# File lib/rodauth/features/audit_logging.rb 46 def audit_log_insert_hash(account_id, action) 47 if message = audit_log_message(action) 48 { 49 audit_logging_account_id_column => account_id, 50 audit_logging_message_column => message, 51 audit_logging_metadata_column => serialize_audit_log_metadata(audit_log_metadata(action)) 52 } 53 end 54 end
# File lib/rodauth/features/audit_logging.rb 64 def audit_log_message(action) 65 meth = :"audit_log_message_for_#{action}" 66 if respond_to?(meth, true) 67 send(meth) 68 else 69 audit_log_message_default(action) 70 end 71 end
# File lib/rodauth/features/audit_logging.rb 60 def audit_log_message_default(action) 61 action.to_s 62 end
# File lib/rodauth/features/audit_logging.rb 73 def audit_log_metadata(action) 74 meth = :"audit_log_metadata_for_#{action}" 75 if respond_to?(meth, true) 76 send(meth) 77 else 78 audit_log_metadata_default 79 end 80 end
# File lib/rodauth/features/base.rb 155 def auth_class_eval(&block) 156 auth.class_eval(&block) 157 end
# File lib/rodauth/features/base.rb 407 def authenticated? 408 logged_in? 409 end
# File lib/rodauth/features/base.rb 511 def authenticated_by 512 session[authenticated_by_session_key] 513 end
# File lib/rodauth/features/webauthn.rb 251 def authenticated_webauthn_id 252 session[authenticated_webauthn_id_session_key] 253 end
# File lib/rodauth/features/recovery_codes.rb 253 def auto_add_missing_recovery_codes 254 if auto_add_recovery_codes? 255 add_recovery_codes(recovery_codes_limit - recovery_codes.length) 256 end 257 end
# File lib/rodauth/features/recovery_codes.rb 259 def auto_remove_recovery_codes 260 if auto_remove_recovery_codes? && (%w'totp webauthn sms_code' & possible_authentication_methods).empty? 261 recovery_codes_remove 262 end 263 end
# File lib/rodauth/features/base.rb 252 def autocomplete_for_field?(_param) 253 mark_input_fields_with_autocomplete? 254 end
# File lib/rodauth/features/base.rb 524 def autologin_session(autologin_type) 525 login_session('autologin') 526 set_session_value(autologin_type_session_key, autologin_type) 527 end
# File lib/rodauth/features/base.rb 520 def autologin_type 521 session[autologin_type_session_key] 522 end
# File lib/rodauth/features/otp.rb 423 def base32_encode(data, length) 424 chars = 'abcdefghijklmnopqrstuvwxyz234567' 425 length.times.map{|i|chars[data[i].ord % 32]}.join 426 end
# File lib/rodauth/features/base.rb 570 def base_url 571 url = String.new("#{request.scheme}://#{domain}") 572 url << ":#{request.port}" if request.port != Rack::Request::DEFAULT_PORTS[request.scheme] 573 url 574 end
# File lib/rodauth/features/verify_account_grace_period.rb 58 def before_change_login_route 59 unless verified_account? 60 set_redirect_error_flash unverified_change_login_error_flash 61 redirect unverified_change_login_redirect 62 end 63 super if defined?(super) 64 end
# File lib/rodauth/features/password_expiration.rb 89 def before_change_password_route 90 check_password_change_allowed 91 super 92 end
# File lib/rodauth/features/disallow_password_reuse.rb 79 def before_create_account_route 80 super if defined?(super) 81 @dont_check_previous_password = true 82 end
# File lib/rodauth/features/lockout.rb 266 def before_login_attempt 267 if locked_out? 268 show_lockout_page 269 end 270 super 271 end
# File lib/rodauth/features/active_sessions.rb 168 def before_logout 169 if param_or_nil(global_logout_param) 170 remove_remember_key(session_value) if respond_to?(:remove_remember_key) 171 remove_all_active_sessions 172 else 173 remove_current_session 174 end 175 super 176 end
# File lib/rodauth/features/active_sessions.rb 178 def before_otp_setup 179 @clear_active_sessions_after_two_factor_setup = !two_factor_authentication_setup? 180 super if defined?(super) 181 end
# File lib/rodauth/features/json.rb 178 def before_otp_setup_route 179 super if defined?(super) 180 if use_json? && otp_keys_use_hmac? && !param_or_nil(otp_setup_raw_param) 181 _otp_tmp_key(otp_new_secret) 182 json_response[otp_setup_param] = otp_user_key 183 json_response[otp_setup_raw_param] = otp_key 184 end 185 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/json.rb 187 def before_rodauth 188 if json_request? 189 if json_check_accept? && (accept = request.env['HTTP_ACCEPT']) && accept !~ json_accept_regexp 190 response.status = 406 191 json_response[json_response_error_key] = json_not_accepted_error_message 192 _return_json_response 193 end 194 195 unless request.post? 196 response.status = 405 197 set_response_header('allow', 'POST') 198 json_response[json_response_error_key] = json_non_post_error_message 199 return_json_response 200 end 201 elsif only_json? 202 response.status = json_response_error_status 203 return_response non_json_request_error_message 204 end 205 206 super 207 end
# File lib/rodauth/features/active_sessions.rb 183 def before_sms_confirm 184 @clear_active_sessions_after_two_factor_setup = !two_factor_authentication_setup? 185 super if defined?(super) 186 end
# File lib/rodauth/features/json.rb 124 def before_two_factor_auth_route 125 super if defined?(super) 126 if use_json? 127 json_response[:auth_links] = two_factor_auth_links.sort.map{|_,link| link} 128 json_response[json_response_success_key] ||= "" if include_success_messages? 129 return_json_response 130 end 131 end
# File lib/rodauth/features/json.rb 114 def before_two_factor_manage_route 115 super if defined?(super) 116 if use_json? 117 json_response[:setup_links] = two_factor_setup_links.sort.map{|_,link| link} 118 json_response[:remove_links] = two_factor_remove_links.sort.map{|_,link| link} 119 json_response[json_response_success_key] ||= "" if include_success_messages? 120 return_json_response 121 end 122 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 32 def before_verify_account 33 super 34 if features.include?(:json) && use_json? && !param_or_nil(webauthn_setup_param) 35 cred = new_webauthn_credential 36 json_response[webauthn_setup_param] = cred.as_json 37 json_response[webauthn_setup_challenge_param] = cred.challenge 38 json_response[webauthn_setup_challenge_hmac_param] = compute_hmac(cred.challenge) 39 end 40 @webauthn_credential = webauthn_setup_credential_from_form_submission 41 add_webauthn_credential(@webauthn_credential) 42 end
# File lib/rodauth/features/disallow_password_reuse.rb 84 def before_verify_account_route 85 super if defined?(super) 86 @dont_check_previous_password = true 87 end
# File lib/rodauth/features/json.rb 133 def before_view_recovery_codes 134 super if defined?(super) 135 if use_json? 136 json_response[:codes] = recovery_codes 137 json_response[json_response_success_key] ||= "" if include_success_messages? 138 end 139 end
# File lib/rodauth/features/json.rb 151 def before_webauthn_auth_route 152 super if defined?(super) 153 if use_json? && !param_or_nil(webauthn_auth_param) 154 cred = webauthn_credential_options_for_get 155 json_response[webauthn_auth_param] = cred.as_json 156 json_response[webauthn_auth_challenge_param] = cred.challenge 157 json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge) 158 end 159 end
# File lib/rodauth/features/json.rb 161 def before_webauthn_login_route 162 super if defined?(super) 163 if use_json? && !param_or_nil(webauthn_auth_param) && webauthn_login_options? 164 cred = webauthn_credential_options_for_get 165 json_response[webauthn_auth_param] = cred.as_json 166 json_response[webauthn_auth_challenge_param] = cred.challenge 167 json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge) 168 end 169 end
# File lib/rodauth/features/json.rb 171 def before_webauthn_remove_route 172 super if defined?(super) 173 if use_json? && !param_or_nil(webauthn_remove_param) 174 json_response[webauthn_remove_param] = account_webauthn_usage 175 end 176 end
# File lib/rodauth/features/active_sessions.rb 188 def before_webauthn_setup 189 @clear_active_sessions_after_two_factor_setup = !two_factor_authentication_setup? 190 super if defined?(super) 191 end
# File lib/rodauth/features/json.rb 141 def before_webauthn_setup_route 142 super if defined?(super) 143 if use_json? && !param_or_nil(webauthn_setup_param) 144 cred = new_webauthn_credential 145 json_response[webauthn_setup_param] = cred.as_json 146 json_response[webauthn_setup_challenge_param] = cred.challenge 147 json_response[webauthn_setup_challenge_hmac_param] = compute_hmac(cred.challenge) 148 end 149 end
# File lib/rodauth/features/base.rb 461 def button(value, opts=OPTS) 462 scope.render(button_opts(value, opts)) 463 end
# File lib/rodauth/features/base.rb 656 def button_fixed_locals 657 '(value:, opts:)' 658 end
# File lib/rodauth/features/base.rb 452 def button_opts(value, opts) 453 opts = Hash[template_opts].merge!(opts) 454 _merge_fixed_locals_opts(opts, button_fixed_locals) 455 opts[:locals] = {:value=>value, :opts=>opts} 456 opts[:cache] = cache_templates 457 opts[:cache_key] = :rodauth_button 458 _template_opts(opts, 'button') 459 end
# File lib/rodauth/features/recovery_codes.rb 178 def can_add_recovery_codes? 179 recovery_codes.length < recovery_codes_limit 180 end
# File lib/rodauth/features/base.rb 779 def catch_error(&block) 780 catch(:rodauth_error, &block) 781 end
# File lib/rodauth/features/change_login.rb 68 def change_login(login) 69 if account_ds.get(login_column).downcase == login.downcase 70 set_login_requirement_error_message(:same_as_current_login, same_as_current_login_message) 71 return false 72 end 73 74 update_login(login) 75 end
# File lib/rodauth/features/verify_login_change.rb 142 def change_login_notice_flash 143 change_login_needs_verification_notice_flash 144 end
# File lib/rodauth/features/change_login.rb 64 def change_login_requires_password? 65 modifications_require_password? 66 end
# File lib/rodauth/features/change_password.rb 78 def change_password_requires_password? 79 modifications_require_password? 80 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 56 def check_active_session 57 if logged_in? && !currently_active_session? 58 no_longer_active_session 59 end 60 end
# File lib/rodauth/features/base.rb 345 def check_already_logged_in 346 # RODAUTH3: Move to login feature 347 already_logged_in if logged_in? 348 end
# File lib/rodauth/features/base.rb 436 def check_csrf 437 scope.check_csrf!(check_csrf_opts, &check_csrf_block) 438 end
# File lib/rodauth/features/base.rb 841 def check_csrf? 842 scope.opts[:rodauth_route_csrf] 843 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 56 def check_single_session 57 if logged_in? && !currently_active_session? 58 no_longer_active_session 59 end 60 end
# File lib/rodauth/features/otp.rb 381 def clear_cached_otp 382 @otp = nil 383 end
# File lib/rodauth/features/lockout.rb 171 def clear_invalid_login_attempts 172 unlock_account 173 end
# File lib/rodauth/features/base.rb 363 def clear_session 364 if use_scope_clear_session? 365 scope.clear_session 366 else 367 session.clear 368 end 369 end
# File lib/rodauth/features/active_sessions.rb 130 def clear_tokens(reason) 131 super 132 remove_all_active_sessions_except_current 133 end
# File lib/rodauth/features/close_account.rb 67 def close_account 68 unless skip_status_checks? 69 update_account(account_status_column=>account_closed_status_value) 70 end 71 72 unless account_password_hash_column 73 password_hash_ds.delete 74 end 75 end
# File lib/rodauth/features/close_account.rb 63 def close_account_requires_password? 64 modifications_require_password? 65 end
Return urlsafe base64 HMAC for data, assumes hmac_secret is set.
# File lib/rodauth/features/base.rb 286 def compute_hmac(data) 287 _process_raw_hmac(compute_raw_hmac(data)) 288 end
Return array of hmacs. Array has two strings if hmac_old_secret is set, or one string otherwise.
# File lib/rodauth/features/base.rb 297 def compute_hmacs(data) 298 hmacs = [compute_hmac(data)] 299 300 if hmac_old_secret 301 hmacs << compute_old_hmac(data) 302 end 303 304 hmacs 305 end
Return urlsafe base64 HMAC for data using hmac_old_secret, assumes hmac_old_secret is set.
# File lib/rodauth/features/base.rb 291 def compute_old_hmac(data) 292 _process_raw_hmac(compute_raw_hmac_with_secret(data, hmac_old_secret)) 293 end
# File lib/rodauth/features/base.rb 900 def compute_raw_hmac(data) 901 raise ConfigurationError, "hmac_secret not set" unless hmac_secret 902 compute_raw_hmac_with_secret(data, hmac_secret) 903 end
# File lib/rodauth/features/base.rb 905 def compute_raw_hmac_with_secret(data, secret) 906 OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, secret, data) 907 end
# File lib/rodauth/features/confirm_password.rb 63 def confirm_password 64 authenticated_by.delete('autologin') 65 authenticated_by.delete('remember') 66 authenticated_by.delete('email_auth') 67 authenticated_by.delete('password') 68 authenticated_by.unshift("password") 69 remove_session_value(autologin_type_session_key) 70 nil 71 end
# File lib/rodauth/features/confirm_password.rb 73 def confirm_password_redirect 74 remove_session_value(confirm_password_redirect_session_key) || default_redirect 75 end
# File lib/rodauth/features/email_base.rb 83 def convert_email_token_key(key) 84 convert_token_key(key) 85 end
# File lib/rodauth/features/base.rb 623 def convert_response_header_key(key) 624 key 625 end
# File lib/rodauth/features/base.rb 758 def convert_session_key(key) 759 key = :"#{session_key_prefix}#{key}" if session_key_prefix 760 normalize_session_or_flash_key(key) 761 end
This is needed for jdbc/sqlite, which returns timestamp columns as strings
# File lib/rodauth/features/base.rb 945 def convert_timestamp(timestamp) 946 timestamp = db.to_application_timestamp(timestamp) if timestamp.is_a?(String) 947 timestamp 948 end
# File lib/rodauth/features/base.rb 711 def convert_token_id(id) 712 if convert_token_id_to_integer? 713 convert_token_id_to_integer(id) 714 else 715 id 716 end 717 end
# File lib/rodauth/features/base.rb 719 def convert_token_id_to_integer(id) 720 if id = (Integer(id, 10) rescue nil) 721 if id > 9223372036854775807 || id < -9223372036854775808 722 # Only allow 64-bit signed integer range to avoid problems on PostgreSQL 723 id = nil 724 end 725 end 726 727 id 728 end
# File lib/rodauth/features/base.rb 699 def convert_token_key(key) 700 if key && hmac_secret 701 compute_hmac(key) 702 else 703 key 704 end 705 end
# File lib/rodauth/features/verify_account.rb 219 def create_account_autologin? 220 false 221 end
# File lib/rodauth/features/verify_account.rb 186 def create_account_notice_flash 187 verify_account_email_sent_notice_flash 188 end
# File lib/rodauth/features/verify_account.rb 223 def create_account_set_password? 224 return false if verify_account_set_password? 225 super 226 end
# File lib/rodauth/features/email_base.rb 47 def create_email(subject, body) 48 create_email_to(email_to, subject, body) 49 end
# File lib/rodauth/features/email_auth.rb 113 def create_email_auth_key 114 transaction do 115 if email_auth_key_value = get_email_auth_key(account_id) 116 set_email_auth_email_last_sent 117 @email_auth_key_value = email_auth_key_value 118 elsif e = raised_uniqueness_violation{email_auth_ds.insert(email_auth_key_insert_hash)} 119 # If inserting into the email auth table causes a violation, we can pull the 120 # existing email auth key from the table, or reraise. 121 raise e unless @email_auth_key_value = get_email_auth_key(account_id) 122 end 123 end 124 end
# File lib/rodauth/features/email_base.rb 51 def create_email_to(to, subject, body) 52 m = Mail.new 53 m.from = email_from 54 m.to = to 55 m.subject = "#{email_subject_prefix}#{subject}" 56 m.body = body 57 m 58 end
# File lib/rodauth/features/reset_password.rb 162 def create_reset_password_key 163 transaction do 164 if reset_password_key_value = get_password_reset_key(account_id) 165 set_reset_password_email_last_sent 166 @reset_password_key_value = reset_password_key_value 167 elsif e = raised_uniqueness_violation{password_reset_ds.insert(reset_password_key_insert_hash)} 168 # If inserting into the reset password table causes a violation, we can pull the 169 # existing reset password key from the table, or reraise. 170 raise e unless @reset_password_key_value = get_password_reset_key(account_id) 171 end 172 end 173 end
# File lib/rodauth/features/verify_account.rb 298 def create_verify_account_key 299 ds = verify_account_ds 300 transaction do 301 if ds.empty? 302 if e = raised_uniqueness_violation{ds.insert(verify_account_key_insert_hash)} 303 # If inserting into the verify account table causes a violation, we can pull the 304 # key from the verify account table, or reraise. 305 raise e unless @verify_account_key_value = get_verify_account_key(account_id) 306 end 307 end 308 end 309 end
# File lib/rodauth/features/verify_login_change.rb 204 def create_verify_login_change_email(login) 205 create_email_to(login, verify_login_change_email_subject, verify_login_change_email_body) 206 end
# File lib/rodauth/features/verify_login_change.rb 182 def create_verify_login_change_key(login) 183 ds = verify_login_change_ds 184 transaction do 185 ds.where((Sequel::CURRENT_TIMESTAMP > verify_login_change_deadline_column) | ~Sequel.expr(verify_login_change_login_column=>login)).delete 186 if e = raised_uniqueness_violation{ds.insert(verify_login_change_key_insert_hash(login))} 187 old_login, key = get_verify_login_change_login_and_key(account_id) 188 # If inserting into the verify login change table causes a violation, we can pull the 189 # key from the verify login change table if the logins match, or reraise. 190 @verify_login_change_key_value = if old_login.downcase == login.downcase 191 key 192 end 193 raise e unless @verify_login_change_key_value 194 end 195 end 196 end
# File lib/rodauth/features/base.rb 440 def csrf_tag(path=request.path) 441 return unless scope.respond_to?(:csrf_tag) 442 443 if use_request_specific_csrf_tokens? 444 scope.csrf_tag(path) 445 else 446 # :nocov: 447 scope.csrf_tag 448 # :nocov: 449 end 450 end
# File lib/rodauth/features/active_sessions.rb 42 def currently_active_session? 43 return false unless session_id = session[session_id_session_key] 44 45 remove_inactive_sessions 46 ds = active_sessions_ds. 47 where(active_sessions_session_id_column => compute_hmacs(session_id)) 48 49 if update_current_session? 50 ds.update(active_sessions_update_hash) == 1 51 else 52 ds.count == 1 53 end 54 end
# File lib/rodauth/features/argon2.rb 121 def database_function_password_match?(name, hash_id, password, salt) 122 return true if super 123 124 if use_argon2? && argon2_hash_algorithm?(salt) && argon2_old_secret != argon2_secret && (ret = db.get(Sequel.function(function_name(name), hash_id, argon2_password_hash_using_salt_and_secret(password, salt, argon2_old_secret)))) 125 @update_password_hash = true 126 end 127 128 !!ret 129 end
# File lib/rodauth/features/base.rb 325 def db 326 Sequel::DATABASES.first or raise "Sequel database connection is missing" 327 end
# File lib/rodauth/features/close_account.rb 77 def delete_account 78 account_ds.delete 79 end
# File lib/rodauth/features/close_account.rb 81 def delete_account_on_close? 82 skip_status_checks? 83 end
# File lib/rodauth/features/remember.rb 159 def disable_remember_login 160 remove_remember_key 161 end
# File lib/rodauth/features/email_auth.rb 243 def email_auth_ds(id=account_id) 244 db[email_auth_table].where(email_auth_id_column=>id) 245 end
# File lib/rodauth/features/email_auth.rb 146 def email_auth_email_link 147 token_link(email_auth_route, email_auth_key_param, email_auth_key_value) 148 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 237 def email_auth_key_insert_hash 238 hash = {email_auth_id_column=>account_id, email_auth_key_column=>email_auth_key_value} 239 set_deadline_value(hash, email_auth_deadline_column, email_auth_deadline_interval) 240 hash 241 end
# File lib/rodauth/features/email_auth.rb 156 def email_auth_request_form 157 render('email-auth-request-form') 158 end
# File lib/rodauth/features/email_base.rb 33 def email_from 34 "webmaster@#{domain}" 35 end
# File lib/rodauth/features/email_base.rb 37 def email_to 38 account[login_column] 39 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_error_reason :session_expired 42 set_redirect_error_flash session_expiration_error_flash 43 redirect session_expiration_redirect 44 end
# File lib/rodauth/features/remember.rb 216 def extend_remember_deadline 217 active_remember_key_ds.update(remember_deadline_column=>Sequel.date_add(Sequel::CURRENT_TIMESTAMP, remember_period)) 218 remember_login 219 end
# File lib/rodauth/features/remember.rb 204 def extend_remember_deadline_while_logged_in? 205 return false unless extend_remember_deadline? 206 207 if extended_at = session[remember_deadline_extended_session_key] 208 extended_at + extend_remember_deadline_period < Time.now.to_i 209 elsif logged_in_via_remember_key? 210 # Handle existing sessions before the change to extend remember deadline 211 # while logged in. 212 true 213 end 214 end
# File lib/rodauth/features/argon2.rb 70 def extract_password_hash_cost(hash) 71 return super unless argon2_hash_algorithm?(hash) 72 73 /\A\$argon2id\$v=\d+\$m=(\d+),t=(\d+),p=(\d+)/ =~ hash 74 { t_cost: $2.to_i, m_cost: Math.log2($1.to_i).to_i, p_cost: $3.to_i } 75 end
# File lib/rodauth/features/base.rb 185 def features 186 self.class.features 187 end
# File lib/rodauth/features/base.rb 260 def field_attributes(field) 261 _field_attributes(field) || default_field_attributes 262 end
# File lib/rodauth/features/base.rb 217 def field_error(field) 218 return nil unless @field_errors 219 @field_errors[field] 220 end
# File lib/rodauth/features/base.rb 264 def field_error_attributes(field) 265 if field_error(field) 266 _field_error_attributes(field) 267 end 268 end
# File lib/rodauth/features/remember.rb 142 def forget_login 143 opts = Hash[remember_cookie_options] 144 opts[:path] = "/" unless opts.key?(:path) 145 ::Rack::Utils.delete_cookie_header!(response.headers, remember_cookie_key, opts) 146 end
# File lib/rodauth/features/base.rb 270 def formatted_field_error(field) 271 if error = field_error(field) 272 _formatted_field_error(field, error) 273 end 274 end
# File lib/rodauth/features/base.rb 845 def function_name(name) 846 if db.database_type == :mssql 847 # :nocov: 848 "dbo.#{name}" 849 # :nocov: 850 else 851 name 852 end 853 end
# File lib/rodauth/features/active_sessions.rb 195 def generate_active_sessions_key 196 @active_sessions_key = random_key 197 end
# File lib/rodauth/features/email_auth.rb 229 def generate_email_auth_key_value 230 @email_auth_key_value = random_key 231 end
# File lib/rodauth/features/jwt_refresh.rb 200 def generate_refresh_token 201 hash = jwt_refresh_token_insert_hash 202 [account_id, jwt_refresh_token_ds.insert(hash), convert_token_key(hash[jwt_refresh_token_key_column])].join(token_separator) 203 end
# File lib/rodauth/features/remember.rb 257 def generate_remember_key_value 258 @remember_key_value = random_key 259 end
# File lib/rodauth/features/reset_password.rb 238 def generate_reset_password_key_value 239 @reset_password_key_value = random_key 240 end
# File lib/rodauth/features/lockout.rb 288 def generate_unlock_account_key 289 random_key 290 end
# File lib/rodauth/features/verify_account.rb 294 def generate_verify_account_key_value 295 @verify_account_key_value = random_key 296 end
# File lib/rodauth/features/verify_login_change.rb 178 def generate_verify_login_change_key_value 179 @verify_login_change_key_value = random_key 180 end
# File lib/rodauth/features/jwt_refresh.rb 169 def get_active_refresh_token(account_id, token_id) 170 jwt_refresh_token_account_ds(account_id). 171 where(Sequel::CURRENT_TIMESTAMP > jwt_refresh_token_deadline_column). 172 delete 173 174 ds = jwt_refresh_token_account_token_ds(account_id, token_id) 175 if @jwt_refresh_key_for_update 176 ds = ds.for_update 177 @jwt_refresh_key_for_update = nil 178 end 179 ds.get(jwt_refresh_token_key_column) 180 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 130 def get_email_auth_email_last_sent 131 if column = email_auth_email_last_sent_column 132 if ts = email_auth_ds.get(column) 133 convert_timestamp(ts) 134 end 135 end 136 end
# File lib/rodauth/features/email_auth.rb 150 def get_email_auth_key(id) 151 ds = email_auth_ds(id) 152 ds.where(Sequel::CURRENT_TIMESTAMP > email_auth_deadline_column).delete 153 apply_key_for_update(ds).get(email_auth_key_column) 154 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 861 def get_password_hash 862 if account_password_hash_column 863 account[account_password_hash_column] if account! 864 elsif use_database_authentication_functions? 865 db.get(Sequel.function(function_name(:rodauth_get_salt), account_id_or_session_value)) 866 else 867 # :nocov: 868 password_hash_ds.get(password_hash_column) 869 # :nocov: 870 end 871 end
# File lib/rodauth/features/reset_password.rb 191 def get_password_reset_key(id) 192 # RODAUTH3: Remove method and call get_reset_password_key directly 193 get_reset_password_key(id) 194 end
# File lib/rodauth/features/remember.rb 148 def get_remember_key 149 unless @remember_key_value = active_remember_key_ds.get(remember_key_column) 150 generate_remember_key_value 151 transaction do 152 remove_remember_key 153 add_remember_key 154 end 155 end 156 nil 157 end
# File lib/rodauth/features/reset_password.rb 206 def get_reset_password_email_last_sent 207 if column = reset_password_email_last_sent_column 208 if ts = password_reset_ds.get(column) 209 convert_timestamp(ts) 210 end 211 end 212 end
# File lib/rodauth/features/reset_password.rb 196 def get_reset_password_key(id) 197 ds = password_reset_ds(id) 198 ds.where(Sequel::CURRENT_TIMESTAMP > reset_password_deadline_column).delete 199 apply_key_for_update(ds).get(reset_password_key_column) 200 end
# File lib/rodauth/features/lockout.rb 234 def get_unlock_account_email_last_sent 235 if column = account_lockouts_email_last_sent_column 236 if ts = account_lockouts_ds.get(column) 237 convert_timestamp(ts) 238 end 239 end 240 end
# File lib/rodauth/features/lockout.rb 222 def get_unlock_account_key 223 account_lockouts_ds.get(account_lockouts_key_column) 224 end
# File lib/rodauth/features/verify_account.rb 232 def get_verify_account_email_last_sent 233 if column = verify_account_email_last_sent_column 234 if ts = verify_account_ds.get(column) 235 convert_timestamp(ts) 236 end 237 end 238 end
# File lib/rodauth/features/verify_account.rb 211 def get_verify_account_key(id) 212 apply_key_for_update(verify_account_ds(id)).get(verify_account_key_column) 213 end
# File lib/rodauth/features/verify_login_change.rb 136 def get_verify_login_change_login_and_key(id) 137 ds = verify_login_change_ds(id) 138 ds.where(Sequel::CURRENT_TIMESTAMP > verify_login_change_deadline_column).delete 139 apply_key_for_update(ds).get([verify_login_change_login_column, verify_login_change_key_column]) 140 end
# File lib/rodauth/features/active_sessions.rb 79 def handle_duplicate_active_session_id(_e) 80 # Do nothing by default as session is already tracked. This will result in 81 # the current session and the existing session with the same id 82 # being tracked together, so that a logout of one will logout 83 # the other, and updating the last use on one will update the other, 84 # but this should be acceptable. However, this can be overridden if different 85 # behavior is desired. 86 end
# File lib/rodauth/features/reset_password.rb 268 def handle_invalid_reset_password_key 269 remove_session_value(reset_password_session_key) 270 set_redirect_error_status(invalid_key_error_status) 271 set_error_reason :invalid_reset_password_key 272 set_redirect_error_flash reset_password_error_flash 273 redirect reset_password_email_sent_redirect 274 end
# File lib/rodauth/features/verify_account.rb 323 def handle_invalid_verify_account_key 324 remove_session_value(verify_account_session_key) 325 set_redirect_error_status(invalid_key_error_status) 326 set_error_reason :invalid_verify_account_key 327 set_redirect_error_flash verify_account_error_flash 328 redirect verify_account_redirect 329 end
# File lib/rodauth/features/webauthn.rb 352 def handle_webauthn_sign_count_verification_error 353 throw_error_reason(:invalid_webauthn_sign_count, invalid_field_error_status, webauthn_auth_param, webauthn_invalid_sign_count_message) 354 end
# File lib/rodauth/features/base.rb 588 def has_password? 589 return @has_password unless @has_password.nil? 590 return false unless account_id_or_session_value 591 @has_password = !!get_password_hash 592 end
# File lib/rodauth/features/base.rb 896 def hmac_secret_rotation? 897 hmac_secret && hmac_old_secret && hmac_secret != hmac_old_secret 898 end
# File lib/rodauth/features/audit_logging.rb 31 def hook_action(hook_type, action) 32 super 33 34 # In after_logout, session is already cleared, so use before_logout in that case 35 if (hook_type == :after || action == :logout) && (id = account_id_or_session_value) 36 add_audit_log(id, action) 37 end 38 end
# File lib/rodauth/features/http_basic_auth.rb 36 def http_basic_auth 37 unless @checked_http_basic_auth.nil? 38 return (@checked_http_basic_auth ? true : nil) 39 end 40 41 @checked_http_basic_auth = false 42 return unless token = ((v = request.env['HTTP_AUTHORIZATION']) && v[/\A *Basic (.*)\Z/, 1]) 43 44 username, password = token.unpack("m*").first.split(/:/, 2) 45 return unless username && password 46 47 catch_error do 48 unless account_from_login(username) 49 after_no_matching_login 50 throw_basic_auth_error(login_param, no_matching_login_message) 51 end 52 53 before_login_attempt 54 55 unless open_account? 56 throw_basic_auth_error(login_param, no_matching_login_message) 57 end 58 59 unless password_match?(password) 60 after_login_failure 61 throw_basic_auth_error(password_param, invalid_password_message) 62 end 63 64 transaction do 65 before_login 66 login_session('password') 67 after_login 68 end 69 70 @checked_http_basic_auth = true 71 return true 72 end 73 74 nil 75 end
# File lib/rodauth/features/active_sessions.rb 225 def inactive_session_cond 226 cond = session_inactivity_deadline_condition 227 cond2 = session_lifetime_deadline_condition 228 return false unless cond || cond2 229 Sequel.|(*[cond, cond2].compact) 230 end
# File lib/rodauth/features/json.rb 224 def include_success_messages? 225 !json_response_success_key.nil? 226 end
# File lib/rodauth/features/base.rb 228 def input_field_string(param, id, opts=OPTS) 229 type = opts.fetch(:type, "text") 230 231 unless type == "password" 232 value = opts.fetch(:value){scope.h param(param)} 233 end 234 235 field_class = opts.fetch(:class, "form-control") 236 237 if autocomplete_for_field?(param) && opts[:autocomplete] 238 autocomplete = "autocomplete=\"#{opts[:autocomplete]}\"" 239 end 240 241 if inputmode_for_field?(param) && opts[:inputmode] 242 inputmode = "inputmode=\"#{opts[:inputmode]}\"" 243 end 244 245 if mark_input_fields_as_required? && opts[:required] != false 246 required = "required=\"required\"" 247 end 248 249 "<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]}" 250 end
# File lib/rodauth/features/base.rb 256 def inputmode_for_field?(_param) 257 mark_input_fields_with_inputmode? 258 end
:nocov:
# File lib/rodauth/features/base.rb 1029 def instance_variables_to_inspect 1030 instance_variables.reject{|v| instance_variable_get(v).nil?} 1031 end
# File lib/rodauth/features/base.rb 1010 def internal_request? 1011 false 1012 end
# File lib/rodauth/features/internal_request.rb 391 def internal_request_configuration(&block) 392 @auth.instance_exec do 393 (@internal_request_configuration_blocks ||= []) << block 394 end 395 end
# File lib/rodauth/features/lockout.rb 181 def invalid_login_attempted 182 ds = account_login_failures_ds. 183 where(account_login_failures_id_column=>account_id) 184 185 number = if db.database_type == :postgres 186 ds.returning(account_login_failures_number_column). 187 with_sql(:update_sql, account_login_failures_number_column=>Sequel.expr(account_login_failures_number_column)+1). 188 single_value 189 else 190 # :nocov: 191 if ds.update(account_login_failures_number_column=>Sequel.expr(account_login_failures_number_column)+1) > 0 192 ds.get(account_login_failures_number_column) 193 end 194 # :nocov: 195 end 196 197 unless number 198 # Ignoring the violation is safe here. It may allow slightly more than max_invalid_logins invalid logins before 199 # lockout, but allowing a few extra is OK if the race is lost. 200 ignore_uniqueness_violation{account_login_failures_ds.insert(account_login_failures_id_column=>account_id)} 201 number = 1 202 end 203 204 if number >= max_invalid_logins 205 @unlock_account_key_value = generate_unlock_account_key 206 hash = _setup_account_lockouts_hash(account_id, unlock_account_key_value) 207 208 if e = raised_uniqueness_violation{account_lockouts_ds.insert(hash)} 209 # If inserting into the lockout table raises a violation, we should just be able to pull the already inserted 210 # key out of it. If that doesn't return a valid key, we should reraise the error. 211 raise e unless @unlock_account_key_value = account_lockouts_ds.get(account_lockouts_key_column) 212 213 after_account_lockout 214 show_lockout_page 215 else 216 after_account_lockout 217 e 218 end 219 end 220 end
# File lib/rodauth/features/change_password.rb 82 def invalid_previous_password_message 83 invalid_password_message 84 end
# File lib/rodauth/features/json.rb 59 def json_request? 60 return @json_request unless @json_request.nil? 61 @json_request = !(request.content_type !~ json_request_content_type_regexp) 62 end
# File lib/rodauth/features/json.rb 232 def json_response 233 @json_response ||= {} 234 end
# File lib/rodauth/features/json.rb 73 def json_response_error? 74 !!json_response[json_response_error_key] 75 end
# File lib/rodauth/features/jwt_cors.rb 16 def jwt_cors_allow? 17 return false unless origin = request.env['HTTP_ORIGIN'] 18 19 case allowed = jwt_cors_allow_origin 20 when String 21 timing_safe_eql?(origin, allowed) 22 when Array 23 allowed.any?{|s| timing_safe_eql?(origin, s)} 24 when Regexp 25 allowed =~ origin 26 when true 27 true 28 else 29 false 30 end 31 end
# File lib/rodauth/features/jwt.rb 124 def jwt_payload 125 return @jwt_payload unless @jwt_payload.nil? 126 @jwt_payload = JWT.decode(jwt_token, _jwt_decode_secrets, true, _jwt_decode_opts.merge(:algorithm=>jwt_algorithm))[0] 127 rescue JWT::DecodeError => e 128 rescue_jwt_payload(e) 129 end
# File lib/rodauth/features/jwt_refresh.rb 182 def jwt_refresh_token_account_ds(account_id) 183 jwt_refresh_token_ds.where(jwt_refresh_token_account_id_column => account_id) 184 end
# File lib/rodauth/features/jwt_refresh.rb 186 def jwt_refresh_token_account_token_ds(account_id, token_id) 187 jwt_refresh_token_account_ds(account_id). 188 where(jwt_refresh_token_id_column=>token_id) 189 end
# File lib/rodauth/features/jwt_refresh.rb 191 def jwt_refresh_token_ds 192 db[jwt_refresh_token_table] 193 end
# File lib/rodauth/features/jwt_refresh.rb 205 def jwt_refresh_token_insert_hash 206 hash = {jwt_refresh_token_account_id_column => account_id, jwt_refresh_token_key_column => random_key} 207 set_deadline_value(hash, jwt_refresh_token_deadline_column, jwt_refresh_token_deadline_interval) 208 hash 209 end
# File lib/rodauth/features/jwt_refresh.rb 158 def jwt_refresh_token_match?(key) 159 # We don't need to match tokens if we are requiring a valid current access token 160 return true unless allow_refresh_with_expired_jwt_access_token? 161 162 # If allowing with expired jwt access token, check the expired session contains 163 # hmac matching submitted and active refresh token. 164 s = session[jwt_refresh_token_hmac_session_key].to_s 165 h = session[jwt_refresh_token_data_session_key].to_s + key 166 timing_safe_eql?(compute_hmac(h), s) || (hmac_secret_rotation? && timing_safe_eql?(compute_old_hmac(h), s)) 167 end
# File lib/rodauth/features/jwt.rb 68 def jwt_secret 69 raise ConfigurationError, "jwt_secret not set" 70 end
# File lib/rodauth/features/jwt.rb 72 def jwt_session_hash 73 jwt_session_key ? {jwt_session_key=>session} : session 74 end
# File lib/rodauth/features/jwt.rb 80 def jwt_token 81 return @jwt_token if @jwt_token 82 83 if (v = request.env['HTTP_AUTHORIZATION']) && v !~ jwt_authorization_ignore 84 @jwt_token = v.sub(jwt_authorization_remove, '') 85 end 86 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 118 def load_memory 119 if logged_in? 120 if extend_remember_deadline_while_logged_in? 121 if account_from_session 122 extend_remember_deadline 123 else 124 forget_login 125 clear_session 126 end 127 end 128 elsif account_from_remember_cookie 129 before_load_memory 130 login_session('remember') 131 extend_remember_deadline if extend_remember_deadline? 132 after_load_memory 133 end 134 end
# File lib/rodauth/features/base.rb 950 def loaded_templates 951 [] 952 end
# File lib/rodauth/features/lockout.rb 152 def locked_out? 153 if t = convert_timestamp(account_lockouts_ds.get(account_lockouts_deadline_column)) 154 if Time.now < t 155 true 156 else 157 unlock_account 158 false 159 end 160 else 161 false 162 end 163 end
# File lib/rodauth/features/remember.rb 178 def logged_in_via_remember_key? 179 authenticated_by.include?('remember') 180 end
# File lib/rodauth/features/login.rb 97 def login(auth_type) 98 @saved_login_redirect = remove_session_value(login_redirect_session_key) 99 transaction do 100 before_login 101 login_session(auth_type) 102 yield if block_given? 103 after_login 104 end 105 require_response(:_login_response) 106 end
# File lib/rodauth/features/login_password_requirements_base.rb 49 def login_confirm_label 50 "Confirm #{login_label}" 51 end
# File lib/rodauth/features/login_password_requirements_base.rb 159 def login_confirmation_matches?(login, login_confirmation) 160 login.casecmp?(login_confirmation) 161 end
# File lib/rodauth/features/login_password_requirements_base.rb 137 def login_does_not_meet_requirements_message 138 "invalid login#{", #{login_requirement_message}" if login_requirement_message}" 139 end
# File lib/rodauth/features/reset_password.rb 242 def login_failed_reset_password_request_form 243 render("reset-password-request") 244 end
# File lib/rodauth/features/base.rb 329 def login_field_autocomplete_value 330 login_uses_email? ? "email" : "on" 331 end
# File lib/rodauth/features/base.rb 355 def login_input_type 356 login_uses_email? ? 'email' : 'text' 357 end
# File lib/rodauth/features/login_password_requirements_base.rb 185 def login_meets_email_requirements?(login) 186 return true unless require_email_address_logins? 187 return true if login_valid_email?(login) 188 set_login_requirement_error_message(:login_not_valid_email, login_not_valid_email_message) 189 return false 190 end
# File lib/rodauth/features/login_password_requirements_base.rb 170 def login_meets_length_requirements?(login) 171 if login_minimum_length > login.length 172 set_login_requirement_error_message(:login_too_short, login_too_short_message) 173 false 174 elsif login_maximum_length < login.length 175 set_login_requirement_error_message(:login_too_long, login_too_long_message) 176 false 177 elsif login_maximum_bytes < login.bytesize 178 set_login_requirement_error_message(:login_too_many_bytes, login_too_many_bytes_message) 179 false 180 else 181 true 182 end 183 end
# File lib/rodauth/features/login_password_requirements_base.rb 57 def login_meets_requirements?(login) 58 login_meets_length_requirements?(login) && \ 59 login_meets_email_requirements?(login) 60 end
The normalized value of the login parameter
# File lib/rodauth/features/base.rb 553 def login_param_value 554 normalize_login(param(login_param)) 555 end
# File lib/rodauth/features/base.rb 374 def login_required 375 set_redirect_error_status(login_required_error_status) 376 set_error_reason :login_required 377 set_redirect_error_flash require_login_error_flash 378 redirect require_login_redirect 379 end
# File lib/rodauth/features/login.rb 115 def login_return_to_requested_location_path 116 request.fullpath 117 end
# File lib/rodauth/features/base.rb 515 def login_session(auth_type) 516 update_session 517 set_session_value(authenticated_by_session_key, [auth_type]) 518 end
# File lib/rodauth/features/login_password_requirements_base.rb 141 def login_too_long_message 142 "maximum #{login_maximum_length} characters" 143 end
# File lib/rodauth/features/login_password_requirements_base.rb 145 def login_too_many_bytes_message 146 "maximum #{login_maximum_bytes} bytes" 147 end
# File lib/rodauth/features/login_password_requirements_base.rb 149 def login_too_short_message 150 "minimum #{login_minimum_length} characters" 151 end
# File lib/rodauth/features/base.rb 359 def login_uses_email? 360 login_column == :email 361 end
# File lib/rodauth/features/login_password_requirements_base.rb 192 def login_valid_email?(login) 193 login =~ login_email_regexp 194 end
# File lib/rodauth/features/active_sessions.rb 120 def logout_additional_form_tags 121 super.to_s + render('global-logout-field') 122 end
:nocov:
# File lib/rodauth/features/base.rb 669 def missing_recommended_configuration(msg) 670 # RODAUTH3: switch to raise ConfigurationError 671 warn msg 672 end
# File lib/rodauth/features/base.rb 580 def modifications_require_password? 581 has_password? 582 end
# File lib/rodauth/features/create_account.rb 96 def new_account(login) 97 @account_retrieval_type = nil 98 set_account(_new_account(login), :new) 99 end
# File lib/rodauth/features/base.rb 873 def new_password_matches_current_password?(password) 874 password_match?(password) 875 end
# File lib/rodauth/features/recovery_codes.rb 245 def new_recovery_code 246 random_key 247 end
# File lib/rodauth/features/webauthn.rb 302 def new_webauthn_credential 303 WebAuthn::Credential.options_for_create( 304 :timeout => webauthn_setup_timeout, 305 :user => {:id=>account_webauthn_user_id, :name=>webauthn_user_name}, 306 :authenticator_selection => webauthn_authenticator_selection, 307 :attestation => webauthn_attestation, 308 :extensions => webauthn_extensions, 309 :exclude => account_webauthn_ids, 310 **webauthn_create_relying_party_opts 311 ) 312 end
# File lib/rodauth/features/active_sessions.rb 62 def no_longer_active_session 63 clear_session 64 set_redirect_error_status inactive_session_error_status 65 set_error_reason :inactive_session 66 set_redirect_error_flash active_sessions_error_flash 67 redirect active_sessions_redirect 68 end
# File lib/rodauth/features/base.rb 557 def normalize_login(login) 558 login 559 end
# File lib/rodauth/features/base.rb 763 def normalize_session_or_flash_key(key) 764 scope.opts[:sessions_convert_symbols] ? key.to_s : key 765 end
Return nil by default for values with null bytes
# File lib/rodauth/features/base.rb 562 def null_byte_parameter_value(key, value) 563 nil 564 end
# File lib/rodauth/features/base.rb 474 def only_json? 475 scope.class.opts[:rodauth_json] == :only 476 end
# File lib/rodauth/features/base.rb 321 def open_account? 322 skip_status_checks? || account[account_status_column] == account_open_status_value 323 end
# File lib/rodauth/features/otp.rb 294 def otp_add_key 295 _otp_add_key(otp_key) 296 super if defined?(super) 297 end
# File lib/rodauth/features/otp.rb 250 def otp_available? 251 otp_exists? && !otp_locked_out? 252 end
# File lib/rodauth/features/otp.rb 254 def otp_exists? 255 !!otp_key 256 end
# File lib/rodauth/features/otp.rb 394 def otp_hmac_old_secret(key) 395 base32_encode(compute_raw_hmac_with_secret(ROTP::Base32.decode(key), hmac_old_secret), key.bytesize) 396 end
# File lib/rodauth/features/otp.rb 390 def otp_hmac_secret(key) 391 base32_encode(compute_raw_hmac(ROTP::Base32.decode(key)), key.bytesize) 392 end
# File lib/rodauth/features/otp.rb 461 def otp_key_ds 462 db[otp_keys_table].where(otp_keys_id_column=>session_value) 463 end
# File lib/rodauth/features/otp.rb 346 def otp_keys_use_hmac? 347 !!hmac_secret 348 end
# File lib/rodauth/features/otp.rb 305 def otp_last_use 306 convert_timestamp(otp_key_ds.get(otp_keys_last_use_column)) 307 end
# File lib/rodauth/features/otp.rb 317 def otp_locked_out? 318 otp_key_ds.get(otp_keys_failures_column) >= otp_auth_failures_limit 319 end
# File lib/rodauth/features/otp_unlock.rb 212 def otp_lockout_redirect 213 otp_unlock_path 214 end
# File lib/rodauth/features/otp.rb 412 def otp_new_secret 413 ROTP::Base32.random_base32.downcase 414 end
# File lib/rodauth/features/otp.rb 329 def otp_provisioning_name 330 account[login_column] 331 end
# File lib/rodauth/features/otp.rb 321 def otp_provisioning_uri 322 otp.provisioning_uri(otp_provisioning_name) 323 end
# File lib/rodauth/features/otp.rb 333 def otp_qr_code 334 svg = RQRCode::QRCode.new(otp_provisioning_uri).as_svg(:module_size=>8, :viewbox=>true, :use_path=>true, :fill=>"fff") 335 svg.sub(/\A<\?xml version="1\.0" standalone="yes"\?>/, '') 336 end
# File lib/rodauth/features/otp.rb 309 def otp_record_authentication_failure 310 otp_key_ds.update(otp_keys_failures_column=>Sequel.identifier(otp_keys_failures_column) + 1) 311 end
# File lib/rodauth/features/otp.rb 289 def otp_remove 290 otp_key_ds.delete 291 @otp_key = false 292 end
# File lib/rodauth/features/otp.rb 313 def otp_remove_auth_failures 314 otp_key_ds.update(otp_keys_failures_column=>0) 315 end
# File lib/rodauth/features/otp.rb 385 def otp_tmp_key(secret) 386 _otp_tmp_key(secret) 387 clear_cached_otp 388 end
# File lib/rodauth/features/otp_unlock.rb 147 def otp_unlock_auth_failure 148 h = { 149 otp_unlock_num_successes_column=>0, 150 otp_unlock_next_auth_attempt_after_column=>Sequel.date_add(Sequel::CURRENT_TIMESTAMP, :seconds=>otp_unlock_auth_failure_cooldown_seconds) 151 } 152 153 if otp_unlock_ds.update(h) == 0 154 h[otp_unlock_id_column] = session_value 155 156 # If row already exists when inserting, no need to do anything 157 raises_uniqueness_violation?{otp_unlock_ds.insert(h)} 158 end 159 end
# File lib/rodauth/features/otp_unlock.rb 161 def otp_unlock_auth_success 162 deadline = Sequel.date_add(Sequel::CURRENT_TIMESTAMP, :seconds=>otp_unlock_success_cooldown_seconds) 163 164 # Add WHERE to avoid possible race condition when multiple unlock auth requests 165 # are sent at the same time (only the first should increment num successes). 166 if otp_unlock_ds. 167 where(Sequel[otp_unlock_next_auth_attempt_after_column] < Sequel::CURRENT_TIMESTAMP). 168 update( 169 otp_unlock_num_successes_column=>Sequel[otp_unlock_num_successes_column]+1, 170 otp_unlock_next_auth_attempt_after_column=>deadline 171 ) == 0 172 173 # Ignore uniqueness errors when inserting after a failed update, 174 # which could be caused due to the race condition mentioned above. 175 raises_uniqueness_violation? do 176 otp_unlock_ds.insert( 177 otp_unlock_id_column=>session_value, 178 otp_unlock_next_auth_attempt_after_column=>deadline 179 ) 180 end 181 end 182 183 @otp_unlock_data = nil 184 # :nocov: 185 if otp_unlock_data 186 # :nocov: 187 if otp_unlock_num_successes >= otp_unlock_auths_required 188 # At least the requisite number of consecutive successful unlock 189 # authentications. Unlock OTP authentication. 190 otp_key_ds.update(otp_keys_failures_column => 0) 191 192 # Remove OTP unlock metadata when unlocking OTP authentication 193 otp_unlock_reset 194 # else 195 # # Still need additional consecutive successful unlock attempts. 196 end 197 # else 198 # # if row isn't available, probably the process was reset during this, 199 # # and it's safe to do nothing in that case. 200 end 201 end
# File lib/rodauth/features/otp_unlock.rb 117 def otp_unlock_available? 118 if otp_unlock_data 119 next_auth_attempt_after = otp_unlock_next_auth_attempt_after 120 current_timestamp = Time.now 121 122 if (next_auth_attempt_after < current_timestamp - otp_unlock_deadline_seconds) 123 # Unlock process not fully completed within deadline, reset process 124 otp_unlock_reset 125 true 126 else 127 if next_auth_attempt_after > current_timestamp 128 # If next auth attempt after timestamp is in the future, that means the next 129 # unlock attempt cannot happen until then. 130 false 131 else 132 if otp_unlock_num_successes == 0 133 # 0 value indicates previous attempt was a failure. Since failure cooldown 134 # period has passed, reset process so user gets full deadline period 135 otp_unlock_reset 136 end 137 true 138 end 139 end 140 else 141 # No row means no unlock attempts yet (or previous attempt was more than the 142 # deadline account, so unlocking is available 143 true 144 end 145 end
# File lib/rodauth/features/otp_unlock.rb 242 def otp_unlock_data 243 @otp_unlock_data ||= otp_unlock_ds.first 244 end
# File lib/rodauth/features/otp_unlock.rb 224 def otp_unlock_deadline 225 otp_unlock_next_auth_attempt_after + otp_unlock_deadline_seconds 226 end
# File lib/rodauth/features/otp_unlock.rb 203 def otp_unlock_deadline_passed? 204 otp_unlock_data ? (otp_unlock_next_auth_attempt_after < Time.now - otp_unlock_deadline_seconds) : false 205 end
# File lib/rodauth/features/otp_unlock.rb 255 def otp_unlock_ds 256 db[otp_unlock_table].where(otp_unlock_id_column=>session_value) 257 end
# File lib/rodauth/features/otp_unlock.rb 216 def otp_unlock_next_auth_attempt_after 217 if otp_unlock_data 218 convert_timestamp(otp_unlock_data[otp_unlock_next_auth_attempt_after_column]) 219 else 220 Time.now 221 end 222 end
# File lib/rodauth/features/otp_unlock.rb 232 def otp_unlock_not_available_set_refresh_header 233 response.headers["refresh"] = ((otp_unlock_next_auth_attempt_after - Time.now).to_i + 1).to_s 234 end
# File lib/rodauth/features/otp_unlock.rb 228 def otp_unlock_num_successes 229 otp_unlock_data ? otp_unlock_data[otp_unlock_num_successes_column] : 0 230 end
# File lib/rodauth/features/otp_unlock.rb 207 def otp_unlock_refresh_tag 208 # RODAUTH3: Remove 209 "<meta http-equiv=\"refresh\" content=\"#{(otp_unlock_next_auth_attempt_after - Time.now).to_i + 1}\">" 210 end
# File lib/rodauth/features/otp_unlock.rb 250 def otp_unlock_reset 251 otp_unlock_ds.delete 252 @otp_unlock_data = nil 253 end
# File lib/rodauth/features/otp_unlock.rb 246 def otp_unlock_success_cooldown_seconds 247 (_otp_interval+(otp_drift||0))*2 248 end
# File lib/rodauth/features/otp.rb 299 def otp_update_last_use 300 otp_key_ds. 301 where(Sequel.date_add(otp_keys_last_use_column, :seconds=>_otp_interval) < Sequel::CURRENT_TIMESTAMP). 302 update(otp_keys_last_use_column=>Sequel::CURRENT_TIMESTAMP) == 1 303 end
# File lib/rodauth/features/otp.rb 338 def otp_user_key 339 @otp_user_key ||= if otp_keys_use_hmac? 340 otp_hmac_secret(otp_key) 341 else 342 otp_key 343 end 344 end
# File lib/rodauth/features/otp.rb 258 def otp_valid_code?(ot_pass) 259 if _otp_valid_code?(ot_pass, otp) 260 true 261 elsif hmac_secret_rotation? && _otp_valid_code?(ot_pass, _otp_for_key(otp_hmac_old_secret(otp_key))) 262 _otp_valid_code_for_old_secret 263 true 264 else 265 false 266 end 267 end
# File lib/rodauth/features/otp.rb 398 def otp_valid_key?(secret) 399 return false unless secret =~ /\A([a-z2-7]{16}|[a-z2-7]{32})\z/ 400 if otp_keys_use_hmac? 401 # Purposely do not allow creating new OTPs with old secrets, 402 # since OTP rotation is difficult. The user will get shown 403 # the same page with an updated secret, which they can submit 404 # to setup OTP. 405 timing_safe_eql?(otp_hmac_secret(param(otp_setup_raw_param)), secret) 406 else 407 true 408 end 409 end
Return nil by default for values over maximum bytesize.
# File lib/rodauth/features/base.rb 548 def over_max_bytesize_param_value(key, value) 549 nil 550 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 531 def param(key) 532 param_or_nil(key).to_s 533 end
Return a string for the parameter name, or nil if there is no parameter with that name.
# File lib/rodauth/features/base.rb 537 def param_or_nil(key) 538 value = raw_param(key) 539 unless value.nil? 540 value = value.to_s 541 value = over_max_bytesize_param_value(key, value) if max_param_bytesize && value.bytesize > max_param_bytesize 542 value = null_byte_parameter_value(key, value) if value && value.include?("\0") 543 end 544 value 545 end
# File lib/rodauth/features/login_password_requirements_base.rb 211 def password_bytesize(password) 212 password.bytesize 213 end
# File lib/rodauth/features/login_password_requirements_base.rb 53 def password_confirm_label 54 "Confirm #{password_label}" 55 end
# File lib/rodauth/features/login_password_requirements_base.rb 215 def password_does_not_contain_null_byte?(password) 216 return true unless password.include?("\0") 217 set_password_requirement_error_message(:password_contains_null_byte, contains_null_byte_message) 218 false 219 end
# File lib/rodauth/features/login_password_requirements_base.rb 116 def password_does_not_meet_requirements_message 117 "invalid password, does not meet requirements#{" (#{password_requirement_message})" if password_requirement_message}" 118 end
# File lib/rodauth/features/disallow_password_reuse.rb 52 def password_doesnt_match_previous_password?(password) 53 match = if use_database_authentication_functions? 54 salts = previous_password_ds. 55 select_map([previous_password_id_column, Sequel.function(function_name(:rodauth_get_previous_salt), previous_password_id_column).as(:salt)]) 56 return true if salts.empty? 57 58 salts.any? do |hash_id, salt| 59 database_function_password_match?(:rodauth_previous_password_hash_match, hash_id, password, salt) 60 end 61 else 62 # :nocov: 63 previous_password_ds.select_map(previous_password_hash_column).any? do |hash| 64 password_hash_match?(hash, password) 65 end 66 # :nocov: 67 end 68 69 return true unless match 70 set_password_requirement_error_message(:password_same_as_previous_password, password_same_as_previous_password_message) 71 false 72 end
# File lib/rodauth/features/password_expiration.rb 106 def password_expiration_ds 107 db[password_expiration_table].where(password_expiration_id_column=>account_id) 108 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 if password_changed_at = get_password_changed_at 74 set_session_value(password_changed_at_session_key, password_changed_at.to_i) 75 password_changed_at + require_password_change_after < Time.now 76 else 77 set_session_value(password_changed_at_session_key, password_expiration_default ? 0 : 2147483647) 78 password_expiration_default 79 end 80 end
# File lib/rodauth/features/base.rb 333 def password_field_autocomplete_value 334 @password_field_autocomplete_value || 'current-password' 335 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 set_password_requirement_error_message(:not_enough_character_groups_in_password, 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 set_password_requirement_error_message(:invalid_password_pattern, password_invalid_pattern_message) 65 false 66 end
# File lib/rodauth/features/argon2.rb 21 def password_hash(password) 22 return super unless use_argon2? 23 24 if secret = argon2_secret 25 argon2_params = Hash[password_hash_cost] 26 argon2_params[:secret] = secret 27 else 28 argon2_params = password_hash_cost 29 end 30 ::Argon2::Password.new(argon2_params).create(password) 31 end
# File lib/rodauth/features/argon2.rb 47 def password_hash_cost 48 return super unless use_argon2? 49 argon2_hash_cost 50 end
# File lib/rodauth/features/base.rb 940 def password_hash_ds 941 db[password_hash_table].where(password_hash_id_column=>account_id_or_session_value) 942 end
# File lib/rodauth/features/argon2.rb 52 def password_hash_match?(hash, password) 53 return super unless argon2_hash_algorithm?(hash) 54 argon2_password_hash_match?(hash, password) 55 end
# File lib/rodauth/features/argon2.rb 57 def password_hash_using_salt(password, salt) 58 return super unless argon2_hash_algorithm?(salt) 59 argon2_password_hash_using_salt_and_secret(password, salt, argon2_secret) 60 end
# File lib/rodauth/features/base.rb 496 def password_match?(password) 497 if @existing_password_hash_or_salt = hash = get_password_hash 498 if account_password_hash_column || !use_database_authentication_functions? 499 password_hash_match?(hash, password) 500 else 501 database_function_password_match?(:rodauth_valid_password_hash, account_id, password, hash) 502 end 503 end 504 end
# File lib/rodauth/features/login_password_requirements_base.rb 196 def password_meets_length_requirements?(password) 197 if password_minimum_length > password.length 198 set_password_requirement_error_message(:password_too_short, password_too_short_message) 199 false 200 elsif password_maximum_length && password_maximum_length < password.length 201 set_password_requirement_error_message(:password_too_long, password_too_long_message) 202 false 203 elsif password_maximum_bytes && password_maximum_bytes < password_bytesize(password) 204 set_password_requirement_error_message(:password_too_many_bytes, password_too_many_bytes_message) 205 false 206 else 207 true 208 end 209 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 set_password_requirement_error_message(:password_in_dictionary, 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 set_password_requirement_error_message(:password_is_one_of_the_most_common, 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 set_password_requirement_error_message(:too_many_repeating_characters_in_password, 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 24 def password_recently_entered? 25 return false unless last_password_entry = session[last_password_entry_session_key] 26 last_password_entry + password_grace_period > Time.now.to_i 27 end
# File lib/rodauth/features/reset_password.rb 256 def password_reset_ds(id=account_id) 257 db[reset_password_table].where(reset_password_id_column=>id) 258 end
# File lib/rodauth/features/login_password_requirements_base.rb 120 def password_too_long_message 121 "maximum #{password_maximum_length} characters" 122 end
# File lib/rodauth/features/login_password_requirements_base.rb 124 def password_too_many_bytes_message 125 "maximum #{password_maximum_bytes} bytes" 126 end
# File lib/rodauth/features/login_password_requirements_base.rb 128 def password_too_short_message 129 "minimum #{password_minimum_length} characters" 130 end
# File lib/rodauth/features/base.rb 584 def possible_authentication_methods 585 has_password? ? ['password'] : [] 586 end
# File lib/rodauth/features/base.rb 478 def post_configure 479 require 'bcrypt' if require_bcrypt? 480 db.extension :date_arithmetic if use_date_arithmetic? 481 482 if method(:convert_token_id_to_integer?).owner == Rodauth::Base && (db rescue false) && db.table_exists?(accounts_table) && db.schema(accounts_table).find{|col, v| break v[:type] == :integer if col == account_id_column} 483 self.class.send(:define_method, :convert_token_id_to_integer?){true} 484 end 485 486 route_hash= {} 487 self.class.routes.each do |meth| 488 route_meth = "#{meth.to_s.sub(/\Ahandle_/, '')}_route" 489 if route = send(route_meth) 490 route_hash["/#{route}"] = meth 491 end 492 end 493 self.class.route_hash = route_hash.freeze 494 end
# File lib/rodauth/features/disallow_password_reuse.rb 96 def previous_password_ds 97 db[previous_password_hash_table].where(previous_password_account_id_column=>account_id) 98 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 969 def raises_uniqueness_violation?(&block) 970 transaction(:savepoint=>:only, &block) 971 false 972 rescue unique_constraint_violation_class => e 973 e 974 end
# File lib/rodauth/features/base.rb 754 def random_key 755 SecureRandom.urlsafe_base64(32) 756 end
# File lib/rodauth/features/base.rb 566 def raw_param(key) 567 request.params[key] 568 end
# File lib/rodauth/features/recovery_codes.rb 162 def recovery_code_match?(code) 163 recovery_codes.each do |s| 164 if timing_safe_eql?(code, s) 165 unless recovery_codes_ds.where(recovery_codes_column=>code).delete == 1 166 return false 167 end 168 169 if recovery_codes_primary? 170 add_recovery_code 171 end 172 return true 173 end 174 end 175 false 176 end
# File lib/rodauth/features/recovery_codes.rb 201 def recovery_codes_available? 202 !recovery_codes_ds.empty? 203 end
# File lib/rodauth/features/recovery_codes.rb 269 def recovery_codes_ds 270 db[recovery_codes_table].where(recovery_codes_id_column=>session_value) 271 end
# File lib/rodauth/features/recovery_codes.rb 249 def recovery_codes_primary? 250 (features & [:otp, :sms_codes, :webauthn]).empty? 251 end
# File lib/rodauth/features/recovery_codes.rb 158 def recovery_codes_remove 159 recovery_codes_ds.delete 160 end
# File lib/rodauth/features/base.rb 730 def redirect(path) 731 request.redirect(path) 732 end
# File lib/rodauth/features/remember.rb 265 def remember_key_ds(id=account_id) 266 db[remember_table].where(remember_id_column=>id) 267 end
# File lib/rodauth/features/remember.rb 136 def remember_login 137 get_remember_key 138 set_remember_cookie 139 set_session_value(remember_deadline_extended_session_key, Time.now.to_i) if extend_remember_deadline? 140 end
# File lib/rodauth/features/remember.rb 95 def remembered_session_id 96 return unless cookie = _get_remember_cookie 97 id, key = cookie.split('_', 2) 98 return unless id && key 99 100 actual, deadline = active_remember_key_ds(id).get([remember_key_column, remember_deadline_column]) 101 return unless actual 102 103 if hmac_secret && !(valid = timing_safe_eql?(key, compute_hmac(actual))) 104 if hmac_secret_rotation? && (valid = timing_safe_eql?(key, compute_old_hmac(actual))) 105 _set_remember_cookie(id, actual, deadline) 106 elsif !(raw_remember_token_deadline && raw_remember_token_deadline > convert_timestamp(deadline)) 107 return 108 end 109 end 110 111 unless valid || timing_safe_eql?(key, actual) 112 return 113 end 114 115 id 116 end
# File lib/rodauth/features/active_sessions.rb 94 def remove_active_session(session_id) 95 active_sessions_ds.where(active_sessions_session_id_column=>session_id).delete 96 end
# File lib/rodauth/features/active_sessions.rb 98 def remove_all_active_sessions 99 active_sessions_ds.delete 100 end
# File lib/rodauth/features/active_sessions.rb 106 def remove_all_active_sessions_except_current 107 if session_id = session[session_id_session_key] 108 remove_all_active_sessions_except_for(session_id) 109 else 110 remove_all_active_sessions 111 end 112 end
# File lib/rodauth/features/active_sessions.rb 102 def remove_all_active_sessions_except_for(session_id) 103 active_sessions_ds.exclude(active_sessions_session_id_column=>compute_hmacs(session_id)).delete 104 end
# File lib/rodauth/features/webauthn.rb 381 def remove_all_webauthn_keys_and_user_ids 382 webauthn_user_ids_ds.delete 383 webauthn_keys_ds.delete 384 end
# File lib/rodauth/features/active_sessions.rb 88 def remove_current_session 89 if session_id = session[session_id_session_key] 90 remove_active_session(compute_hmacs(session_id)) 91 end 92 end
# File lib/rodauth/features/email_auth.rb 138 def remove_email_auth_key 139 email_auth_ds.delete 140 end
# File lib/rodauth/features/active_sessions.rb 114 def remove_inactive_sessions 115 if cond = inactive_session_cond 116 active_sessions_ds.where(cond).delete 117 end 118 end
# File lib/rodauth/features/jwt_refresh.rb 195 def remove_jwt_refresh_token_key(token) 196 account_id, token_id, _ = _account_refresh_token_split(token) 197 jwt_refresh_token_account_token_ds(account_id, token_id).delete 198 end
# File lib/rodauth/features/lockout.rb 292 def remove_lockout_metadata 293 account_login_failures_ds.delete 294 account_lockouts_ds.delete 295 end
# File lib/rodauth/features/remember.rb 174 def remove_remember_key(id=account_id) 175 remember_key_ds(id).delete 176 end
# File lib/rodauth/features/reset_password.rb 179 def remove_reset_password_key 180 password_reset_ds.delete 181 end
# File lib/rodauth/features/base.rb 1047 def remove_session_value(key) 1048 session.delete(key) 1049 end
# File lib/rodauth/features/verify_account.rb 169 def remove_verify_account_key 170 verify_account_ds.delete 171 end
# File lib/rodauth/features/verify_login_change.rb 112 def remove_verify_login_change_key 113 verify_login_change_ds.delete 114 end
# File lib/rodauth/features/webauthn.rb 377 def remove_webauthn_key(webauthn_id) 378 webauthn_keys_ds.where(webauthn_keys_webauthn_id_column=>webauthn_id).delete == 1 379 end
# File lib/rodauth/features/base.rb 470 def render(page) 471 _view(:render, page) 472 end
# File lib/rodauth/features/login.rb 148 def render_multi_phase_login_forms 149 multi_phase_login_forms.sort.map{|_, form, _| form}.join("\n") 150 end
# File lib/rodauth/features/base.rb 189 def request 190 scope.request 191 end
# File lib/rodauth/features/base.rb 415 def require_account 416 require_authentication 417 require_account_session 418 end
# File lib/rodauth/features/base.rb 772 def require_account_session 773 unless account_from_session 774 clear_session 775 login_required 776 end 777 end
# File lib/rodauth/features/base.rb 411 def require_authentication 412 require_login 413 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 29 def require_http_basic_auth 30 unless http_basic_auth 31 set_http_basic_auth_error_response 32 return_response 33 end 34 end
# File lib/rodauth/features/base.rb 403 def require_login 404 login_required unless logged_in? 405 end
# File lib/rodauth/features/verify_account.rb 161 def require_login_confirmation? 162 false 163 end
# File lib/rodauth/features/login.rb 152 def require_login_redirect 153 login_path 154 end
# File lib/rodauth/features/otp.rb 241 def require_otp_setup 242 unless otp_exists? 243 set_redirect_error_status(two_factor_not_setup_error_status) 244 set_error_reason :two_factor_not_setup 245 set_redirect_error_flash two_factor_not_setup_error_flash 246 redirect two_factor_need_setup_redirect 247 end 248 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_error_reason :password_authentication_required 57 set_redirect_error_flash password_authentication_required_error_flash 58 set_session_return_to_path(confirm_password_redirect_session_key) 59 redirect password_authentication_required_redirect 60 end 61 end
# File lib/rodauth/features/confirm_password.rb 87 def require_password_authentication? 88 return true if defined?(super) && super 89 !authenticated_by.include?('password') 90 end
# File lib/rodauth/features/base.rb 1038 def require_response(meth) 1039 send(meth) 1040 raise ConfigurationError, "#{meth.to_s.sub(/\A_/, '')} overridden without returning a response (should use redirect or request.halt)." 1041 end
# File lib/rodauth/features/sms_codes.rb 341 def require_sms_available 342 require_sms_setup 343 344 if sms_locked_out? 345 set_redirect_error_status(lockout_error_status) 346 set_error_reason :sms_locked_out 347 set_redirect_error_flash sms_lockout_error_flash 348 redirect sms_lockout_redirect 349 end 350 end
# File lib/rodauth/features/sms_codes.rb 332 def require_sms_not_setup 333 if sms_setup? 334 set_redirect_error_status(sms_already_setup_error_status) 335 set_error_reason :sms_already_setup 336 set_redirect_error_flash sms_already_setup_error_flash 337 redirect sms_already_setup_redirect 338 end 339 end
# File lib/rodauth/features/sms_codes.rb 323 def require_sms_setup 324 unless sms_setup? 325 set_redirect_error_status(two_factor_not_setup_error_status) 326 set_error_reason :sms_not_setup 327 set_redirect_error_flash sms_not_setup_error_flash 328 redirect sms_needs_setup_redirect 329 end 330 end
# File lib/rodauth/features/two_factor_base.rb 158 def require_two_factor_authenticated 159 unless two_factor_authenticated? 160 if two_factor_auth_return_to_requested_location? 161 set_session_return_to_path(two_factor_auth_redirect_session_key) 162 end 163 set_redirect_error_status(two_factor_need_authentication_error_status) 164 set_error_reason :two_factor_need_authentication 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 149 def require_two_factor_not_authenticated(auth_type = nil) 150 if two_factor_authenticated? || (auth_type && two_factor_login_type_match?(auth_type)) 151 set_redirect_error_status(two_factor_already_authenticated_error_status) 152 set_error_reason :two_factor_already_authenticated 153 set_redirect_error_flash two_factor_already_authenticated_error_flash 154 redirect two_factor_already_authenticated_redirect 155 end 156 end
# File lib/rodauth/features/two_factor_base.rb 137 def require_two_factor_setup 138 # Avoid database query if already authenticated via 2nd factor 139 return if two_factor_authenticated? 140 141 return if uses_two_factor_authentication? 142 143 set_redirect_error_status(two_factor_not_setup_error_status) 144 set_error_reason :two_factor_not_setup 145 set_redirect_error_flash two_factor_not_setup_error_flash 146 redirect two_factor_need_setup_redirect 147 end
# File lib/rodauth/features/webauthn.rb 390 def require_webauthn_setup 391 unless webauthn_setup? 392 set_redirect_error_status(webauthn_not_setup_error_status) 393 set_error_reason :webauthn_not_setup 394 set_redirect_error_flash webauthn_not_setup_error_flash 395 redirect two_factor_need_setup_redirect 396 end 397 end
# File lib/rodauth/features/jwt.rb 131 def rescue_jwt_payload(_) 132 @jwt_payload = false 133 end
# File lib/rodauth/features/reset_password.rb 264 def reset_password_account_status_value 265 account_open_status_value 266 end
# File lib/rodauth/features/reset_password.rb 187 def reset_password_email_link 188 token_link(reset_password_route, reset_password_key_param, reset_password_key_value) 189 end
# File lib/rodauth/features/reset_password.rb 214 def reset_password_email_recently_sent? 215 (email_last_sent = get_reset_password_email_last_sent) && (Time.now - email_last_sent < reset_password_skip_resend_email_within) 216 end
# File lib/rodauth/features/reset_password.rb 250 def reset_password_key_insert_hash 251 hash = {reset_password_id_column=>account_id, reset_password_key_column=>reset_password_key_value} 252 set_deadline_value(hash, reset_password_deadline_column, reset_password_deadline_interval) 253 hash 254 end
# File lib/rodauth/features/reset_password.rb 175 def reset_password_request_for_unverified_account 176 throw_error_reason(:unverified_account, unopen_account_error_status, login_param, unverified_account_message) 177 end
# File lib/rodauth/features/single_session.rb 24 def reset_single_session_key 25 if logged_in? 26 single_session_ds.update(single_session_key_column=>random_key) 27 end 28 end
# File lib/rodauth/features/base.rb 193 def response 194 scope.response 195 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 960 def retry_on_uniqueness_violation(&block) 961 if raises_uniqueness_violation?(&block) 962 yield 963 end 964 end
# File lib/rodauth/features/json.rb 214 def return_json_response 215 _return_json_response 216 end
# File lib/rodauth/features/base.rb 734 def return_response(body=nil) 735 response.write(body) if body 736 request.halt 737 end
# File lib/rodauth/features/base.rb 205 def route! 206 if meth = self.class.route_hash[request.remaining_path] 207 send(meth) 208 end 209 210 nil 211 end
# File lib/rodauth/features/base.rb 739 def route_path(route, opts=OPTS) 740 path = "#{prefix}/#{route}" 741 path += "?#{Rack::Utils.build_nested_query(opts)}" unless opts.empty? 742 path 743 end
# File lib/rodauth/features/base.rb 745 def route_url(route, opts=OPTS) 746 "#{base_url}#{route_path(route, opts)}" 747 end
# File lib/rodauth/features/create_account.rb 101 def save_account 102 id = nil 103 raised = raises_uniqueness_violation?{id = db[accounts_table].insert(account)} 104 105 if raised 106 set_login_requirement_error_message(:already_an_account_with_this_login, already_an_account_with_this_login_message) 107 end 108 109 if id 110 account[account_id_column] ||= id 111 end 112 113 id && !raised 114 end
# File lib/rodauth/features/email_base.rb 87 def select_key_for_update! 88 @key_for_update = true 89 end
# File lib/rodauth/features/email_base.rb 43 def send_email(email) 44 email.deliver! 45 end
# File lib/rodauth/features/verify_login_change.rb 128 def send_verify_login_change_email(login) 129 send_email(create_verify_login_change_email(login)) 130 end
# File lib/rodauth/features/audit_logging.rb 56 def serialize_audit_log_metadata(metadata) 57 metadata.to_json unless metadata.nil? 58 end
# File lib/rodauth/features/base.rb 197 def session 198 scope.session 199 end
# File lib/rodauth/features/active_sessions.rb 213 def session_inactivity_deadline_condition 214 if deadline = session_inactivity_deadline 215 Sequel[active_sessions_last_use_column] < Sequel.date_sub(Sequel::CURRENT_TIMESTAMP, seconds: deadline) 216 end 217 end
# File lib/rodauth/features/jwt.rb 76 def session_jwt 77 JWT.encode(jwt_session_hash, jwt_secret, jwt_algorithm) 78 end
# File lib/rodauth/features/active_sessions.rb 219 def session_lifetime_deadline_condition 220 if deadline = session_lifetime_deadline 221 Sequel[active_sessions_created_at_column] < Sequel.date_sub(Sequel::CURRENT_TIMESTAMP, seconds: deadline) 222 end 223 end
# File lib/rodauth/features/email_base.rb 68 def session_param(session_key, param_name) 69 unless value = session[session_key] 70 if allow_param_fallback_for_session_param? 71 value = param(param_name) 72 end 73 end 74 75 value 76 end
# File lib/rodauth/features/base.rb 312 def session_value 313 session[session_key] 314 end
# File lib/rodauth/features/base.rb 685 def set_account(account, retrieval_type) 686 account_reload(@account_retrieval_type, retrieval_type) if @account_retrieval_type 687 @account_retrieval_type = retrieval_type 688 @account = account 689 end
This is needed on MySQL, which doesn’t support non constant defaults other than CURRENT_TIMESTAMP.
# File lib/rodauth/features/base.rb 996 def set_deadline_value(hash, column, interval) 997 if set_deadline_values? 998 # :nocov: 999 hash[column] = Sequel.date_add(Sequel::CURRENT_TIMESTAMP, interval) 1000 # :nocov: 1001 end 1002 end
# File lib/rodauth/features/base.rb 822 def set_deadline_values? 823 db.database_type == :mysql 824 end
# File lib/rodauth/features/email_auth.rb 126 def set_email_auth_email_last_sent 127 email_auth_ds.update(email_auth_email_last_sent_column=>Sequel::CURRENT_TIMESTAMP) if email_auth_email_last_sent_column 128 end
# File lib/rodauth/features/base.rb 387 def set_error_flash(message) 388 flash.now[flash_error_key] = message 389 end
# File lib/rodauth/features/base.rb 810 def set_error_reason(reason) 811 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 213 def set_field_error(field, error) 214 (@field_errors ||= {})[field] = error 215 end
# File lib/rodauth/features/http_basic_auth.rb 79 def set_http_basic_auth_error_response 80 response.status = 401 81 set_response_header("www-authenticate", "Basic realm=\"#{http_basic_auth_realm}\"") 82 end
# File lib/rodauth/features/jwt.rb 158 def set_jwt 159 set_jwt_token(session_jwt) 160 end
# File lib/rodauth/features/jwt_refresh.rb 211 def set_jwt_refresh_token_hmac_session_key(token) 212 if allow_refresh_with_expired_jwt_access_token? 213 key = _account_refresh_token_split(token).last 214 data = random_key 215 set_session_value(jwt_refresh_token_data_session_key, data) 216 set_session_value(jwt_refresh_token_hmac_session_key, compute_hmac(data + key)) 217 end 218 end
# File lib/rodauth/features/jwt.rb 88 def set_jwt_token(token) 89 set_response_header('authorization', token) 90 end
# File lib/rodauth/features/password_grace_period.rb 53 def set_last_password_entry 54 set_session_value(last_password_entry_session_key, Time.now.to_i) 55 end
# File lib/rodauth/features/login_password_requirements_base.rb 153 def set_login_requirement_error_message(reason, message) 154 set_error_reason(reason) 155 @login_requirement_message = message 156 end
# File lib/rodauth/features/create_account.rb 92 def set_new_account_password(password) 93 account[account_password_hash_column] = password_hash(password) 94 end
# File lib/rodauth/features/base.rb 395 def set_notice_flash(message) 396 flash[flash_notice_key] = message 397 end
# File lib/rodauth/features/base.rb 399 def set_notice_now_flash(message) 400 flash.now[flash_notice_key] = message 401 end
# File lib/rodauth/features/disallow_password_reuse.rb 21 def set_password(password) 22 hash = super 23 add_previous_password_hash(hash) 24 hash 25 end
# File lib/rodauth/features/login_password_requirements_base.rb 132 def set_password_requirement_error_message(reason, message) 133 set_error_reason(reason) 134 @password_requirement_message = message 135 end
# File lib/rodauth/features/base.rb 391 def set_redirect_error_flash(message) 392 flash[flash_error_key] = message 393 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 784 def set_redirect_error_status(status) 785 end
# File lib/rodauth/features/remember.rb 200 def set_remember_cookie 201 _set_remember_cookie(account_id, remember_key_value, active_remember_key_ds.get(remember_deadline_column)) 202 end
# File lib/rodauth/features/reset_password.rb 202 def set_reset_password_email_last_sent 203 password_reset_ds.update(reset_password_email_last_sent_column=>Sequel::CURRENT_TIMESTAMP) if reset_password_email_last_sent_column 204 end
# File lib/rodauth/features/base.rb 791 def set_response_error_reason_status(reason, status) 792 set_error_reason(reason) 793 set_response_error_status(status) 794 end
# File lib/rodauth/features/base.rb 787 def set_response_error_status(status) 788 response.status = status 789 end
# File lib/rodauth/features/base.rb 619 def set_response_header(key, value) 620 response.headers[key] = value 621 end
# File lib/rodauth/features/base.rb 1020 def set_session_return_to_path(session_key, path=request.fullpath) 1021 if request.get? && valid_return_to_path?(path) 1022 set_session_value(session_key, path) 1023 end 1024 end
# File lib/rodauth/features/base.rb 1043 def set_session_value(key, value) 1044 session[key] = value 1045 end
# File lib/rodauth/features/single_session.rb 103 def set_single_session_key(data) 104 data = compute_hmac(data) if hmac_secret 105 set_session_value(single_session_session_key, data) 106 end
# File lib/rodauth/features/base.rb 381 def set_title(title) 382 if title_instance_variable 383 scope.instance_variable_set(title_instance_variable, title) 384 end 385 end
# File lib/rodauth/features/lockout.rb 242 def set_unlock_account_email_last_sent 243 account_lockouts_ds.update(account_lockouts_email_last_sent_column=>Sequel::CURRENT_TIMESTAMP) if account_lockouts_email_last_sent_column 244 end
# File lib/rodauth/features/verify_account.rb 228 def set_verify_account_email_last_sent 229 verify_account_ds.update(verify_account_email_last_sent_column=>Sequel::CURRENT_TIMESTAMP) if verify_account_email_last_sent_column 230 end
# File lib/rodauth/features/verify_account.rb 240 def setup_account_verification 241 generate_verify_account_key_value 242 create_verify_account_key 243 send_verify_account_email 244 end
# File lib/rodauth/features/lockout.rb 297 def show_lockout_page 298 set_response_error_reason_status(:account_locked_out, lockout_error_status) 299 set_error_flash login_lockout_error_flash 300 return_response unlock_account_request_view 301 end
# File lib/rodauth/features/otp.rb 465 def show_otp_auth_link? 466 otp_available? 467 end
# File lib/rodauth/features/single_session.rb 108 def single_session_ds(id=session_value) 109 db[single_session_table]. 110 where(single_session_id_column=>id) 111 end
# File lib/rodauth/features/login.rb 126 def skip_login_field_on_login? 127 return false unless use_multi_phase_login? 128 valid_login_entered? 129 end
# File lib/rodauth/features/login.rb 131 def skip_password_field_on_login? 132 return false unless use_multi_phase_login? 133 !valid_login_entered? 134 end
# File lib/rodauth/features/close_account.rb 85 def skip_status_checks? 86 false 87 end
# File lib/rodauth/features/sms_codes.rb 528 def sms 529 case @sms 530 when nil 531 (@sms = sms_ds.first || false) || nil 532 when false 533 nil 534 else 535 @sms 536 end 537 end
# File lib/rodauth/features/sms_codes.rb 403 def sms_auth_message(code) 404 "SMS authentication code for #{domain} is #{code}" 405 end
# File lib/rodauth/features/sms_codes.rb 456 def sms_available? 457 sms_setup? && !sms_locked_out? 458 end
# File lib/rodauth/features/sms_codes.rb 435 def sms_code 436 sms[sms_code_column] 437 end
# File lib/rodauth/features/sms_codes.rb 439 def sms_code_issued_at 440 convert_timestamp(sms[sms_issued_at_column]) 441 end
# File lib/rodauth/features/sms_codes.rb 352 def sms_code_match?(code) 353 return false unless sms_current_auth? 354 timing_safe_eql?(code, sms_code) 355 end
# File lib/rodauth/features/sms_codes.rb 504 def sms_codes_primary? 505 (features & [:otp, :webauthn]).empty? 506 end
# File lib/rodauth/features/recovery_codes.rb 148 def sms_confirm 149 super if defined?(super) 150 auto_add_missing_recovery_codes 151 end
# File lib/rodauth/features/sms_codes.rb 366 def sms_confirm_failure 367 sms_ds.delete 368 end
# File lib/rodauth/features/sms_codes.rb 407 def sms_confirm_message(code) 408 "SMS confirmation code for #{domain} is #{code}" 409 end
# File lib/rodauth/features/sms_codes.rb 357 def sms_confirmation_match?(code) 358 sms_needs_confirmation? && sms_code_match?(code) 359 end
# File lib/rodauth/features/sms_codes.rb 464 def sms_current_auth? 465 sms_code && sms_code_issued_at + sms_code_allowed_seconds > Time.now 466 end
# File lib/rodauth/features/sms_codes.rb 361 def sms_disable 362 sms_ds.delete 363 @sms = false 364 end
# File lib/rodauth/features/sms_codes.rb 539 def sms_ds 540 db[sms_codes_table].where(sms_id_column=>session_value) 541 end
# File lib/rodauth/features/sms_codes.rb 443 def sms_failures 444 sms[sms_failures_column] 445 end
# File lib/rodauth/features/sms_codes.rb 460 def sms_locked_out? 461 sms_failures >= sms_failure_limit 462 end
# File lib/rodauth/features/sms_codes.rb 452 def sms_needs_confirmation? 453 sms && sms_failures.nil? 454 end
# File lib/rodauth/features/sms_codes.rb 411 def sms_needs_confirmation_notice_flash 412 sms_needs_confirmation_error_flash 413 end
# File lib/rodauth/features/sms_codes.rb 512 def sms_new_auth_code 513 SecureRandom.random_number(10**sms_auth_code_length).to_s.rjust(sms_auth_code_length, "0") 514 end
# File lib/rodauth/features/sms_codes.rb 516 def sms_new_confirm_code 517 SecureRandom.random_number(10**sms_confirm_code_length).to_s.rjust(sms_confirm_code_length, "0") 518 end
# File lib/rodauth/features/sms_codes.rb 508 def sms_normalize_phone(phone) 509 phone.to_s.gsub(/\D+/, '') 510 end
# File lib/rodauth/features/sms_codes.rb 431 def sms_phone 432 sms[sms_phone_column] 433 end
# File lib/rodauth/features/sms_codes.rb 426 def sms_record_failure 427 update_sms(sms_failures_column=>Sequel.expr(sms_failures_column)+1) 428 sms[sms_failures_column] = sms_ds.get(sms_failures_column) 429 end
# File lib/rodauth/features/sms_codes.rb 419 def sms_remove_expired_confirm_code 420 db[sms_codes_table]. 421 where(sms_id_column=>session_value, sms_failures_column => nil). 422 where(Sequel[sms_issued_at_column] < Sequel.date_sub(Sequel::CURRENT_TIMESTAMP, seconds: sms_confirm_deadline)). 423 delete 424 end
# File lib/rodauth/features/sms_codes.rb 377 def sms_remove_failures 378 return if sms_needs_confirmation? 379 update_hash_ds(sms, sms_ds.exclude(sms_failures_column => nil), sms_failures_column => 0, sms_code_column => nil) 380 end
# File lib/rodauth/features/sms_codes.rb 520 def sms_send(phone, message) 521 raise ConfigurationError, "sms_send needs to be defined in the Rodauth configuration for SMS sending to work" 522 end
# File lib/rodauth/features/sms_codes.rb 387 def sms_send_auth_code 388 code = sms_new_auth_code 389 sms_set_code(code) 390 sms_send(sms_phone, sms_auth_message(code)) 391 end
# File lib/rodauth/features/sms_codes.rb 393 def sms_send_confirm_code 394 code = sms_new_confirm_code 395 sms_set_code(code) 396 sms_send(sms_phone, sms_confirm_message(code)) 397 end
# File lib/rodauth/features/sms_codes.rb 415 def sms_set_code(code) 416 update_sms(sms_code_column=>code, sms_issued_at_column=>Sequel::CURRENT_TIMESTAMP) 417 end
# File lib/rodauth/features/sms_codes.rb 370 def sms_setup(phone_number) 371 # Cannot handle uniqueness violation here, as the phone number given may not match the 372 # one in the table. 373 sms_ds.insert(sms_id_column=>session_value, sms_phone_column=>phone_number, sms_failures_column => nil) 374 @sms = nil 375 end
# File lib/rodauth/features/sms_codes.rb 447 def sms_setup? 448 return false unless sms 449 !sms_needs_confirmation? 450 end
# File lib/rodauth/features/sms_codes.rb 399 def sms_valid_phone?(phone) 400 phone.length >= sms_phone_min_length 401 end
# File lib/rodauth/features/base.rb 707 def split_token(token) 708 token.split(token_separator, 2) 709 end
# File lib/rodauth/features/base.rb 925 def template_path(page) 926 File.join(File.dirname(__FILE__), '../../../templates', "#{page}.str") 927 end
# File lib/rodauth/features/http_basic_auth.rb 84 def throw_basic_auth_error(*args) 85 set_http_basic_auth_error_response 86 throw_error(*args) 87 end
# File lib/rodauth/features/base.rb 800 def throw_error(field, error) 801 set_field_error(field, error) 802 throw_rodauth_error 803 end
# File lib/rodauth/features/base.rb 813 def throw_error_reason(reason, status, field, message) 814 set_error_reason(reason) 815 throw_error_status(status, field, message) 816 end
# File lib/rodauth/features/base.rb 805 def throw_error_status(status, field, error) 806 set_response_error_status(status) 807 throw_error(field, error) 808 end
# File lib/rodauth/features/base.rb 796 def throw_rodauth_error 797 throw :rodauth_error 798 end
# File lib/rodauth/features/base.rb 767 def timing_safe_eql?(provided, actual) 768 provided = provided.to_s 769 Rack::Utils.secure_compare(provided.ljust(actual.length), actual) && provided.length == actual.length 770 end
# File lib/rodauth/features/email_base.rb 60 def token_link(route, param, key) 61 route_url(route, param => token_param_value(key)) 62 end
# File lib/rodauth/features/email_base.rb 64 def token_param_value(key) 65 "#{account_id}#{token_separator}#{convert_email_token_key(key)}" 66 end
# File lib/rodauth/features/base.rb 749 def transaction(opts=OPTS, &block) 750 opts = opts.empty? ? transaction_opts : transaction_opts.merge(opts) 751 db.transaction(opts, &block) 752 end
# File lib/rodauth/features/base.rb 280 def translate(_key, default) 281 # do not attempt to translate by default 282 default 283 end
# File lib/rodauth/features/two_factor_base.rb 208 def two_factor_auth_links 209 @two_factor_auth_links ||= _filter_links(_two_factor_auth_links) 210 end
# File lib/rodauth/features/two_factor_base.rb 243 def two_factor_authenticate(type) 244 two_factor_update_session(type) 245 two_factor_remove_auth_failures 246 after_two_factor_authentication 247 require_response(:_two_factor_auth_response) 248 end
# File lib/rodauth/features/two_factor_base.rb 186 def two_factor_authenticated? 187 authenticated_by && authenticated_by.length >= 2 188 end
# File lib/rodauth/features/two_factor_base.rb 190 def two_factor_authentication_setup? 191 possible_authentication_methods.length >= 2 192 end
# File lib/rodauth/features/two_factor_base.rb 200 def two_factor_login_type_match?(type) 201 authenticated_by && authenticated_by.include?(type) 202 end
# File lib/rodauth/features/two_factor_base.rb 124 def two_factor_modifications_require_password? 125 modifications_require_password? 126 end
# File lib/rodauth/features/two_factor_base.rb 182 def two_factor_partially_authenticated? 183 logged_in? && !two_factor_authenticated? && uses_two_factor_authentication? 184 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 231 def two_factor_remove 232 super 233 otp_remove 234 end
# File lib/rodauth/features/otp.rb 236 def two_factor_remove_auth_failures 237 super 238 otp_remove_auth_failures 239 end
# File lib/rodauth/features/two_factor_base.rb 216 def two_factor_remove_links 217 @two_factor_remove_links ||= _filter_links(_two_factor_remove_links) 218 end
# File lib/rodauth/features/two_factor_base.rb 256 def two_factor_remove_session(type) 257 authenticated_by.delete(type) 258 remove_session_value(two_factor_setup_session_key) 259 if authenticated_by.empty? 260 clear_session 261 end 262 end
# File lib/rodauth/features/two_factor_base.rb 212 def two_factor_setup_links 213 @two_factor_setup_links ||= _filter_links(_two_factor_setup_links) 214 end
# File lib/rodauth/features/two_factor_base.rb 264 def two_factor_update_session(auth_type) 265 raise Error, "attempt to have two factor authentication using same factor" if authenticated_by.include?(auth_type) 266 authenticated_by << auth_type 267 set_session_value(two_factor_setup_session_key, true) 268 end
Work around jdbc/sqlite issue where it only raises ConstraintViolation and not UniqueConstraintViolation.
# File lib/rodauth/features/base.rb 978 def unique_constraint_violation_class 979 if db.adapter_scheme == :jdbc && db.database_type == :sqlite 980 # :nocov: 981 Sequel::ConstraintViolation 982 # :nocov: 983 else 984 Sequel::UniqueConstraintViolation 985 end 986 end
# File lib/rodauth/features/lockout.rb 165 def unlock_account 166 transaction do 167 remove_lockout_metadata 168 end 169 end
# File lib/rodauth/features/lockout.rb 230 def unlock_account_email_link 231 token_link(unlock_account_route, unlock_account_key_param, unlock_account_key_value) 232 end
# File lib/rodauth/features/lockout.rb 246 def unlock_account_email_recently_sent? 247 (email_last_sent = get_unlock_account_email_last_sent) && (Time.now - email_last_sent < unlock_account_skip_resend_email_within) 248 end
# File lib/rodauth/features/lockout.rb 257 def unlock_account_key 258 @unlock_account_key_value 259 end
# File lib/rodauth/features/lockout.rb 261 def unlock_account_key_value 262 # RODAUTH3: call unlock_account_key directly 263 unlock_account_key 264 end
# File lib/rodauth/features/verify_account_grace_period.rb 92 def unverified_grace_period_expired? 93 return false unless expires_at = session[unverified_account_session_key] 94 expires_at.is_a?(Integer) && Time.now.to_i > expires_at 95 end
# File lib/rodauth/features/base.rb 1061 def update_account(values, ds=account_ds) 1062 update_hash_ds(account, ds, values) 1063 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/active_sessions.rb 232 def update_current_session? 233 !!session_inactivity_deadline 234 end
# File lib/rodauth/features/base.rb 1051 def update_hash_ds(hash, ds, values) 1052 num = ds.update(values) 1053 if num == 1 1054 values.each do |k, v| 1055 hash[k] = Sequel::CURRENT_TIMESTAMP == v ? Time.now : v 1056 end 1057 end 1058 num 1059 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 79 def update_login(login) 80 _update_login(login) 81 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 24 def update_password_hash? 25 password_hash_cost != @current_password_hash_cost || @update_password_hash 26 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 70 def update_single_session_key 71 key = random_key 72 set_single_session_key(key) 73 if single_session_ds.update(single_session_key_column=>key) == 0 74 # Don't handle uniqueness violations here. While we could get the stored key from the 75 # database, it could lead to two sessions sharing the same key, which this feature is 76 # designed to prevent. 77 single_session_ds.insert(single_session_id_column=>session_value, single_session_key_column=>key) 78 end 79 end
# File lib/rodauth/features/sms_codes.rb 524 def update_sms(values) 525 update_hash_ds(sms, sms_ds, values) 526 end
# File lib/rodauth/features/base.rb 826 def use_database_authentication_functions? 827 case db.database_type 828 when :postgres, :mysql, :mssql 829 true 830 else 831 # :nocov: 832 false 833 # :nocov: 834 end 835 end
# File lib/rodauth/features/active_sessions.rb 241 def use_date_arithmetic? 242 true 243 end
# File lib/rodauth/features/json.rb 64 def use_json? 65 json_request? || only_json? 66 end
# File lib/rodauth/features/email_auth.rb 167 def use_multi_phase_login? 168 true 169 end
# File lib/rodauth/features/base.rb 837 def use_request_specific_csrf_tokens? 838 scope.opts[:rodauth_route_csrf] && scope.use_request_specific_csrf_tokens? 839 end
# File lib/rodauth/features/base.rb 1034 def use_scope_clear_session? 1035 scope.respond_to?(:clear_session) 1036 end
# File lib/rodauth/features/base.rb 159 def uses_instance_variables(*ivs) 160 auth.define_singleton_method(:instance_variables_used) do 161 super() + ivs 162 end 163 end
# File lib/rodauth/features/two_factor_base.rb 194 def uses_two_factor_authentication? 195 return false unless logged_in? 196 set_session_value(two_factor_setup_session_key, two_factor_authentication_setup?) unless session.has_key?(two_factor_setup_session_key) 197 session[two_factor_setup_session_key] 198 end
# File lib/rodauth/features/jwt.rb 100 def valid_jwt? 101 !!(jwt_token && jwt_payload) 102 end
# File lib/rodauth/features/login.rb 136 def valid_login_entered? 137 @valid_login_entered 138 end
# File lib/rodauth/features/webauthn.rb 314 def valid_new_webauthn_credential?(webauthn_credential) 315 _override_webauthn_credential_response_verify(webauthn_credential) 316 (challenge = param_or_nil(webauthn_setup_challenge_param)) && 317 (hmac = param_or_nil(webauthn_setup_challenge_hmac_param)) && 318 (timing_safe_eql?(compute_hmac(challenge), hmac) || (hmac_secret_rotation? && timing_safe_eql?(compute_old_hmac(challenge), hmac))) && 319 webauthn_credential.verify(challenge) 320 end
# File lib/rodauth/features/base.rb 1014 def valid_return_to_path?(path) 1015 path[0] == "/" && 1016 path[1] != "/" && 1017 path.bytesize <= return_to_path_max_size 1018 end
# File lib/rodauth/features/webauthn.rb 362 def valid_webauthn_credential_auth?(webauthn_credential) 363 ds = webauthn_keys_ds.where(webauthn_keys_webauthn_id_column => webauthn_credential.id) 364 pub_key, sign_count = ds.get([webauthn_keys_public_key_column, webauthn_keys_sign_count_column]) 365 366 _override_webauthn_credential_response_verify(webauthn_credential) 367 (challenge = param_or_nil(webauthn_auth_challenge_param)) && 368 (hmac = param_or_nil(webauthn_auth_challenge_hmac_param)) && 369 (timing_safe_eql?(compute_hmac(challenge), hmac) || (hmac_secret_rotation? && timing_safe_eql?(compute_old_hmac(challenge), hmac))) && 370 webauthn_credential.verify(challenge, public_key: pub_key, sign_count: sign_count) && 371 ds.update( 372 webauthn_keys_sign_count_column => Integer(webauthn_credential.sign_count), 373 webauthn_keys_last_use_column => Sequel::CURRENT_TIMESTAMP 374 ) == 1 375 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 173 def verify_account 174 ds = account_ds.where(account_status_column=>account_unverified_status_value) 175 update_account({account_status_column=>account_open_status_value}, ds) == 1 176 end
# File lib/rodauth/features/verify_account.rb 290 def verify_account_check_already_logged_in 291 check_already_logged_in 292 end
# File lib/rodauth/features/verify_account.rb 315 def verify_account_ds(id=account_id) 316 db[verify_account_table].where(verify_account_id_column=>id) 317 end
# File lib/rodauth/features/verify_account.rb 207 def verify_account_email_link 208 token_link(verify_account_route, verify_account_key_param, verify_account_key_value) 209 end
# File lib/rodauth/features/verify_account.rb 246 def verify_account_email_recently_sent? 247 account && (email_last_sent = get_verify_account_email_last_sent) && (Time.now - email_last_sent < verify_account_skip_resend_email_within) 248 end
# File lib/rodauth/features/verify_account.rb 178 def verify_account_email_resend 179 if @verify_account_key_value = get_verify_account_key(account_id) 180 set_verify_account_email_last_sent 181 send_verify_account_email 182 true 183 end 184 end
# File lib/rodauth/features/verify_account.rb 311 def verify_account_key_insert_hash 312 {verify_account_id_column=>account_id, verify_account_key_column=>verify_account_key_value} 313 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 9 def verify_account_view 10 webauthn_setup_view 11 end
# File lib/rodauth/features/verify_login_change.rb 116 def verify_login_change 117 unless res = _update_login(verify_login_change_new_login) 118 remove_verify_login_change_key 119 end 120 121 res 122 end
# File lib/rodauth/features/verify_login_change.rb 223 def verify_login_change_account_status_value 224 account_open_status_value 225 end
# File lib/rodauth/features/verify_login_change.rb 212 def verify_login_change_ds(id=account_id) 213 db[verify_login_change_table].where(verify_login_change_id_column=>id) 214 end
# File lib/rodauth/features/verify_login_change.rb 208 def verify_login_change_email_body 209 render('verify-login-change-email') 210 end
# File lib/rodauth/features/verify_login_change.rb 132 def verify_login_change_email_link 133 token_link(verify_login_change_route, verify_login_change_key_param, verify_login_change_key_value) 134 end
# File lib/rodauth/features/verify_login_change.rb 198 def verify_login_change_key_insert_hash(login) 199 hash = {verify_login_change_id_column=>account_id, verify_login_change_key_column=>verify_login_change_key_value, verify_login_change_login_column=>login} 200 set_deadline_value(hash, verify_login_change_deadline_column, verify_login_change_deadline_interval) 201 hash 202 end
# File lib/rodauth/features/verify_login_change.rb 146 def verify_login_change_old_login 147 account_ds.get(login_column) 148 end
# File lib/rodauth/features/base.rb 465 def view(page, title) 466 set_title(title) 467 _view(:view, page) 468 end
# File lib/rodauth/features/webauthn.rb 508 def webauthn_account_id 509 account_id_or_session_value 510 end
# File lib/rodauth/features/webauthn.rb 340 def webauthn_allow 341 account_webauthn_ids 342 end
# File lib/rodauth/features/webauthn_login.rb 45 def webauthn_auth_additional_form_tags 46 if @webauthn_login 47 super.to_s + login_hidden_field 48 else 49 super 50 end 51 end
# File lib/rodauth/features/webauthn.rb 520 def webauthn_auth_credential_from_form_submission 521 begin 522 webauthn_credential = webauthn_form_submission_call(:from_get, webauthn_auth_data) 523 524 unless valid_webauthn_credential_auth?(webauthn_credential) 525 throw_error_reason(:invalid_webauthn_auth_param, invalid_key_error_status, webauthn_auth_param, webauthn_invalid_auth_param_message) 526 end 527 rescue WebAuthn::SignCountVerificationError 528 handle_webauthn_sign_count_verification_error 529 rescue WebAuthn::Error, RuntimeError, NoMethodError 530 throw_error_reason(:invalid_webauthn_auth_param, invalid_field_error_status, webauthn_auth_param, webauthn_invalid_auth_param_message) 531 end 532 533 webauthn_credential 534 end
# File lib/rodauth/features/webauthn.rb 536 def webauthn_auth_data 537 case auth_data = raw_param(webauthn_auth_param) 538 when String 539 begin 540 JSON.parse(auth_data) 541 rescue 542 throw_error_reason(:invalid_webauthn_auth_param, invalid_field_error_status, webauthn_auth_param, webauthn_invalid_auth_param_message) 543 end 544 when Hash 545 auth_data 546 else 547 throw_error_reason(:invalid_webauthn_auth_param, invalid_field_error_status, webauthn_auth_param, webauthn_invalid_auth_param_message) 548 end 549 end
# File lib/rodauth/features/webauthn.rb 247 def webauthn_auth_form_path 248 webauthn_auth_path 249 end
# File lib/rodauth/features/webauthn.rb 263 def webauthn_authenticator_selection 264 {'requireResidentKey' => false, 'userVerification' => webauthn_user_verification} 265 end
# File lib/rodauth/features/webauthn.rb 434 def webauthn_create_relying_party_opts 435 { :relying_party => webauthn_relying_party } 436 end
# File lib/rodauth/features/webauthn.rb 322 def webauthn_credential_options_for_get 323 WebAuthn::Credential.options_for_get( 324 :allow => webauthn_allow, 325 :timeout => webauthn_auth_timeout, 326 :user_verification => webauthn_user_verification, 327 :extensions => webauthn_extensions, 328 **webauthn_get_relying_party_opts 329 ) 330 end
# File lib/rodauth/features/webauthn.rb 267 def webauthn_extensions 268 {} 269 end
# File lib/rodauth/features/webauthn.rb 439 def webauthn_form_submission_call(meth, arg) 440 WebAuthn::Credential.public_send(meth, arg, :relying_party => webauthn_relying_party) 441 end
# File lib/rodauth/features/webauthn.rb 499 def webauthn_key_insert_hash(webauthn_credential) 500 { 501 webauthn_keys_account_id_column => webauthn_account_id, 502 webauthn_keys_webauthn_id_column => webauthn_credential.id, 503 webauthn_keys_public_key_column => webauthn_credential.public_key, 504 webauthn_keys_sign_count_column => Integer(webauthn_credential.sign_count) 505 } 506 end
# File lib/rodauth/features/webauthn.rb 516 def webauthn_keys_ds 517 db[webauthn_keys_table].where(webauthn_keys_account_id_column => webauthn_account_id) 518 end
# File lib/rodauth/features/webauthn_autofill.rb 60 def webauthn_login_options? 61 return true unless param_or_nil(login_param) 62 super 63 end
# File lib/rodauth/features/webauthn_login.rb 72 def webauthn_login_verification_factor?(webauthn_credential) 73 webauthn_login_user_verification_additional_factor? && 74 webauthn_credential.response.authenticator_data.user_verified? && 75 uses_two_factor_authentication? 76 end
# File lib/rodauth/features/webauthn.rb 472 def webauthn_modification_authenticated? 473 two_factor_login_type_match?('webauthn') && 474 (!uses_two_factor_authentication? || two_factor_modifications_require_password?) 475 end
# File lib/rodauth/features/webauthn.rb 336 def webauthn_origin 337 base_url 338 end
# File lib/rodauth/features/webauthn.rb 414 def webauthn_relying_party 415 # No need to memoize, only called once per request 416 WebAuthn::RelyingParty.new( 417 allowed_origins: [webauthn_origin], 418 id: webauthn_rp_id, 419 name: webauthn_rp_name, 420 ) 421 end
# File lib/rodauth/features/webauthn.rb 255 def webauthn_remove_authenticated_session 256 remove_session_value(authenticated_webauthn_id_session_key) 257 end
# File lib/rodauth/features/webauthn.rb 344 def webauthn_rp_id 345 webauthn_origin.sub(/\Ahttps?:\/\//, '').sub(/:\d+\z/, '') 346 end
# File lib/rodauth/features/webauthn.rb 348 def webauthn_rp_name 349 webauthn_rp_id 350 end
# File lib/rodauth/features/webauthn.rb 386 def webauthn_setup? 387 !webauthn_keys_ds.empty? 388 end
# File lib/rodauth/features/webauthn.rb 551 def webauthn_setup_credential_from_form_submission 552 unless two_factor_password_match?(param(password_param)) 553 throw_error_reason(:invalid_password, invalid_password_error_status, password_param, invalid_password_message) 554 end 555 556 begin 557 webauthn_credential = webauthn_form_submission_call(:from_create, webauthn_setup_data) 558 559 unless valid_new_webauthn_credential?(webauthn_credential) 560 throw_error_reason(:invalid_webauthn_setup_param, invalid_field_error_status, webauthn_setup_param, webauthn_invalid_setup_param_message) 561 end 562 rescue WebAuthn::Error, RuntimeError, NoMethodError 563 throw_error_reason(:invalid_webauthn_setup_param, invalid_field_error_status, webauthn_setup_param, webauthn_invalid_setup_param_message) 564 end 565 566 webauthn_credential 567 end
# File lib/rodauth/features/webauthn.rb 569 def webauthn_setup_data 570 case setup_data = raw_param(webauthn_setup_param) 571 when String 572 begin 573 JSON.parse(setup_data) 574 rescue 575 throw_error_reason(:invalid_webauthn_setup_param, invalid_field_error_status, webauthn_setup_param, webauthn_invalid_setup_param_message) 576 end 577 when Hash 578 setup_data 579 else 580 throw_error_reason(:invalid_webauthn_setup_param, invalid_field_error_status, webauthn_setup_param, webauthn_invalid_setup_param_message) 581 end 582 end
# File lib/rodauth/features/webauthn.rb 259 def webauthn_update_session(webauthn_id) 260 set_session_value(authenticated_webauthn_id_session_key, webauthn_id) 261 end
# File lib/rodauth/features/webauthn.rb 512 def webauthn_user_ids_ds 513 db[webauthn_user_ids_table].where(webauthn_user_ids_account_id_column => webauthn_account_id) 514 end
# File lib/rodauth/features/webauthn.rb 332 def webauthn_user_name 333 account![login_column] 334 end
# File lib/rodauth/features/webauthn_autofill.rb 25 def webauthn_user_verification 26 'preferred' 27 end