diff --git a/app/controllers/join_codes_controller.rb b/app/controllers/join_codes_controller.rb index 99298880c..8bd67c9dc 100644 --- a/app/controllers/join_codes_controller.rb +++ b/app/controllers/join_codes_controller.rb @@ -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 diff --git a/test/controllers/join_codes_controller_test.rb b/test/controllers/join_codes_controller_test.rb index 9558b605a..415bde3e5 100644 --- a/test/controllers/join_codes_controller_test.rb +++ b/test/controllers/join_codes_controller_test.rb @@ -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