From fe5222be682c66a53bd0101d6a3946b6b67c6f95 Mon Sep 17 00:00:00 2001 From: Mikkel Malmberg Date: Fri, 26 Jan 2024 14:09:27 +0100 Subject: [PATCH 1/3] Evaluate callable redirects in context of controller --- app/controllers/passwordless/sessions_controller.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/controllers/passwordless/sessions_controller.rb b/app/controllers/passwordless/sessions_controller.rb index a7c7e41..4e97639 100644 --- a/app/controllers/passwordless/sessions_controller.rb +++ b/app/controllers/passwordless/sessions_controller.rb @@ -169,7 +169,11 @@ def authenticatable_class end def call_or_return(value) - value.respond_to?(:call) ? value.call : value + if value.respond_to?(:call) + instance_eval(&value) + else + value + end end def find_authenticatable From 165c8292bad228112c188f6c744b1da4a062d114 Mon Sep 17 00:00:00 2001 From: Mikkel Malmberg Date: Fri, 26 Jan 2024 14:16:01 +0100 Subject: [PATCH 2/3] Use instance_exec --- app/controllers/passwordless/sessions_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/passwordless/sessions_controller.rb b/app/controllers/passwordless/sessions_controller.rb index 4e97639..15783f9 100644 --- a/app/controllers/passwordless/sessions_controller.rb +++ b/app/controllers/passwordless/sessions_controller.rb @@ -170,7 +170,7 @@ def authenticatable_class def call_or_return(value) if value.respond_to?(:call) - instance_eval(&value) + instance_exec(&value) else value end From 12ca2ef19e6efd2b8084d6c1081c29ca77bd5db2 Mon Sep 17 00:00:00 2001 From: Mikkel Malmberg Date: Fri, 26 Jan 2024 14:33:23 +0100 Subject: [PATCH 3/3] Optionally pass authenticatable as argument --- .../passwordless/sessions_controller.rb | 21 ++++++++++++++----- .../passwordless/sessions_controller_test.rb | 16 +++++++++----- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/app/controllers/passwordless/sessions_controller.rb b/app/controllers/passwordless/sessions_controller.rb index 15783f9..0e4b680 100644 --- a/app/controllers/passwordless/sessions_controller.rb +++ b/app/controllers/passwordless/sessions_controller.rb @@ -119,8 +119,15 @@ def passwordless_query_redirect_path nil end - def passwordless_success_redirect_path - success_redirect_path = call_or_return(Passwordless.config.success_redirect_path) + def passwordless_success_redirect_path(authenticatable) + success_redirect_path = Passwordless.config.success_redirect_path + + if success_redirect_path.respond_to?(:call) + success_redirect_path = call_or_return( + success_redirect_path, + *[authenticatable].first(success_redirect_path.arity) + ) + end if Passwordless.config.redirect_back_after_sign_in session_redirect_url = reset_passwordless_redirect_location!(authenticatable_class) @@ -142,7 +149,11 @@ def artificially_slow_down_brute_force_attacks(token) def authenticate_and_sign_in(session, token) if session.authenticate(token) sign_in(session) - redirect_to(passwordless_success_redirect_path, status: :see_other, **redirect_to_options) + redirect_to( + passwordless_success_redirect_path(session.authenticatable), + status: :see_other, + **redirect_to_options + ) else flash[:error] = I18n.t("passwordless.sessions.errors.invalid_token") render(status: :forbidden, action: "show") @@ -168,9 +179,9 @@ def authenticatable_class authenticatable_type.constantize end - def call_or_return(value) + def call_or_return(value, *args) if value.respond_to?(:call) - instance_exec(&value) + instance_exec(*args, &value) else value end diff --git a/test/controllers/passwordless/sessions_controller_test.rb b/test/controllers/passwordless/sessions_controller_test.rb index 044670d..62cbb6e 100644 --- a/test/controllers/passwordless/sessions_controller_test.rb +++ b/test/controllers/passwordless/sessions_controller_test.rb @@ -145,20 +145,26 @@ class << User assert_equal pwless_session(User), Session.last!.id end - test("PATCH /:passwordless_for/sign_in/:id -> SUCCESS / callable success path") do + test("PATCH /:passwordless_for/sign_in/:id -> SUCCESS / callable success path with no args") do passwordless_session = create_pwless_session(token: "hi") with_config(success_redirect_path: lambda { "/" }) do patch("/users/sign_in/#{passwordless_session.identifier}", params: {passwordless: {token: "hi"}}) end - assert_equal 303, status - follow_redirect! - assert_equal 200, status assert_equal "/", path + end - assert_equal pwless_session(User), Session.last!.id + test("PATCH /:passwordless_for/sign_in/:id -> SUCCESS / callable success path with 1 arg") do + passwordless_session = create_pwless_session(token: "hi") + + with_config(success_redirect_path: lambda { |user| "/#{user.id}" }) do + patch("/users/sign_in/#{passwordless_session.identifier}", params: {passwordless: {token: "hi"}}) + end + + follow_redirect! + assert_equal "/#{passwordless_session.authenticatable.id}", path end test("PATCH /:passwordless_for/sign_in/:id -> ERROR") do