shared link 2fa
This commit is contained in:
committed by
Pete Matsyburka
parent
931addedbe
commit
a61c3e798d
@@ -0,0 +1,27 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module EmailVerificationCodes
|
||||
DRIFT_BEHIND = 5.minutes
|
||||
|
||||
module_function
|
||||
|
||||
def generate(value)
|
||||
totp = ROTP::TOTP.new(build_totp_secret(value))
|
||||
|
||||
totp.at(Time.current)
|
||||
end
|
||||
|
||||
def verify(code, value)
|
||||
totp = ROTP::TOTP.new(build_totp_secret(value))
|
||||
|
||||
totp.verify(code, drift_behind: DRIFT_BEHIND)
|
||||
end
|
||||
|
||||
def build_totp_secret(value)
|
||||
ROTP::Base32.encode(
|
||||
Digest::SHA1.digest(
|
||||
[Rails.application.secret_key_base, value].join(':')
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -244,11 +244,18 @@ module Submissions
|
||||
|
||||
click_email_event =
|
||||
submission.submission_events.find { |e| e.submitter_id == submitter.id && e.click_email? }
|
||||
|
||||
verify_email_event =
|
||||
submission.submission_events.find { |e| e.submitter_id == submitter.id && e.phone_verified? }
|
||||
|
||||
is_phone_verified =
|
||||
submission.template_fields.any? do |e|
|
||||
e['type'] == 'phone' && e['submitter_uuid'] == submitter.uuid && submitter.values[e['uuid']].present?
|
||||
end
|
||||
|
||||
verify_phone_event =
|
||||
submission.submission_events.find { |e| e.submitter_id == submitter.id && e.phone_verified? }
|
||||
|
||||
is_id_verified =
|
||||
submission.template_fields.any? do |e|
|
||||
e['type'] == 'verification' && e['submitter_uuid'] == submitter.uuid && submitter.values[e['uuid']].present?
|
||||
@@ -270,10 +277,10 @@ module Submissions
|
||||
[
|
||||
composer.document.layout.formatted_text_box(
|
||||
[
|
||||
submitter.email && click_email_event && {
|
||||
submitter.email && (click_email_event || verify_email_event) && {
|
||||
text: "#{I18n.t('email_verification')}: #{I18n.t('verified')}\n"
|
||||
},
|
||||
submitter.phone && is_phone_verified && {
|
||||
submitter.phone && (is_phone_verified || verify_phone_event) && {
|
||||
text: "#{I18n.t('phone_verification')}: #{I18n.t('verified')}\n"
|
||||
},
|
||||
is_id_verified && {
|
||||
|
||||
@@ -11,6 +11,9 @@ module Submitters
|
||||
'values' => 'D'
|
||||
}.freeze
|
||||
|
||||
UnableToSendCode = Class.new(StandardError)
|
||||
InvalidOtp = Class.new(StandardError)
|
||||
|
||||
module_function
|
||||
|
||||
def search(current_user, submitters, keyword)
|
||||
@@ -194,4 +197,27 @@ module Submitters
|
||||
|
||||
"#{filename}.#{blob.filename.extension}"
|
||||
end
|
||||
|
||||
def send_shared_link_email_verification_code(submitter, request:)
|
||||
RateLimit.call("send-otp-code-#{request.remote_ip}", limit: 2, ttl: 45.seconds, enabled: true)
|
||||
|
||||
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)
|
||||
|
||||
raise UnableToSendCode, I18n.t('too_many_attempts')
|
||||
end
|
||||
|
||||
def verify_link_otp!(otp, submitter)
|
||||
return false if otp.blank?
|
||||
|
||||
RateLimit.call("verify-2fa-code-#{Digest::MD5.base64digest(submitter.email)}",
|
||||
limit: 2, ttl: 45.seconds, enabled: true)
|
||||
|
||||
link_2fa_key = [submitter.email.downcase.squish, submitter.submission.template.slug].join(':')
|
||||
|
||||
raise InvalidOtp, I18n.t(:invalid_code) unless EmailVerificationCodes.verify(otp, link_2fa_key)
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user