# frozen-string-literal: truerequire'stringio'moduleRodauthINVALID_DOMAIN="invalidurl @@.com"classInternalRequestError<StandardErrorattr_accessor:flashattr_accessor:reasonattr_accessor:field_errorsdefinitialize(attrs)returnsuperifattrs.is_a?(String)@flash=attrs[:flash]@reason=attrs[:reason]@field_errors=attrs[:field_errors]||{}super(build_message)endprivatedefbuild_messageextras=[]extras<<reasonifreasonextras<<field_errorsunlessfield_errors.empty?extras=(" (#{extras.join(", ")})"unlessextras.empty?)"#{flash}#{extras}"endendmoduleInternalRequestMethodsattr_accessor:sessionattr_accessor:paramsattr_reader:flashattr_accessor:internal_request_blockdefdomaind=superifd==INVALID_DOMAINraiseInternalRequestError,"must set domain in configuration, as it cannot be determined from internal request"enddenddefraw_param(k)@params[k]enddefset_error_flash(message)@flash=message_handle_internal_request_errorendaliasset_redirect_error_flashset_error_flashdefset_notice_flash(message)@flash=messageendaliasset_notice_now_flashset_notice_flashdefmodifications_require_password?falseendaliasrequire_login_confirmation?modifications_require_password?aliasrequire_password_confirmation?modifications_require_password?aliaschange_login_requires_password?modifications_require_password?aliaschange_password_requires_password?modifications_require_password?aliasclose_account_requires_password?modifications_require_password?aliastwo_factor_modifications_require_password?modifications_require_password?defotp_setup_viewhash={:otp_setup=>otp_user_key}hash[:otp_setup_raw]=otp_keyifhmac_secret_return_from_internal_request(hash)enddefadd_recovery_codes_view_return_from_internal_request(recovery_codes)enddefhandle_internal_request(meth)catch(:halt)do_around_rodauthdobefore_rodauthsend(meth,request)endend@internal_request_return_valueenddefonly_json?falseendprivatedefinternal_request?trueenddefset_error_reason(reason)@error_reason=reasonenddefafter_loginsuper_set_internal_request_return_value(account_id)unless@return_false_on_errorenddefafter_remembersuperifparams[remember_param]==remember_remember_param_value_set_internal_request_return_value("#{account_id}_#{convert_token_key(remember_key_value)}")endenddefafter_load_memorysuper_return_from_internal_request(session_value)enddefbefore_change_password_routesuperparams[new_password_param]||=params[password_param]enddefbefore_email_auth_request_routesuper_set_login_param_from_accountenddefbefore_login_routesuper_set_login_param_from_accountenddefbefore_unlock_account_request_routesuper_set_login_param_from_accountenddefbefore_reset_password_request_routesuper_set_login_param_from_accountenddefbefore_verify_account_resend_routesuper_set_login_param_from_accountenddefaccount_from_key(token,status_id=nil)returnsuperunlesssession_valuereturnunlessyieldsession_valueds=account_ds(session_value)ds=ds.where(account_status_column=>status_id)ifstatus_id&&!skip_status_checks?ds.firstenddef_set_internal_request_return_value(value)@internal_request_return_value=valueenddef_return_from_internal_request(value)_set_internal_request_return_value(value)throw(:halt)enddef_handle_internal_request_errorif@return_false_on_error_return_from_internal_request(false)elseraiseInternalRequestError.new(flash: @flash,reason: @error_reason,field_errors: @field_errors)endenddef_return_false_on_error!@return_false_on_error=trueenddef_set_login_param_from_accountifsession_value&&!params[login_param]&&(account=account_ds(session_value).first)params[login_param]=account[login_column]endenddef_get_remember_cookieparams[remember_param]enddef_handle_internal_request_eval(_)v=instance_eval(&internal_request_block)_set_internal_request_return_value(v)unlessdefined?(@internal_request_return_value)enddef_handle_account_id_for_login(_)raiseInternalRequestError,"no login provided"unlesslogin=param_or_nil(login_param)raiseInternalRequestError,"no account for login"unlessaccount=account_from_login(login)_return_from_internal_request(account[account_id_column])enddef_handle_account_exists?(_)raiseInternalRequestError,"no login provided"unlesslogin=param_or_nil(login_param)_return_from_internal_request(!!account_from_login(login))enddef_handle_lock_account(_)raised_uniqueness_violation{account_lockouts_ds(session_value).insert(_setup_account_lockouts_hash(session_value,generate_unlock_account_key))}enddef_handle_remember_setup(request)params[remember_param]=remember_remember_param_value_handle_remember(request)enddef_handle_remember_disable(request)params[remember_param]=remember_disable_param_value_handle_remember(request)enddef_handle_account_id_for_remember_key(request)load_memoryraiseInternalRequestError,"invalid remember key"enddef_handle_otp_setup_params(request)request.env['REQUEST_METHOD']='GET'_handle_otp_setup(request)enddef_predicate_internal_request(meth,request)_return_false_on_error!_set_internal_request_return_value(true)send(meth,request)enddef_handle_valid_login_and_password?(request)_predicate_internal_request(:_handle_login,request)enddef_handle_valid_email_auth?(request)_predicate_internal_request(:_handle_email_auth,request)enddef_handle_valid_otp_auth?(request)_predicate_internal_request(:_handle_otp_auth,request)enddef_handle_valid_recovery_auth?(request)_predicate_internal_request(:_handle_recovery_auth,request)enddef_handle_valid_sms_auth?(request)_predicate_internal_request(:_handle_sms_auth,request)endendmoduleInternalRequestClassMethodsdefinternal_request(route,opts={},&block)opts=opts.dupenv={'REQUEST_METHOD'=>'POST','PATH_INFO'=>'/',"SCRIPT_NAME"=>"","HTTP_HOST"=>INVALID_DOMAIN,"SERVER_NAME"=>INVALID_DOMAIN,"SERVER_PORT"=>443,"CONTENT_TYPE"=>"application/x-www-form-urlencoded","rack.input"=>StringIO.new(''),"rack.url_scheme"=>"https"}env.merge!(opts.delete(:env))ifopts[:env]session={}session.merge!(opts.delete(:session))ifopts[:session]params={}params.merge!(opts.delete(:params))ifopts[:params]scope=roda_class.new(env)rodauth=new(scope)rodauth.session=sessionrodauth.params=paramsrodauth.internal_request_block=blockunlessaccount_id=opts.delete(:account_id)if(account_login=opts.delete(:account_login))if(account=rodauth.send(:_account_from_login,account_login))account_id=account[rodauth.account_id_column]elseraiseInternalRequestError,"no account for login: #{account_login.inspect}"endendendifaccount_idsession[rodauth.session_key]=account_idunlessauthenticated_by=opts.delete(:authenticated_by)authenticated_by=caseroutewhen:otp_auth,:sms_request,:sms_auth,:recovery_auth,:valid_otp_auth?,:valid_sms_auth?,:valid_recovery_auth?['internal1']else['internal1','internal2']endendsession[rodauth.authenticated_by_session_key]=authenticated_byendopts.keys.eachdo|k|meth=:"#{k}_param"params[rodauth.public_send(meth).to_s]=opts.delete(k)ifrodauth.respond_to?(meth)endunlessopts.empty?warn"unhandled options passed to #{route}: #{opts.inspect}"endrodauth.handle_internal_request(:"_handle_#{route}")endendFeature.define(:internal_request,:InternalRequest)doconfiguration_module_evaldodefinternal_request_configuration(&block)@auth.instance_execdo(@internal_request_configuration_blocks||=[])<<blockendendenddefpost_configuresuperreturnifis_a?(InternalRequestMethods)klass=self.classinternal_class=Class.new(klass)ifblocks=klass.instance_variable_get(:@internal_request_configuration_blocks)configuration=internal_class.configurationblocks.eachdo|block|configuration.instance_exec(&block)endendinternal_class.send(:extend,InternalRequestClassMethods)internal_class.send(:include,InternalRequestMethods)internal_class.allocate.post_configure([:base]+internal_class.features).eachdo|feature_name|feature=FEATURES[feature_name]ifmeths=feature.internal_request_methodsmeths.eachdo|name|klass.define_singleton_method(name){|opts={},&block|internal_class.internal_request(name,opts,&block)}endendendklass.const_set(:InternalRequest,internal_class)klass.private_constant:InternalRequestendendend