From 6f442d46691beee4da19e2c99b6fbd7c1f821af4 Mon Sep 17 00:00:00 2001 From: Dakota Schramm Date: Fri, 3 May 2024 15:31:16 -0500 Subject: [PATCH 1/8] Add Unknown Address mailer to default mailers Currently, there is no configuration option to allow for sending an email when the resource is not found when the user opts into the "paranoid" option. With this addition, users will have a special email sent to them when their email is not found in the database --- app/controllers/passwordless/sessions_controller.rb | 6 +++--- app/mailers/passwordless/mailer.rb | 13 +++++++++++++ .../passwordless/mailer/unknown_address.text.erb | 1 + config/locales/en.yml | 10 ++++++++++ lib/passwordless/config.rb | 6 ++++++ .../passwordless/sessions_controller_test.rb | 2 +- 6 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 app/views/passwordless/mailer/unknown_address.text.erb diff --git a/app/controllers/passwordless/sessions_controller.rb b/app/controllers/passwordless/sessions_controller.rb index ce4face..725bf83 100644 --- a/app/controllers/passwordless/sessions_controller.rb +++ b/app/controllers/passwordless/sessions_controller.rb @@ -213,9 +213,9 @@ def handle_resource_not_found end def call_after_session_save - return if @skip_after_session_save_callback - - if Passwordless.config.after_session_save.arity == 2 + if @skip_after_session_save_callback + Passwordless.config.after_session_paranoid.call(@session, request) + elsif Passwordless.config.after_session_save.arity == 2 Passwordless.config.after_session_save.call(@session, request) else Passwordless.config.after_session_save.call(@session) diff --git a/app/mailers/passwordless/mailer.rb b/app/mailers/passwordless/mailer.rb index 8cace33..d4af857 100644 --- a/app/mailers/passwordless/mailer.rb +++ b/app/mailers/passwordless/mailer.rb @@ -29,5 +29,18 @@ def sign_in(session, token = nil, url_options = {}) subject: I18n.t("passwordless.mailer.sign_in.subject") ) end + + # sends an email when user attempts to login with unknown address + # + # @param session [Session] An instance of Passwordless::Session + def unknown_address(session) + email_field = session.authenticatable.class.passwordless_email_field + @email = session.authenticatable.send(email_field) + + mail( + to: @email, + subject: I18n.t("passwordless.mailer.unknown_address.subject") + ) + end end end diff --git a/app/views/passwordless/mailer/unknown_address.text.erb b/app/views/passwordless/mailer/unknown_address.text.erb new file mode 100644 index 0000000..85785f9 --- /dev/null +++ b/app/views/passwordless/mailer/unknown_address.text.erb @@ -0,0 +1 @@ +<%= t("passwordless.mailer.unknown_address.body", email: @email ) %> \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 091ee62..478a64b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -28,3 +28,13 @@ en: Alternatively you can use this link to sign in directly: %{magic_link} + unknown_address: + subject: "Not Registered" + body: |- + We noticed a login attempt using your email, %{email}. + + If you're seeing this email, that means that you don't currently have an + account associated with this email for Chuck. + Maybe you have a different account that's associated with your Chuck user? + + If this wasn't you, disregard this email. diff --git a/lib/passwordless/config.rb b/lib/passwordless/config.rb index e992e0c..4519f58 100644 --- a/lib/passwordless/config.rb +++ b/lib/passwordless/config.rb @@ -48,6 +48,12 @@ class Configuration Mailer.sign_in(session, session.token).deliver_now end ) + option( + :after_session_paranoid, + default: lambda do |session, _request| + Mailer.unknown_address(session).deliver_now + end + ) option :paranoid, default: false diff --git a/test/controllers/passwordless/sessions_controller_test.rb b/test/controllers/passwordless/sessions_controller_test.rb index b0ac305..3d74e41 100644 --- a/test/controllers/passwordless/sessions_controller_test.rb +++ b/test/controllers/passwordless/sessions_controller_test.rb @@ -98,9 +98,9 @@ class << User post("/users/sign_in", params: {passwordless: {email: "a@a"}}) end + assert_equal 1, ActionMailer::Base.deliveries.size assert_equal 302, status - assert_equal 0, ActionMailer::Base.deliveries.size assert_nil Session.last.authenticatable follow_redirect! From 72f8d9b945903ad0aaa6fd610ad5d09f4b53b690 Mon Sep 17 00:00:00 2001 From: Dakota Schramm Date: Fri, 3 May 2024 15:34:50 -0500 Subject: [PATCH 2/8] Add config option for sending paranoid email --- app/controllers/passwordless/sessions_controller.rb | 5 ++++- lib/passwordless/config.rb | 1 + test/dummy/db/schema.rb | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/controllers/passwordless/sessions_controller.rb b/app/controllers/passwordless/sessions_controller.rb index 725bf83..9aee0b4 100644 --- a/app/controllers/passwordless/sessions_controller.rb +++ b/app/controllers/passwordless/sessions_controller.rb @@ -203,7 +203,10 @@ def normalized_email_param def handle_resource_not_found if Passwordless.config.paranoid @resource = authenticatable_class.new(email: normalized_email_param) - @skip_after_session_save_callback = true + + if Passwordless.config.send_paranoid_email + @skip_after_session_save_callback = true + end else raise( ActiveRecord::RecordNotFound, diff --git a/lib/passwordless/config.rb b/lib/passwordless/config.rb index 4519f58..08d066f 100644 --- a/lib/passwordless/config.rb +++ b/lib/passwordless/config.rb @@ -56,6 +56,7 @@ class Configuration ) option :paranoid, default: false + option :send_paranoid_email, default: false def initialize set_defaults! diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index 5b34a51..79b7ea6 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -26,8 +26,8 @@ t.datetime "claimed_at", precision: nil t.string "token_digest", null: false t.string "identifier", null: false - t.datetime "created_at", precision: nil, null: false - t.datetime "updated_at", precision: nil, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["authenticatable_type", "authenticatable_id"], name: "authenticatable" t.index ["identifier"], name: "index_passwordless_sessions_on_identifier", unique: true end From 72f461a58f380f56fe6e24d6dc77dc3ae86cbab5 Mon Sep 17 00:00:00 2001 From: Dakota Schramm Date: Fri, 3 May 2024 15:40:13 -0500 Subject: [PATCH 3/8] Add NL to end of unknown_address text --- app/views/passwordless/mailer/unknown_address.text.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/passwordless/mailer/unknown_address.text.erb b/app/views/passwordless/mailer/unknown_address.text.erb index 85785f9..7201149 100644 --- a/app/views/passwordless/mailer/unknown_address.text.erb +++ b/app/views/passwordless/mailer/unknown_address.text.erb @@ -1 +1 @@ -<%= t("passwordless.mailer.unknown_address.body", email: @email ) %> \ No newline at end of file +<%= t("passwordless.mailer.unknown_address.body", email: @email ) %> From 917ffdbd7ff725be7df1073fc5a6d637eb496c54 Mon Sep 17 00:00:00 2001 From: Dakota Schramm Date: Fri, 3 May 2024 16:17:46 -0500 Subject: [PATCH 4/8] Move method for after config paranoid directly into call_after_session_save --- app/controllers/passwordless/sessions_controller.rb | 9 ++++----- lib/passwordless/config.rb | 8 +------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/app/controllers/passwordless/sessions_controller.rb b/app/controllers/passwordless/sessions_controller.rb index 9aee0b4..980f93a 100644 --- a/app/controllers/passwordless/sessions_controller.rb +++ b/app/controllers/passwordless/sessions_controller.rb @@ -203,10 +203,7 @@ def normalized_email_param def handle_resource_not_found if Passwordless.config.paranoid @resource = authenticatable_class.new(email: normalized_email_param) - - if Passwordless.config.send_paranoid_email - @skip_after_session_save_callback = true - end + @skip_after_session_save_callback = true else raise( ActiveRecord::RecordNotFound, @@ -217,7 +214,9 @@ def handle_resource_not_found def call_after_session_save if @skip_after_session_save_callback - Passwordless.config.after_session_paranoid.call(@session, request) + if Passwordless.config.send_paranoid_email + Mailer.unknown_address(@session).deliver_now + end elsif Passwordless.config.after_session_save.arity == 2 Passwordless.config.after_session_save.call(@session, request) else diff --git a/lib/passwordless/config.rb b/lib/passwordless/config.rb index 08d066f..5f2ffbe 100644 --- a/lib/passwordless/config.rb +++ b/lib/passwordless/config.rb @@ -48,13 +48,7 @@ class Configuration Mailer.sign_in(session, session.token).deliver_now end ) - option( - :after_session_paranoid, - default: lambda do |session, _request| - Mailer.unknown_address(session).deliver_now - end - ) - + option :paranoid, default: false option :send_paranoid_email, default: false From ea1ba19bdf41612e8b81ef457e7ad7c3573f366f Mon Sep 17 00:00:00 2001 From: Dakota Schramm Date: Fri, 3 May 2024 16:18:15 -0500 Subject: [PATCH 5/8] Add test for sending paranoid email with send_paranoid_email config enabled --- .../passwordless/sessions_controller_test.rb | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/test/controllers/passwordless/sessions_controller_test.rb b/test/controllers/passwordless/sessions_controller_test.rb index 3d74e41..09d7fd5 100644 --- a/test/controllers/passwordless/sessions_controller_test.rb +++ b/test/controllers/passwordless/sessions_controller_test.rb @@ -98,15 +98,31 @@ class << User post("/users/sign_in", params: {passwordless: {email: "a@a"}}) end - assert_equal 1, ActionMailer::Base.deliveries.size assert_equal 302, status + assert_equal 0, ActionMailer::Base.deliveries.size assert_nil Session.last.authenticatable follow_redirect! assert_equal "/users/sign_in/#{Session.last!.identifier}", path end + test("POST /:passwordless_for/sign_in -> SUCCESS / not found, + paranoid enabled, send paranoid email") do + with_config(paranoid: true, send_paranoid_email: true) do + post("/users/sign_in", params: {passwordless: {email: "a@a"}}) + end + + assert_equal 1, ActionMailer::Base.deliveries.size + assert_nil Session.last.authenticatable + + assert_equal 302, status + + follow_redirect! + assert_equal "/users/sign_in/#{Session.last!.identifier}", path + end + + test("POST /:passwordless_for/sign_in -> ERROR / not found and paranoid disabled") do post("/users/sign_in", params: {passwordless: {email: "A@a"}}) From 58268055549372b18a7df49975206ad9c46306ff Mon Sep 17 00:00:00 2001 From: Dakota Schramm Date: Fri, 3 May 2024 16:32:34 -0500 Subject: [PATCH 6/8] Remove whitespace. Revert schema update --- app/controllers/passwordless/sessions_controller.rb | 4 ++-- test/dummy/db/schema.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/passwordless/sessions_controller.rb b/app/controllers/passwordless/sessions_controller.rb index 980f93a..c5cdc14 100644 --- a/app/controllers/passwordless/sessions_controller.rb +++ b/app/controllers/passwordless/sessions_controller.rb @@ -203,7 +203,7 @@ def normalized_email_param def handle_resource_not_found if Passwordless.config.paranoid @resource = authenticatable_class.new(email: normalized_email_param) - @skip_after_session_save_callback = true + @skip_after_session_save_callback = true else raise( ActiveRecord::RecordNotFound, @@ -215,7 +215,7 @@ def handle_resource_not_found def call_after_session_save if @skip_after_session_save_callback if Passwordless.config.send_paranoid_email - Mailer.unknown_address(@session).deliver_now + Mailer.unknown_address(@session).deliver_now end elsif Passwordless.config.after_session_save.arity == 2 Passwordless.config.after_session_save.call(@session, request) diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index 79b7ea6..5b34a51 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -26,8 +26,8 @@ t.datetime "claimed_at", precision: nil t.string "token_digest", null: false t.string "identifier", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", precision: nil, null: false + t.datetime "updated_at", precision: nil, null: false t.index ["authenticatable_type", "authenticatable_id"], name: "authenticatable" t.index ["identifier"], name: "index_passwordless_sessions_on_identifier", unique: true end From 686e1214e20425af105afcb1c0e3e2f9b1bc3260 Mon Sep 17 00:00:00 2001 From: Dakota Schramm Date: Fri, 3 May 2024 16:35:29 -0500 Subject: [PATCH 7/8] Fix default text added with unknown_address mailer --- config/locales/en.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 478a64b..1a98f8a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -34,7 +34,7 @@ en: We noticed a login attempt using your email, %{email}. If you're seeing this email, that means that you don't currently have an - account associated with this email for Chuck. - Maybe you have a different account that's associated with your Chuck user? + account associated with this email. + Maybe you have a different email that's associated with your account? If this wasn't you, disregard this email. From c999b647e63cf6d003e98c2a207faa68e7fed071 Mon Sep 17 00:00:00 2001 From: Dakota Schramm Date: Fri, 3 May 2024 16:36:16 -0500 Subject: [PATCH 8/8] Remove extra whitespace --- lib/passwordless/config.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/passwordless/config.rb b/lib/passwordless/config.rb index 5f2ffbe..93e367a 100644 --- a/lib/passwordless/config.rb +++ b/lib/passwordless/config.rb @@ -48,7 +48,7 @@ class Configuration Mailer.sign_in(session, session.token).deliver_now end ) - + option :paranoid, default: false option :send_paranoid_email, default: false