diff --git a/app/controllers/start_form_controller.rb b/app/controllers/start_form_controller.rb index a5b6fce1..86471d38 100644 --- a/app/controllers/start_form_controller.rb +++ b/app/controllers/start_form_controller.rb @@ -162,6 +162,10 @@ class StartFormController < ApplicationController end rescue Submitters::StartForm::NotSaved render :show, status: :unprocessable_content + rescue Submitters::BouncedEmail => e + @error_message = e.message + + render :error, status: :unprocessable_content rescue Submitters::UnableToSendCode, Submitters::InvalidOtp => e redirect_to start_form_path(template.slug, params: submitter_params.merge(email_verification: true)), alert: e.message diff --git a/app/controllers/start_form_email_2fa_send_controller.rb b/app/controllers/start_form_email_2fa_send_controller.rb index 07dd18c4..0787ab46 100644 --- a/app/controllers/start_form_email_2fa_send_controller.rb +++ b/app/controllers/start_form_email_2fa_send_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class StartFormEmail2faSendController < ApplicationController + layout 'form' + around_action :with_browser_locale skip_before_action :authenticate_user! @@ -23,6 +25,10 @@ class StartFormEmail2faSendController < ApplicationController redirect_to start_form_path(@template.slug, params: submitter_params.merge(email_verification: true)), **redir_params + rescue Submitters::BouncedEmail => e + @error_message = e.message + + render 'start_form/error', status: :unprocessable_content rescue Submitters::UnableToSendCode => e redirect_to start_form_path(@template.slug, params: submitter_params.merge(email_verification: true)), alert: e.message diff --git a/app/controllers/start_form_resubmit_controller.rb b/app/controllers/start_form_resubmit_controller.rb index d0c91c69..d616a4e0 100644 --- a/app/controllers/start_form_resubmit_controller.rb +++ b/app/controllers/start_form_resubmit_controller.rb @@ -87,6 +87,10 @@ class StartFormResubmitController < ApplicationController end rescue Submitters::StartForm::NotSaved render 'start_form/show', status: :unprocessable_content + rescue Submitters::BouncedEmail => e + @error_message = e.message + + render 'start_form/error', status: :unprocessable_content rescue Submitters::UnableToSendCode, Submitters::InvalidOtp => e flash.now[:alert] = e.message diff --git a/app/controllers/submit_form_email_2fas_controller.rb b/app/controllers/submit_form_email_2fas_controller.rb index dfe518b0..377f99ca 100644 --- a/app/controllers/submit_form_email_2fas_controller.rb +++ b/app/controllers/submit_form_email_2fas_controller.rb @@ -35,6 +35,12 @@ class SubmitFormEmail2fasController < ApplicationController RateLimit.call("send-email-code-#{@submitter.id}", limit: 2, ttl: 45.seconds, enabled: true) + if Docuseal.multitenant? && Submitters.email_bounced_recently?(@submitter.email) + Rollbar.warning("Bounced OTP email for submitter: #{@submitter.id}") if defined?(Rollbar) + + return redirect_to submit_form_path(@submitter.slug, status: :error), alert: I18n.t(:verification_email_bounced) + end + SendSubmitterVerificationEmailJob.perform_async('submitter_id' => @submitter.id, 'locale' => I18n.locale.to_s) redir_params = params[:resend] ? { alert: I18n.t(:code_has_been_resent) } : {} diff --git a/app/views/start_form/error.html.erb b/app/views/start_form/error.html.erb new file mode 100644 index 00000000..45221209 --- /dev/null +++ b/app/views/start_form/error.html.erb @@ -0,0 +1,31 @@ +<% content_for(:html_title, "#{@template.name} | DocuSeal") %> +<% I18n.with_locale(@template.account.locale) do %> + <% content_for(:html_description, t('account_name_has_invited_you_to_fill_and_sign_documents_online_effortlessly_with_a_secure_fast_and_user_friendly_digital_document_signing_solution', account_name: @template.account.name)) %> +<% end %> +
+
+
+
+ <%= render 'start_form/banner' %> +
+
+
+
+ <%= svg_icon('writing_sign', class: 'w-10 h-10') %> +
+
+

<%= @template.name %>

+

<%= t('invited_by_html', name: @template.account.name) %>

+
+
+
+
+
+ <%= svg_icon('info_circle', class: 'stroke-current shrink-0 h-6 w-6 mt-1') %> +
<%= @error_message %>
+
+
+ <%= link_to t('back'), @resubmit_submitter ? submit_form_path(@resubmit_submitter.slug) : start_form_path(@template.slug, @submitter.slice(:name, :email, :phone).compact_blank), class: 'base-button' %> +
+
+
diff --git a/config/locales/i18n.yml b/config/locales/i18n.yml index 6d5dfe53..869795e2 100644 --- a/config/locales/i18n.yml +++ b/config/locales/i18n.yml @@ -790,6 +790,7 @@ en: &en the_code_has_been_sent_to_your_email: The code has been sent to your email. enter_the_verification_code_from_your_email: Enter the verification code from your email. too_many_attempts: Too many attempts. + verification_email_bounced: "Unable to send the verification code: email to this address bounced." verification_code: Verification Code resend_code: Resend Code verify_new_sign_in: Verify new sign in @@ -1916,6 +1917,7 @@ es: &es the_code_has_been_sent_to_your_email: El código ha sido enviado a tu correo electrónico. enter_the_verification_code_from_your_email: Ingresa el código de verificación de tu correo electrónico. too_many_attempts: Demasiados intentos. + verification_email_bounced: "No se pudo enviar el código de verificación: el correo a esta dirección rebotó." verification_code: Código de Verificación resend_code: Reenviar Código verify_new_sign_in: Verificar nuevo inicio de sesión @@ -3049,6 +3051,7 @@ it: &it the_code_has_been_sent_to_your_email: Il codice è stato inviato alla tua e-mail. enter_the_verification_code_from_your_email: Inserisci il codice di verifica dalla tua e-mail. too_many_attempts: Troppi tentativi. + verification_email_bounced: "Impossibile inviare il codice di verifica: l'email a questo indirizzo è stata respinta." verification_code: Codice di Verifica resend_code: Reinvia Codice verify_new_sign_in: Verifica nuovo accesso @@ -4168,6 +4171,7 @@ fr: &fr the_code_has_been_sent_to_your_email: Le code a été envoyé à votre e‑mail. enter_the_verification_code_from_your_email: Saisissez le code de vérification reçu par e‑mail. too_many_attempts: Trop de tentatives. + verification_email_bounced: "Impossible d'envoyer le code de vérification : l'e-mail à cette adresse a été rejeté." verification_code: Code de vérification resend_code: Renvoyer le code verify_new_sign_in: Vérifier une nouvelle connexion @@ -5297,6 +5301,7 @@ pt: &pt the_code_has_been_sent_to_your_email: O código foi enviado para seu e-mail. enter_the_verification_code_from_your_email: Insira o código de verificação do seu e-mail. too_many_attempts: Muitas tentativas. + verification_email_bounced: "Não foi possível enviar o código de verificação: o e-mail para este endereço não foi entregue." verification_code: Código de Verificação resend_code: Reenviar Código verify_new_sign_in: Verificar novo login @@ -6429,6 +6434,7 @@ de: &de the_code_has_been_sent_to_your_email: Der Code wurde an Ihre E-Mail gesendet. enter_the_verification_code_from_your_email: Geben Sie den Verifizierungscode aus Ihrer E-Mail ein. too_many_attempts: Zu viele Versuche. + verification_email_bounced: "Der Verifizierungscode konnte nicht gesendet werden: E-Mail an diese Adresse ist unzustellbar." verification_code: Verifizierungscode resend_code: Code erneut senden verify_new_sign_in: Neue Anmeldung verifizieren @@ -6868,6 +6874,8 @@ pl: the_code_has_been_sent_to_your_email: Kod został wysłany na Twój e-mail. enter_the_verification_code_from_your_email: Wprowadź kod weryfikacyjny z Twojego e-maila. too_many_attempts: Zbyt wiele prób. + verification_email_bounced: "Nie można wysłać kodu weryfikacyjnego: e-mail na ten adres został odrzucony." + back: Wstecz verification_code: Kod Weryfikacyjny resend_code: Wyślij Kod Ponownie powered_by: 'Napędzany przez' @@ -7008,6 +7016,8 @@ uk: the_code_has_been_sent_to_your_email: Код було надіслано на вашу електронну пошту. enter_the_verification_code_from_your_email: Введіть код перевірки з вашої електронної пошти. too_many_attempts: Забагато спроб. + verification_email_bounced: "Не вдалося надіслати код підтвердження: лист на цю адресу було відхилено." + back: Назад verification_code: Код перевірки resend_code: Надіслати код знову powered_by: 'Працює на базі' @@ -7148,6 +7158,8 @@ cs: the_code_has_been_sent_to_your_email: Kód byl odeslán na váš e-mail. enter_the_verification_code_from_your_email: Zadejte ověřovací kód z vašeho e-mailu. too_many_attempts: Příliš mnoho pokusů. + verification_email_bounced: "Ověřovací kód nelze odeslat: e-mail na tuto adresu byl odmítnut." + back: Zpět verification_code: Ověřovací kód resend_code: Znovu odeslat kód powered_by: 'Poháněno' @@ -7274,6 +7286,8 @@ he: the_code_has_been_sent_to_your_email: הקוד נשלח לדוא"ל שלך. enter_the_verification_code_from_your_email: הזן את קוד האימות מדוא"ל שלך. too_many_attempts: יותר מדי ניסיונות. + verification_email_bounced: "לא ניתן לשלוח את קוד האימות: האימייל לכתובת זו נדחה." + back: חזרה verification_code: קוד אימות resend_code: שלח קוד מחדש powered_by: 'מופעל על ידי' @@ -8081,6 +8095,7 @@ nl: &nl the_code_has_been_sent_to_your_email: De code is naar uw e-mail verzonden. enter_the_verification_code_from_your_email: Voer de verificatiecode uit uw e-mail in. too_many_attempts: Te veel pogingen. + verification_email_bounced: "Verificatiecode kan niet worden verzonden: e-mail naar dit adres is geretourneerd." verification_code: Verificatiecode resend_code: Code opnieuw verzenden verify_new_sign_in: Nieuwe aanmelding verifiëren @@ -8503,6 +8518,8 @@ ar: the_code_has_been_sent_to_your_email: تم إرسال الرمز إلى بريدك الإلكتروني. enter_the_verification_code_from_your_email: أدخل رمز التحقق من بريدك الإلكتروني. too_many_attempts: عدد المحاولات كبير جدًا. + verification_email_bounced: "تعذر إرسال رمز التحقق: تم رفض البريد الإلكتروني المرسل إلى هذا العنوان." + back: رجوع verification_code: رمز التحقق resend_code: إعادة إرسال الرمز powered_by: 'مشغل بواسطة' @@ -8615,6 +8632,8 @@ ko: the_code_has_been_sent_to_your_email: 코드가 이메일로 전송되었습니다. enter_the_verification_code_from_your_email: 이메일로 받은 인증 코드를 입력하세요. too_many_attempts: 시도 횟수가 너무 많습니다. + verification_email_bounced: "인증 코드를 보낼 수 없습니다: 이 주소로 보낸 이메일이 반송되었습니다." + back: 뒤로 verification_code: 인증 코드 resend_code: 코드 재전송 powered_by: '제공:' @@ -8727,6 +8746,8 @@ ja: the_code_has_been_sent_to_your_email: コードがあなたのメールに送信されました enter_the_verification_code_from_your_email: メールに記載された認証コードを入力してください too_many_attempts: 試行回数が多すぎます + verification_email_bounced: "認証コードを送信できません:このアドレス宛のメールが配信できませんでした。" + back: 戻る verification_code: 認証コード resend_code: コードを再送信 powered_by: '提供元:' diff --git a/lib/submitters.rb b/lib/submitters.rb index 6a562390..3ea1aa07 100644 --- a/lib/submitters.rb +++ b/lib/submitters.rb @@ -11,6 +11,7 @@ module Submitters }.freeze UnableToSendCode = Class.new(StandardError) + BouncedEmail = Class.new(UnableToSendCode) InvalidOtp = Class.new(StandardError) MaliciousFileExtension = Class.new(StandardError) ParamsError = Class.new(StandardError) @@ -243,6 +244,12 @@ module Submitters def send_shared_link_email_verification_code(submitter, request:) RateLimit.call("send-otp-code-#{request.remote_ip}", limit: 2, ttl: 45.seconds, enabled: true) + if Docuseal.multitenant? && email_bounced_recently?(submitter.email) + Rollbar.warning("Bounced OTP email for template: #{submitter.submission.template.id}") if defined?(Rollbar) + + raise BouncedEmail, I18n.t(:verification_email_bounced) + end + TemplateMailer.otp_verification_email(submitter.submission.template, email: submitter.email).deliver_later! rescue RateLimit::LimitApproached Rollbar.warning("Limit verification code for template: #{submitter.submission.template.id}") if defined?(Rollbar) @@ -250,6 +257,11 @@ module Submitters raise UnableToSendCode, I18n.t('too_many_attempts') end + def email_bounced_recently?(email) + EmailEvent.exists?(email:, event_type: %w[bounce soft_bounce permanent_bounce], + event_datetime: 24.hours.ago..Time.current) + end + def verify_link_otp!(otp, submitter) return false if otp.blank?