Validate email before creating identity during join code redemption

Avoid Sentry exceptions when attackers try to stuff invalid emails. The
browser performs form field validation that should normally prevent this
from occurring, so we just return 422 without validation error messages.

See similar change in #1996 for sign-in and sign-up
This commit is contained in:
Mike Dalessio
2025-12-07 13:26:31 -05:00
parent 12eceb97eb
commit 661a7e5e2d
2 changed files with 30 additions and 7 deletions
+18 -7
View File
@@ -3,6 +3,7 @@ class JoinCodesController < ApplicationController
before_action :set_join_code
before_action :ensure_join_code_is_valid
before_action :set_identity, only: :create
layout "public"
@@ -10,25 +11,35 @@ class JoinCodesController < ApplicationController
end
def create
identity = Identity.find_or_create_by!(email_address: params.expect(:email_address))
@join_code.redeem_if { |account| @identity.join(account) }
user = User.active.find_by!(account: @join_code.account, identity: @identity)
@join_code.redeem_if { |account| identity.join(account) }
user = User.active.find_by!(account: @join_code.account, identity: identity)
if identity == Current.identity && user.setup?
if @identity == Current.identity && user.setup?
redirect_to landing_url(script_name: @join_code.account.slug)
elsif identity == Current.identity
elsif @identity == Current.identity
redirect_to new_users_verification_url(script_name: @join_code.account.slug)
else
terminate_session if Current.identity
redirect_to_session_magic_link \
identity.send_magic_link,
@identity.send_magic_link,
return_to: new_users_verification_url(script_name: @join_code.account.slug)
end
end
private
def set_identity
@identity = Identity.find_or_initialize_by(email_address: params.expect(:email_address))
if @identity.new_record?
if @identity.invalid?
head :unprocessable_entity
else
@identity.save!
end
end
end
def set_join_code
@join_code ||= Account::JoinCode.find_by(code: params.expect(:code), account: Current.account)
end
@@ -82,4 +82,16 @@ class JoinCodesControllerTest < ActionDispatch::IntegrationTest
assert_redirected_to session_magic_link_url(script_name: nil)
assert_not_predicate cookies[:session_token], :present?
end
test "create with invalid email address" do
# Avoid Sentry exceptions when attackers try to stuff invalid emails into the system
without_action_dispatch_exception_handling do
assert_no_difference -> { Identity.count } do
assert_no_difference -> { User.count } do
post join_path(code: @join_code.code, script_name: @account.slug), params: { email_address: "not-a-valid-email" }
end
end
assert_response :unprocessable_entity
end
end
end