rodauth 2.11.0 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG +28 -0
- data/README.rdoc +29 -7
- data/doc/active_sessions.rdoc +4 -0
- data/doc/base.rdoc +1 -0
- data/doc/error_reasons.rdoc +73 -0
- data/doc/internal_request.rdoc +463 -0
- data/doc/path_class_methods.rdoc +10 -0
- data/doc/release_notes/2.11.0.txt +1 -1
- data/doc/release_notes/2.12.0.txt +17 -0
- data/doc/release_notes/2.13.0.txt +19 -0
- data/doc/release_notes/2.14.0.txt +17 -0
- data/doc/release_notes/2.15.0.txt +48 -0
- data/doc/remember.rdoc +1 -0
- data/lib/rodauth.rb +9 -2
- data/lib/rodauth/features/active_sessions.rb +29 -8
- data/lib/rodauth/features/base.rb +26 -1
- data/lib/rodauth/features/change_login.rb +6 -4
- data/lib/rodauth/features/change_password.rb +5 -3
- data/lib/rodauth/features/close_account.rb +3 -1
- data/lib/rodauth/features/confirm_password.rb +2 -2
- data/lib/rodauth/features/create_account.rb +6 -4
- data/lib/rodauth/features/disallow_common_passwords.rb +1 -1
- data/lib/rodauth/features/disallow_password_reuse.rb +1 -1
- data/lib/rodauth/features/email_auth.rb +6 -0
- data/lib/rodauth/features/internal_request.rb +367 -0
- data/lib/rodauth/features/jwt_refresh.rb +1 -1
- data/lib/rodauth/features/lockout.rb +15 -4
- data/lib/rodauth/features/login.rb +6 -3
- data/lib/rodauth/features/login_password_requirements_base.rb +15 -6
- data/lib/rodauth/features/otp.rb +13 -6
- data/lib/rodauth/features/password_complexity.rb +4 -4
- data/lib/rodauth/features/path_class_methods.rb +22 -0
- data/lib/rodauth/features/recovery_codes.rb +6 -2
- data/lib/rodauth/features/remember.rb +25 -10
- data/lib/rodauth/features/reset_password.rb +8 -4
- data/lib/rodauth/features/session_expiration.rb +1 -0
- data/lib/rodauth/features/single_session.rb +1 -0
- data/lib/rodauth/features/sms_codes.rb +17 -5
- data/lib/rodauth/features/two_factor_base.rb +6 -1
- data/lib/rodauth/features/verify_account.rb +8 -1
- data/lib/rodauth/features/verify_account_grace_period.rb +1 -1
- data/lib/rodauth/features/verify_login_change.rb +5 -2
- data/lib/rodauth/features/webauthn.rb +15 -14
- data/lib/rodauth/features/webauthn_login.rb +1 -1
- data/lib/rodauth/version.rb +1 -1
- data/templates/button.str +1 -1
- data/templates/change-password.str +2 -2
- data/templates/global-logout-field.str +1 -1
- data/templates/login-confirm-field.str +2 -2
- data/templates/login-display.str +2 -2
- data/templates/login-field.str +2 -2
- data/templates/otp-auth-code-field.str +2 -2
- data/templates/otp-setup.str +2 -2
- data/templates/password-confirm-field.str +2 -2
- data/templates/password-field.str +2 -2
- data/templates/recovery-auth.str +2 -2
- data/templates/remember.str +1 -1
- data/templates/sms-code-field.str +2 -2
- data/templates/sms-setup.str +2 -2
- data/templates/unlock-account-email.str +1 -1
- data/templates/webauthn-remove.str +1 -1
- metadata +19 -3
| @@ -27,6 +27,8 @@ module Rodauth | |
| 27 27 | 
             
                  :new_account
         | 
| 28 28 | 
             
                )
         | 
| 29 29 |  | 
| 30 | 
            +
                internal_request_method
         | 
| 31 | 
            +
             | 
| 30 32 | 
             
                route do |r|
         | 
| 31 33 | 
             
                  check_already_logged_in
         | 
| 32 34 | 
             
                  before_create_account_route
         | 
| @@ -43,7 +45,7 @@ module Rodauth | |
| 43 45 |  | 
| 44 46 | 
             
                    catch_error do
         | 
| 45 47 | 
             
                      if require_login_confirmation? && login != param(login_confirm_param)
         | 
| 46 | 
            -
                         | 
| 48 | 
            +
                        throw_error_reason(:logins_do_not_match, unmatched_field_error_status, login_param, logins_do_not_match_message)
         | 
| 47 49 | 
             
                      end
         | 
| 48 50 |  | 
| 49 51 | 
             
                      unless login_meets_requirements?(login)
         | 
| @@ -52,11 +54,11 @@ module Rodauth | |
| 52 54 |  | 
| 53 55 | 
             
                      if create_account_set_password?
         | 
| 54 56 | 
             
                        if require_password_confirmation? && password != param(password_confirm_param)
         | 
| 55 | 
            -
                           | 
| 57 | 
            +
                          throw_error_reason(:passwords_do_not_match, unmatched_field_error_status, password_param, passwords_do_not_match_message)
         | 
| 56 58 | 
             
                        end
         | 
| 57 59 |  | 
| 58 60 | 
             
                        unless password_meets_requirements?(password)
         | 
| 59 | 
            -
                           | 
| 61 | 
            +
                          throw_error_reason(:password_does_not_meet_requirements, invalid_field_error_status, password_param, password_does_not_meet_requirements_message)
         | 
| 60 62 | 
             
                        end
         | 
| 61 63 |  | 
| 62 64 | 
             
                        if account_password_hash_column
         | 
| @@ -100,7 +102,7 @@ module Rodauth | |
| 100 102 | 
             
                  raised = raises_uniqueness_violation?{id = db[accounts_table].insert(account)}
         | 
| 101 103 |  | 
| 102 104 | 
             
                  if raised
         | 
| 103 | 
            -
                     | 
| 105 | 
            +
                    set_login_requirement_error_message(:already_an_account_with_this_login, already_an_account_with_this_login_message)
         | 
| 104 106 | 
             
                  end
         | 
| 105 107 |  | 
| 106 108 | 
             
                  if id
         | 
| @@ -32,7 +32,7 @@ module Rodauth | |
| 32 32 |  | 
| 33 33 | 
             
                def password_not_one_of_the_most_common?(password)
         | 
| 34 34 | 
             
                  return true unless password_one_of_most_common?(password)
         | 
| 35 | 
            -
                   | 
| 35 | 
            +
                  set_password_requirement_error_message(:password_is_one_of_the_most_common, password_is_one_of_the_most_common_message)
         | 
| 36 36 | 
             
                  false
         | 
| 37 37 | 
             
                end
         | 
| 38 38 | 
             
              end
         | 
| @@ -65,7 +65,7 @@ module Rodauth | |
| 65 65 | 
             
                  end
         | 
| 66 66 |  | 
| 67 67 | 
             
                  return true unless match
         | 
| 68 | 
            -
                   | 
| 68 | 
            +
                  set_password_requirement_error_message(:password_same_as_previous_password, password_same_as_previous_password_message)
         | 
| 69 69 | 
             
                  false
         | 
| 70 70 | 
             
                end
         | 
| 71 71 |  | 
| @@ -49,6 +49,10 @@ module Rodauth | |
| 49 49 |  | 
| 50 50 | 
             
                auth_private_methods :account_from_email_auth_key
         | 
| 51 51 |  | 
| 52 | 
            +
                internal_request_method
         | 
| 53 | 
            +
                internal_request_method :email_auth_request
         | 
| 54 | 
            +
                internal_request_method :valid_email_auth?
         | 
| 55 | 
            +
             | 
| 52 56 | 
             
                route(:email_auth_request) do |r|
         | 
| 53 57 | 
             
                  check_already_logged_in
         | 
| 54 58 | 
             
                  before_email_auth_request_route
         | 
| @@ -58,6 +62,7 @@ module Rodauth | |
| 58 62 | 
             
                      _email_auth_request
         | 
| 59 63 | 
             
                    else
         | 
| 60 64 | 
             
                      set_redirect_error_status(no_matching_login_error_status)
         | 
| 65 | 
            +
                      set_error_reason :no_matching_login
         | 
| 61 66 | 
             
                      set_redirect_error_flash email_auth_request_error_flash
         | 
| 62 67 | 
             
                    end
         | 
| 63 68 |  | 
| @@ -90,6 +95,7 @@ module Rodauth | |
| 90 95 | 
             
                    key = session[email_auth_session_key] || param(email_auth_key_param)
         | 
| 91 96 | 
             
                    unless account_from_email_auth_key(key)
         | 
| 92 97 | 
             
                      set_redirect_error_status(invalid_key_error_status)
         | 
| 98 | 
            +
                      set_error_reason :invalid_email_auth_key
         | 
| 93 99 | 
             
                      set_redirect_error_flash email_auth_error_flash
         | 
| 94 100 | 
             
                      redirect email_auth_email_sent_redirect
         | 
| 95 101 | 
             
                    end
         | 
| @@ -0,0 +1,367 @@ | |
| 1 | 
            +
            # frozen-string-literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'stringio'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Rodauth
         | 
| 6 | 
            +
              INVALID_DOMAIN = "invalidurl @@.com"
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              class InternalRequestError < StandardError
         | 
| 9 | 
            +
                attr_accessor :flash
         | 
| 10 | 
            +
                attr_accessor :reason
         | 
| 11 | 
            +
                attr_accessor :field_errors
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def initialize(attrs)
         | 
| 14 | 
            +
                  return super if attrs.is_a?(String)
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  @flash = attrs[:flash]
         | 
| 17 | 
            +
                  @reason = attrs[:reason]
         | 
| 18 | 
            +
                  @field_errors = attrs[:field_errors] || {}
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  super(build_message)
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                private
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def build_message
         | 
| 26 | 
            +
                  extras = []
         | 
| 27 | 
            +
                  extras << reason if reason
         | 
| 28 | 
            +
                  extras << field_errors unless field_errors.empty?
         | 
| 29 | 
            +
                  extras = (" (#{extras.join(", ")})" unless extras.empty?)
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  "#{flash}#{extras}"
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              module InternalRequestMethods
         | 
| 36 | 
            +
                attr_accessor :session
         | 
| 37 | 
            +
                attr_accessor :params
         | 
| 38 | 
            +
                attr_reader :flash
         | 
| 39 | 
            +
                attr_accessor :internal_request_block
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def domain
         | 
| 42 | 
            +
                  d = super
         | 
| 43 | 
            +
                  if d == INVALID_DOMAIN
         | 
| 44 | 
            +
                    raise InternalRequestError, "must set domain in configuration, as it cannot be determined from internal request"
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                  d
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def raw_param(k)
         | 
| 50 | 
            +
                  @params[k]
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                def set_error_flash(message)
         | 
| 54 | 
            +
                  @flash = message
         | 
| 55 | 
            +
                  _handle_internal_request_error
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
                alias set_redirect_error_flash set_error_flash
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                def set_notice_flash(message)
         | 
| 60 | 
            +
                  @flash = message
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
                alias set_notice_now_flash set_notice_flash
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                def modifications_require_password?
         | 
| 65 | 
            +
                  false
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
                alias require_login_confirmation? modifications_require_password?
         | 
| 68 | 
            +
                alias require_password_confirmation? modifications_require_password?
         | 
| 69 | 
            +
                alias change_login_requires_password? modifications_require_password?
         | 
| 70 | 
            +
                alias change_password_requires_password? modifications_require_password?
         | 
| 71 | 
            +
                alias close_account_requires_password? modifications_require_password?
         | 
| 72 | 
            +
                alias two_factor_modifications_require_password? modifications_require_password?
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                def otp_setup_view
         | 
| 75 | 
            +
                  hash = {:otp_setup=>otp_user_key}
         | 
| 76 | 
            +
                  hash[:otp_setup_raw] = otp_key if hmac_secret
         | 
| 77 | 
            +
                  _return_from_internal_request(hash)
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                def add_recovery_codes_view
         | 
| 81 | 
            +
                  _return_from_internal_request(recovery_codes)
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                def handle_internal_request(meth)
         | 
| 85 | 
            +
                  catch(:halt) do
         | 
| 86 | 
            +
                    _around_rodauth do
         | 
| 87 | 
            +
                      before_rodauth
         | 
| 88 | 
            +
                      send(meth, request)
         | 
| 89 | 
            +
                    end
         | 
| 90 | 
            +
                  end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                  @internal_request_return_value
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                private
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                def internal_request?
         | 
| 98 | 
            +
                  true
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                def set_error_reason(reason)
         | 
| 102 | 
            +
                  @error_reason = reason
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                def after_login
         | 
| 106 | 
            +
                  super
         | 
| 107 | 
            +
                  _set_internal_request_return_value(account_id) unless @return_false_on_error
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                def after_remember
         | 
| 111 | 
            +
                  super
         | 
| 112 | 
            +
                  if params[remember_param] == remember_remember_param_value
         | 
| 113 | 
            +
                    _set_internal_request_return_value("#{account_id}_#{convert_token_key(remember_key_value)}")
         | 
| 114 | 
            +
                  end
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                def after_load_memory
         | 
| 118 | 
            +
                  super
         | 
| 119 | 
            +
                  _return_from_internal_request(session_value)
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                def before_change_password_route
         | 
| 123 | 
            +
                  super
         | 
| 124 | 
            +
                  params[new_password_param] ||= params[password_param]
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                def before_email_auth_request_route
         | 
| 128 | 
            +
                  super
         | 
| 129 | 
            +
                  _set_login_param_from_account
         | 
| 130 | 
            +
                end
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                def before_login_route
         | 
| 133 | 
            +
                  super
         | 
| 134 | 
            +
                  _set_login_param_from_account
         | 
| 135 | 
            +
                end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                def before_unlock_account_request_route
         | 
| 138 | 
            +
                  super
         | 
| 139 | 
            +
                  _set_login_param_from_account
         | 
| 140 | 
            +
                end
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                def before_reset_password_request_route
         | 
| 143 | 
            +
                  super
         | 
| 144 | 
            +
                  _set_login_param_from_account
         | 
| 145 | 
            +
                end
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                def before_verify_account_resend_route
         | 
| 148 | 
            +
                  super
         | 
| 149 | 
            +
                  _set_login_param_from_account
         | 
| 150 | 
            +
                end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                def account_from_key(token, status_id=nil)
         | 
| 153 | 
            +
                  return super unless session_value
         | 
| 154 | 
            +
                  return unless yield session_value
         | 
| 155 | 
            +
                  ds = account_ds(session_value)
         | 
| 156 | 
            +
                  ds = ds.where(account_status_column=>status_id) if status_id && !skip_status_checks?
         | 
| 157 | 
            +
                  ds.first
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                def _set_internal_request_return_value(value)
         | 
| 161 | 
            +
                  @internal_request_return_value = value
         | 
| 162 | 
            +
                end
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                def _return_from_internal_request(value)
         | 
| 165 | 
            +
                  _set_internal_request_return_value(value)
         | 
| 166 | 
            +
                  throw(:halt)
         | 
| 167 | 
            +
                end
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                def _handle_internal_request_error
         | 
| 170 | 
            +
                  if @return_false_on_error
         | 
| 171 | 
            +
                    _return_from_internal_request(false)
         | 
| 172 | 
            +
                  else
         | 
| 173 | 
            +
                    raise InternalRequestError.new(flash: @flash, reason: @error_reason, field_errors: @field_errors)
         | 
| 174 | 
            +
                  end
         | 
| 175 | 
            +
                end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                def _return_false_on_error!
         | 
| 178 | 
            +
                  @return_false_on_error = true
         | 
| 179 | 
            +
                end
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                def _set_login_param_from_account
         | 
| 182 | 
            +
                  if session_value && !params[login_param] && (account = account_ds(session_value).first)
         | 
| 183 | 
            +
                    params[login_param] = account[login_column]
         | 
| 184 | 
            +
                  end
         | 
| 185 | 
            +
                end
         | 
| 186 | 
            +
             | 
| 187 | 
            +
                def _get_remember_cookie
         | 
| 188 | 
            +
                  params[remember_param]
         | 
| 189 | 
            +
                end
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                def _handle_internal_request_eval(_)
         | 
| 192 | 
            +
                  v = instance_eval(&internal_request_block)
         | 
| 193 | 
            +
                  _set_internal_request_return_value(v) unless defined?(@internal_request_return_value)
         | 
| 194 | 
            +
                end
         | 
| 195 | 
            +
             | 
| 196 | 
            +
                def _handle_account_id_for_login(_)
         | 
| 197 | 
            +
                  raise InternalRequestError, "no login provided" unless login = param_or_nil(login_param)
         | 
| 198 | 
            +
                  raise InternalRequestError, "no account for login" unless account = account_from_login(login)
         | 
| 199 | 
            +
                  _return_from_internal_request(account[account_id_column])
         | 
| 200 | 
            +
                end
         | 
| 201 | 
            +
             | 
| 202 | 
            +
                def _handle_account_exists?(_)
         | 
| 203 | 
            +
                  raise InternalRequestError, "no login provided" unless login = param_or_nil(login_param)
         | 
| 204 | 
            +
                  _return_from_internal_request(!!account_from_login(login))
         | 
| 205 | 
            +
                end
         | 
| 206 | 
            +
             | 
| 207 | 
            +
                def _handle_lock_account(_)
         | 
| 208 | 
            +
                  raised_uniqueness_violation{account_lockouts_ds(session_value).insert(_setup_account_lockouts_hash(session_value, generate_unlock_account_key))}
         | 
| 209 | 
            +
                end
         | 
| 210 | 
            +
             | 
| 211 | 
            +
                def _handle_remember_setup(request)
         | 
| 212 | 
            +
                  params[remember_param] = remember_remember_param_value
         | 
| 213 | 
            +
                  _handle_remember(request)
         | 
| 214 | 
            +
                end
         | 
| 215 | 
            +
             | 
| 216 | 
            +
                def _handle_remember_disable(request)
         | 
| 217 | 
            +
                  params[remember_param] = remember_disable_param_value
         | 
| 218 | 
            +
                  _handle_remember(request)
         | 
| 219 | 
            +
                end
         | 
| 220 | 
            +
             | 
| 221 | 
            +
                def _handle_account_id_for_remember_key(request)
         | 
| 222 | 
            +
                  load_memory
         | 
| 223 | 
            +
                  raise InternalRequestError, "invalid remember key"
         | 
| 224 | 
            +
                end
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                def _handle_otp_setup_params(request)
         | 
| 227 | 
            +
                  request.env['REQUEST_METHOD'] = 'GET'
         | 
| 228 | 
            +
                  _handle_otp_setup(request)
         | 
| 229 | 
            +
                end
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                def _predicate_internal_request(meth, request)
         | 
| 232 | 
            +
                  _return_false_on_error!
         | 
| 233 | 
            +
                  _set_internal_request_return_value(true)
         | 
| 234 | 
            +
                  send(meth, request)
         | 
| 235 | 
            +
                end
         | 
| 236 | 
            +
             | 
| 237 | 
            +
                def _handle_valid_login_and_password?(request)
         | 
| 238 | 
            +
                  _predicate_internal_request(:_handle_login, request)
         | 
| 239 | 
            +
                end
         | 
| 240 | 
            +
             | 
| 241 | 
            +
                def _handle_valid_email_auth?(request)
         | 
| 242 | 
            +
                  _predicate_internal_request(:_handle_email_auth, request)
         | 
| 243 | 
            +
                end
         | 
| 244 | 
            +
             | 
| 245 | 
            +
                def _handle_valid_otp_auth?(request)
         | 
| 246 | 
            +
                  _predicate_internal_request(:_handle_otp_auth, request)
         | 
| 247 | 
            +
                end
         | 
| 248 | 
            +
             | 
| 249 | 
            +
                def _handle_valid_recovery_auth?(request)
         | 
| 250 | 
            +
                  _predicate_internal_request(:_handle_recovery_auth, request)
         | 
| 251 | 
            +
                end
         | 
| 252 | 
            +
             | 
| 253 | 
            +
                def _handle_valid_sms_auth?(request)
         | 
| 254 | 
            +
                  _predicate_internal_request(:_handle_sms_auth, request)
         | 
| 255 | 
            +
                end
         | 
| 256 | 
            +
              end
         | 
| 257 | 
            +
             | 
| 258 | 
            +
              module InternalRequestClassMethods
         | 
| 259 | 
            +
                def internal_request(route, opts={}, &block)
         | 
| 260 | 
            +
                  opts = opts.dup
         | 
| 261 | 
            +
                  
         | 
| 262 | 
            +
                  env = {
         | 
| 263 | 
            +
                     'REQUEST_METHOD'=>'POST',
         | 
| 264 | 
            +
                     'PATH_INFO'=>'/',
         | 
| 265 | 
            +
                     "SCRIPT_NAME" => "",
         | 
| 266 | 
            +
                     "HTTP_HOST" => INVALID_DOMAIN,
         | 
| 267 | 
            +
                     "SERVER_NAME" => INVALID_DOMAIN,
         | 
| 268 | 
            +
                     "SERVER_PORT" => 443,
         | 
| 269 | 
            +
                     "CONTENT_TYPE" => "application/x-www-form-urlencoded",
         | 
| 270 | 
            +
                     "rack.input"=>StringIO.new(''),
         | 
| 271 | 
            +
                     "rack.url_scheme"=>"https"
         | 
| 272 | 
            +
                  }
         | 
| 273 | 
            +
                  env.merge!(opts.delete(:env)) if opts[:env]
         | 
| 274 | 
            +
             | 
| 275 | 
            +
                  session = {}
         | 
| 276 | 
            +
                  session.merge!(opts.delete(:session)) if opts[:session]
         | 
| 277 | 
            +
             | 
| 278 | 
            +
                  params = {}
         | 
| 279 | 
            +
                  params.merge!(opts.delete(:params)) if opts[:params]
         | 
| 280 | 
            +
             | 
| 281 | 
            +
                  scope = roda_class.new(env)
         | 
| 282 | 
            +
                  rodauth = new(scope)
         | 
| 283 | 
            +
                  rodauth.session = session
         | 
| 284 | 
            +
                  rodauth.params = params
         | 
| 285 | 
            +
                  rodauth.internal_request_block = block
         | 
| 286 | 
            +
             | 
| 287 | 
            +
                  unless account_id = opts.delete(:account_id)
         | 
| 288 | 
            +
                    if (account_login = opts.delete(:account_login))
         | 
| 289 | 
            +
                      if (account = rodauth.send(:_account_from_login, account_login))
         | 
| 290 | 
            +
                        account_id = account[rodauth.account_id_column]
         | 
| 291 | 
            +
                      else
         | 
| 292 | 
            +
                        raise InternalRequestError, "no account for login: #{account_login.inspect}"
         | 
| 293 | 
            +
                      end
         | 
| 294 | 
            +
                    end
         | 
| 295 | 
            +
                  end
         | 
| 296 | 
            +
             | 
| 297 | 
            +
                  if account_id
         | 
| 298 | 
            +
                    session[rodauth.session_key] = account_id
         | 
| 299 | 
            +
                    unless authenticated_by = opts.delete(:authenticated_by)
         | 
| 300 | 
            +
                      authenticated_by = case route
         | 
| 301 | 
            +
                      when :otp_auth, :sms_request, :sms_auth, :recovery_auth, :valid_otp_auth?, :valid_sms_auth?, :valid_recovery_auth?
         | 
| 302 | 
            +
                        ['internal1']
         | 
| 303 | 
            +
                      else
         | 
| 304 | 
            +
                        ['internal1', 'internal2']
         | 
| 305 | 
            +
                      end
         | 
| 306 | 
            +
                    end
         | 
| 307 | 
            +
                    session[rodauth.authenticated_by_session_key] = authenticated_by
         | 
| 308 | 
            +
                  end
         | 
| 309 | 
            +
             | 
| 310 | 
            +
                  opts.keys.each do |k|
         | 
| 311 | 
            +
                    meth = :"#{k}_param"
         | 
| 312 | 
            +
                    params[rodauth.public_send(meth).to_s] = opts.delete(k) if rodauth.respond_to?(meth)
         | 
| 313 | 
            +
                  end
         | 
| 314 | 
            +
             | 
| 315 | 
            +
                  unless opts.empty?
         | 
| 316 | 
            +
                    warn "unhandled options passed to #{route}: #{opts.inspect}"
         | 
| 317 | 
            +
                  end
         | 
| 318 | 
            +
             | 
| 319 | 
            +
                  rodauth.handle_internal_request(:"_handle_#{route}")
         | 
| 320 | 
            +
                end
         | 
| 321 | 
            +
              end
         | 
| 322 | 
            +
             | 
| 323 | 
            +
              Feature.define(:internal_request, :InternalRequest) do
         | 
| 324 | 
            +
                configuration_module_eval do
         | 
| 325 | 
            +
                  def internal_request_configuration(&block)
         | 
| 326 | 
            +
                    @auth.instance_exec do
         | 
| 327 | 
            +
                      (@internal_request_configuration_blocks ||= []) << block
         | 
| 328 | 
            +
                    end
         | 
| 329 | 
            +
                  end
         | 
| 330 | 
            +
                end
         | 
| 331 | 
            +
             | 
| 332 | 
            +
                def post_configure
         | 
| 333 | 
            +
                  super
         | 
| 334 | 
            +
             | 
| 335 | 
            +
                  return if is_a?(InternalRequestMethods)
         | 
| 336 | 
            +
             | 
| 337 | 
            +
                  klass = self.class
         | 
| 338 | 
            +
                  internal_class = Class.new(klass) do
         | 
| 339 | 
            +
                    @roda_class = klass.roda_class
         | 
| 340 | 
            +
                    @features = klass.features.clone
         | 
| 341 | 
            +
                    @routes = klass.routes.clone
         | 
| 342 | 
            +
                    @route_hash = klass.route_hash.clone
         | 
| 343 | 
            +
                    @configuration = klass.configuration.clone
         | 
| 344 | 
            +
                    @configuration.instance_variable_set(:@auth, self)
         | 
| 345 | 
            +
                  end
         | 
| 346 | 
            +
             | 
| 347 | 
            +
                  if blocks = klass.instance_variable_get(:@internal_request_configuration_blocks)
         | 
| 348 | 
            +
                    configuration = internal_class.configuration
         | 
| 349 | 
            +
                    blocks.each do |block|
         | 
| 350 | 
            +
                      configuration.instance_exec(&block)
         | 
| 351 | 
            +
                    end
         | 
| 352 | 
            +
                  end
         | 
| 353 | 
            +
                  internal_class.send(:extend, InternalRequestClassMethods)
         | 
| 354 | 
            +
                  internal_class.send(:include, InternalRequestMethods)
         | 
| 355 | 
            +
                  internal_class.allocate.post_configure
         | 
| 356 | 
            +
             | 
| 357 | 
            +
                  ([:base] + internal_class.features).each do |feature_name|
         | 
| 358 | 
            +
                    feature = FEATURES[feature_name]
         | 
| 359 | 
            +
                    if meths = feature.internal_request_methods
         | 
| 360 | 
            +
                      meths.each do |name|
         | 
| 361 | 
            +
                        klass.define_singleton_method(name){|opts={}, &block| internal_class.internal_request(name, opts, &block)}
         | 
| 362 | 
            +
                      end
         | 
| 363 | 
            +
                    end
         | 
| 364 | 
            +
                  end
         | 
| 365 | 
            +
                end
         | 
| 366 | 
            +
              end
         | 
| 367 | 
            +
            end
         |