refactor 2fa

pull/402/merge
Pete Matsyburka 1 month ago
parent fe6baba8bf
commit 347be0137d

@ -27,26 +27,34 @@ class SubmissionsDownloadController < ApplicationController
Submissions::EnsureResultGenerated.call(last_submitter) Submissions::EnsureResultGenerated.call(last_submitter)
if last_submitter.completed_at < TTL.ago && !signature_valid && !current_user_submitter?(last_submitter) if !signature_valid && !current_user_submitter?(last_submitter)
return head :not_found unless Submitters::AuthorizedForForm.call(@submitter, current_user, request)
if last_submitter.completed_at < TTL.ago
Rollbar.info("TTL: #{last_submitter.id}") if defined?(Rollbar) Rollbar.info("TTL: #{last_submitter.id}") if defined?(Rollbar)
return head :not_found return head :not_found
end end
end
if params[:combined] == 'true' if params[:combined] == 'true'
url = build_combined_url(@submitter) respond_with_combined(last_submitter)
else
render json: build_urls(last_submitter)
end
end
private
def respond_with_combined(submitter)
url = build_combined_url(submitter)
if url if url
render json: [url] render json: [url]
else else
head :not_found head :not_found
end end
else
render json: build_urls(last_submitter)
end end
end
private
def current_user_submitter?(submitter) def current_user_submitter?(submitter)
current_user && current_user.account.submitters.exists?(id: submitter.id) current_user && current_user.account.submitters.exists?(id: submitter.id)

@ -9,7 +9,7 @@ class SubmitFormController < ApplicationController
before_action :load_submitter, only: %i[show update completed] before_action :load_submitter, only: %i[show update completed]
before_action :maybe_render_locked_page, only: :show before_action :maybe_render_locked_page, only: :show
before_action :maybe_require_link_2fa, only: %i[show update] before_action :maybe_require_link_2fa, only: %i[show]
CONFIG_KEYS = [].freeze CONFIG_KEYS = [].freeze
@ -17,7 +17,7 @@ class SubmitFormController < ApplicationController
submission = @submitter.submission submission = @submitter.submission
return redirect_to submit_form_completed_path(@submitter.slug) if @submitter.completed_at? return redirect_to submit_form_completed_path(@submitter.slug) if @submitter.completed_at?
return render :email_2fa if require_email_2fa?(@submitter) return render :email_2fa unless Submitters::AuthorizedForForm.pass_email_2fa?(@submitter, request)
@form_configs = Submitters::FormConfigs.call(@submitter, CONFIG_KEYS) @form_configs = Submitters::FormConfigs.call(@submitter, CONFIG_KEYS)
@ -48,7 +48,7 @@ class SubmitFormController < ApplicationController
end end
def update def update
if require_email_2fa?(@submitter) unless Submitters::AuthorizedForForm.call(@submitter, current_user, request)
return render json: { error: I18n.t('verification_required_refresh_the_page_and_pass_2fa') }, return render json: { error: I18n.t('verification_required_refresh_the_page_and_pass_2fa') },
status: :unprocessable_content status: :unprocessable_content
end end
@ -84,7 +84,9 @@ class SubmitFormController < ApplicationController
def completed def completed
raise ActionController::RoutingError, I18n.t('not_found') if @submitter.account.archived_at? raise ActionController::RoutingError, I18n.t('not_found') if @submitter.account.archived_at?
redirect_to submit_form_path(params[:submit_form_slug]) if require_email_2fa?(@submitter) return if Submitters::AuthorizedForForm.call(@submitter, current_user, request)
redirect_to submit_form_path(params[:submit_form_slug])
end end
def success; end def success; end
@ -92,10 +94,7 @@ class SubmitFormController < ApplicationController
private private
def maybe_require_link_2fa def maybe_require_link_2fa
return if @submitter.submission.source != 'link' return if Submitters::AuthorizedForForm.pass_link_2fa?(@submitter, current_user, request)
return unless @submitter.submission.template&.preferences&.dig('shared_link_2fa') == true
return if cookies.encrypted[:email_2fa_slug] == @submitter.slug
return if @submitter.email == current_user&.email && current_user&.account_id == @submitter.account_id
redirect_to start_form_path(@submitter.submission.template.slug) redirect_to start_form_path(@submitter.submission.template.slug)
end end
@ -117,12 +116,4 @@ class SubmitFormController < ApplicationController
ActiveStorage::Attachment.where(record: submission.submitters, name: :attachments) ActiveStorage::Attachment.where(record: submission.submitters, name: :attachments)
.preload(:blob).index_by(&:uuid) .preload(:blob).index_by(&:uuid)
end end
def require_email_2fa?(submitter)
return false if submitter.submission.template&.preferences&.dig('require_email_2fa') != true &&
submitter.preferences['require_email_2fa'] != true
return false if cookies.encrypted[:email_2fa_slug] == submitter.slug
true
end
end end

@ -11,7 +11,9 @@ class SubmitFormDeclineController < ApplicationController
submitter.completed_at? || submitter.completed_at? ||
submitter.submission.archived_at? || submitter.submission.archived_at? ||
submitter.submission.expired? || submitter.submission.expired? ||
submitter.submission.template&.archived_at? submitter.submission.template&.archived_at? ||
!Submitters::AuthorizedForForm.call(submitter, current_user,
request)
ApplicationRecord.transaction do ApplicationRecord.transaction do
submitter.update!(declined_at: Time.current) submitter.update!(declined_at: Time.current)

@ -17,7 +17,8 @@ class SubmitFormDownloadController < ApplicationController
@submitter.submission.template&.archived_at? || @submitter.submission.template&.archived_at? ||
AccountConfig.exists?(account_id: @submitter.account_id, AccountConfig.exists?(account_id: @submitter.account_id,
key: AccountConfig::ALLOW_TO_PARTIAL_DOWNLOAD_KEY, key: AccountConfig::ALLOW_TO_PARTIAL_DOWNLOAD_KEY,
value: false) value: false) ||
!Submitters::AuthorizedForForm.call(@submitter, current_user, request)
last_completed_submitter = @submitter.submission.submitters last_completed_submitter = @submitter.submission.submitters
.where.not(id: @submitter.id) .where.not(id: @submitter.id)

@ -12,7 +12,8 @@ class SubmitFormDrawSignatureController < ApplicationController
return redirect_to submit_form_completed_path(@submitter.slug) if @submitter.completed_at? return redirect_to submit_form_completed_path(@submitter.slug) if @submitter.completed_at?
if @submitter.submission.template&.archived_at? || @submitter.submission.archived_at? if @submitter.submission.template&.archived_at? || @submitter.submission.archived_at? ||
!Submitters::AuthorizedForForm.call(@submitter, current_user, request)
return redirect_to submit_form_path(@submitter.slug) return redirect_to submit_form_path(@submitter.slug)
end end

@ -45,7 +45,8 @@ class SubmitFormInviteController < ApplicationController
!submitter.completed_at? && !submitter.completed_at? &&
!submitter.submission.archived_at? && !submitter.submission.archived_at? &&
!submitter.submission.expired? && !submitter.submission.expired? &&
!submitter.submission.template&.archived_at? !submitter.submission.template&.archived_at? &&
Submitters::AuthorizedForForm.call(submitter, current_user, request)
end end
def filter_invite_submitters(submitter, key = 'invite_by_uuid') def filter_invite_submitters(submitter, key = 'invite_by_uuid')

@ -7,10 +7,12 @@ class SubmitFormValuesController < ApplicationController
def index def index
submitter = Submitter.find_by!(slug: params[:submit_form_slug]) submitter = Submitter.find_by!(slug: params[:submit_form_slug])
return render json: {} if submitter.completed_at? || submitter.declined_at? return render json: {} if submitter.completed_at? ||
return render json: {} if submitter.submission.template&.archived_at? || submitter.declined_at? ||
submitter.submission.template&.archived_at? ||
submitter.submission.archived_at? || submitter.submission.archived_at? ||
submitter.submission.expired? submitter.submission.expired? ||
!Submitters::AuthorizedForForm.call(submitter, current_user, request)
value = submitter.values[params['field_uuid']] value = submitter.values[params['field_uuid']]
attachment = submitter.attachments.where(created_at: params[:after]..).find_by(uuid: value) if value.present? attachment = submitter.attachments.where(created_at: params[:after]..).find_by(uuid: value) if value.present?

@ -0,0 +1,45 @@
# frozen_string_literal: true
module Submitters
module AuthorizedForForm
Unauthorized = Class.new(StandardError)
module_function
def call(submitter, current_user, request)
pass_email_2fa?(submitter, request) && pass_link_2fa?(submitter, current_user, request)
end
def pass_email_2fa?(submitter, request)
return false unless submitter
return true if submitter.submission.template&.preferences&.dig('require_email_2fa') != true &&
submitter.preferences['require_email_2fa'] != true
return true if request.cookie_jar.encrypted[:email_2fa_slug] == submitter.slug
return true if request.params[:two_factor_token].present? &&
Submitter.signed_id_verifier.verified(request.params[:two_factor_token],
purpose: :email_two_factor) == submitter.slug
false
end
def pass_link_2fa?(submitter, current_user, request)
return false unless submitter
return true if submitter.submission.source != 'link'
return true unless submitter.submission.template&.preferences&.dig('shared_link_2fa') == true
return true if request.cookie_jar.encrypted[:email_2fa_slug] == submitter.slug
return true if submitter.email == current_user&.email && current_user&.account_id == submitter.account_id
if request.params[:two_factor_token].present?
link_2fa_key = [submitter.email.downcase.squish, submitter.submission.template.slug].join(':')
return true if Submitter.signed_id_verifier.verified(request.params[:two_factor_token],
purpose: :email_two_factor) == link_2fa_key
end
false
end
end
end
Loading…
Cancel
Save