add cancan for authorization

This commit is contained in:
Alex Turchyn
2023-09-17 00:45:57 +03:00
parent f89c50d096
commit 2f1843151d
58 changed files with 343 additions and 186 deletions
+7
View File
@@ -9,6 +9,9 @@ class AccountsController < ApplicationController
'de-DE' => 'German (Germany)'
}.freeze
before_action :load_account
authorize_resource :account
def show; end
def update
@@ -35,6 +38,10 @@ class AccountsController < ApplicationController
private
def load_account
@account = current_account
end
def account_params
params.require(:account).permit(:name, :timezone, :locale)
end
@@ -5,6 +5,15 @@ module Api
include ActiveStorage::SetCurrent
before_action :authenticate_user!
check_authorization
if Rails.env.production?
rescue_from CanCan::AccessDenied do |e|
Rollbar.error(e) if defined?(Rollbar)
render json: { error: e.message }, status: :forbidden
end
end
private
@@ -3,6 +3,7 @@
module Api
class AttachmentsController < ApiBaseController
skip_before_action :authenticate_user!
skip_authorization_check
def create
submitter = Submitter.find_by!(slug: params[:submitter_slug])
@@ -5,21 +5,25 @@ module Api
UnknownFieldName = Class.new(StandardError)
UnknownSubmitterName = Class.new(StandardError)
def create
template = current_account.templates.find(params[:template_id])
load_and_authorize_resource :template
before_action do
authorize!(:create, Submission)
end
def create
submissions =
if (emails = (params[:emails] || params[:email]).presence)
Submissions.create_from_emails(template:,
Submissions.create_from_emails(template: @template,
user: current_user,
source: :api,
mark_as_sent: params[:send_email] != 'false',
emails:)
else
submissions_attrs = normalize_submissions_params!(submissions_params[:submission], template)
submissions_attrs = normalize_submissions_params!(submissions_params[:submission], @template)
Submissions.create_from_submitters(
template:,
template: @template,
user: current_user,
source: :api,
mark_as_sent: params[:send_email] != 'false',
@@ -3,6 +3,7 @@
module Api
class SubmitterEmailClicksController < ApiBaseController
skip_before_action :authenticate_user!
skip_authorization_check
def create
submitter = Submitter.find_by!(slug: params[:submitter_slug])
@@ -3,6 +3,7 @@
module Api
class SubmitterFormViewsController < ApiBaseController
skip_before_action :authenticate_user!
skip_authorization_check
def create
submitter = Submitter.find_by!(slug: params[:submitter_slug])
+2 -6
View File
@@ -2,10 +2,10 @@
module Api
class TemplatesController < ApiBaseController
before_action :load_template, only: %i[show update]
load_and_authorize_resource :template
def index
render json: current_account.templates
render json: @templates
end
def show
@@ -28,9 +28,5 @@ module Api
fields: [[:uuid, :submitter_uuid, :name, :type, :required,
{ options: [], areas: [%i[x y w h cell_w attachment_uuid page]] }]])
end
def load_template
@template = current_account.templates.find(params[:id])
end
end
end
@@ -2,11 +2,11 @@
module Api
class TemplatesDocumentsController < ApiBaseController
load_and_authorize_resource :template
def create
return head :unprocessable_entity if params[:blobs].blank? && params[:files].blank?
@template = current_account.templates.find(params[:template_id])
documents = Templates::CreateAttachments.call(@template, params)
schema = documents.map do |doc|
+3 -1
View File
@@ -1,5 +1,7 @@
# frozen_string_literal: true
class ApiSettingsController < ApplicationController
def index; end
def index
authorize!(:read, current_user.access_token)
end
end
+10
View File
@@ -4,6 +4,8 @@ class ApplicationController < ActionController::Base
include ActiveStorage::SetCurrent
include Pagy::Backend
check_authorization unless: :devise_controller?
before_action :sign_in_for_demo, if: -> { Docuseal.demo? }
before_action :maybe_redirect_to_setup, unless: :signed_in?
before_action :authenticate_user!, unless: :devise_controller?
@@ -16,6 +18,14 @@ class ApplicationController < ActionController::Base
redirect_to request.path
end
if Rails.env.production?
rescue_from CanCan::AccessDenied do |e|
Rollbar.error(e) if defined?(Rollbar)
redirect_back(fallback_location: root_path, alert: e.message)
end
end
def default_url_options
Docuseal.default_url_options
end
@@ -2,6 +2,7 @@
class ConsoleRedirectController < ApplicationController
skip_before_action :authenticate_user!
skip_authorization_check
def index
return redirect_to(new_user_session_path({ redir: params[:redir] }.compact)) if current_user.blank?
+21 -5
View File
@@ -3,13 +3,29 @@
class DashboardController < ApplicationController
skip_before_action :authenticate_user!, only: %i[index]
before_action :maybe_redirect_product_url
before_action :maybe_render_landing
load_and_authorize_resource :template, parent: false
def index
return redirect_to Docuseal::PRODUCT_URL, allow_other_host: true if Docuseal.multitenant? && !signed_in?
return render 'pages/landing' unless signed_in?
@templates = @templates.active.preload(:author).order(id: :desc)
@templates = Templates.search(@templates, params[:q])
templates = current_account.templates.active.preload(:author).order(id: :desc)
templates = Templates.search(templates, params[:q])
@pagy, @templates = pagy(@templates, items: 12)
end
@pagy, @templates = pagy(templates, items: 12)
private
def maybe_redirect_product_url
return if !Docuseal.multitenant? || signed_in?
redirect_to Docuseal::PRODUCT_URL, allow_other_host: true
end
def maybe_render_landing
return if signed_in?
render 'pages/landing'
end
end
@@ -2,6 +2,8 @@
class EmailSettingsController < ApplicationController
before_action :load_encrypted_config
authorize_resource :encrypted_config, only: :index
authorize_resource :encrypted_config, parent: false, only: :create
def index; end
+17 -15
View File
@@ -11,9 +11,12 @@ class EsignSettingsController < ApplicationController
end
end
before_action :load_encrypted_config
authorize_resource :encrypted_config, parent: false, only: %i[new create]
authorize_resource :encrypted_config, only: %i[update destroy show]
def show
cert_data = EncryptedConfig.find_by(account: current_account,
key: EncryptedConfig::ESIGN_CERTS_KEY)&.value || {}
cert_data = @encrypted_config.value || {}
default_pkcs = GenerateCertificate.load_pkcs(cert_data) if cert_data['cert'].present?
@@ -42,10 +45,7 @@ class EsignSettingsController < ApplicationController
def create
@cert_record = CertFormRecord.new(**cert_params)
cert_configs = EncryptedConfig.find_or_initialize_by(account: current_account,
key: EncryptedConfig::ESIGN_CERTS_KEY)
if (cert_configs.value && cert_configs.value['custom']&.any? { |e| e['name'] == @cert_record.name }) ||
if (@encrypted_config.value && @encrypted_config.value['custom']&.any? { |e| e['name'] == @cert_record.name }) ||
@cert_record.name == DEFAULT_CERT_NAME
@cert_record.errors.add(:name, 'already exists')
@@ -54,7 +54,7 @@ class EsignSettingsController < ApplicationController
status: :unprocessable_entity
end
save_new_cert!(cert_configs, @cert_record)
save_new_cert!(@encrypted_config, @cert_record)
redirect_to settings_esign_path, notice: 'Certificate has been successfully added!'
rescue OpenSSL::PKCS12::PKCS12Error
@@ -64,29 +64,31 @@ class EsignSettingsController < ApplicationController
end
def update
cert_configs = EncryptedConfig.find_by(account: current_account, key: EncryptedConfig::ESIGN_CERTS_KEY)
@encrypted_config.value['custom'].each { |e| e['status'] = 'validate' }
cert_configs.value['custom'].each { |e| e['status'] = 'validate' }
custom_cert_data = cert_configs.value['custom'].find { |e| e['name'] == params[:name] }
custom_cert_data = @encrypted_config.value['custom'].find { |e| e['name'] == params[:name] }
custom_cert_data['status'] = 'default' if custom_cert_data
cert_configs.save!
@encrypted_config.save!
redirect_to settings_esign_path, notice: 'Default certificate has been selected'
end
def destroy
cert_configs = EncryptedConfig.find_by(account: current_account, key: EncryptedConfig::ESIGN_CERTS_KEY)
@encrypted_config.value['custom'].reject! { |e| e['name'] == params[:name] }
cert_configs.value['custom'].reject! { |e| e['name'] == params[:name] }
cert_configs.save!
@encrypted_config.save!
redirect_to settings_esign_path, notice: 'Certificate has been removed'
end
private
def load_encrypted_config
@encrypted_config = EncryptedConfig.find_or_initialize_by(account: current_account,
key: EncryptedConfig::ESIGN_CERTS_KEY)
end
def save_new_cert!(cert_configs, cert_record)
pkcs = OpenSSL::PKCS12.new(cert_record.file.read, cert_record.password)
+4
View File
@@ -1,6 +1,10 @@
# frozen_string_literal: true
class MfaSetupController < ApplicationController
before_action do
authorize!(:update, current_user)
end
def new
current_user.otp_secret ||= User.generate_otp_secret
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class NewslettersController < ApplicationController
skip_authorization_check
def show; end
def update
@@ -1,12 +1,16 @@
# frozen_string_literal: true
class PersonalizationSettingsController < ApplicationController
def show; end
def show
authorize!(:read, AccountConfig)
end
def create
account_config =
current_account.account_configs.find_or_initialize_by(key: encrypted_config_params[:key])
authorize!(:create, account_config)
account_config.update!(encrypted_config_params)
redirect_back(fallback_location: settings_personalization_path, notice: 'Settings have been saved.')
+4
View File
@@ -1,6 +1,10 @@
# frozen_string_literal: true
class ProfileController < ApplicationController
before_action do
authorize!(:manage, current_user)
end
def index; end
def update_contact
@@ -5,6 +5,7 @@ class SendSubmissionEmailController < ApplicationController
skip_before_action :authenticate_user!
skip_before_action :verify_authenticity_token
skip_authorization_check
def success; end
+1
View File
@@ -3,6 +3,7 @@
class SetupController < ApplicationController
skip_before_action :maybe_redirect_to_setup
skip_before_action :authenticate_user!
skip_authorization_check
before_action :redirect_to_root_if_signed, if: :signed_in?
before_action :ensure_first_user_not_created!
@@ -1,5 +1,16 @@
# frozen_string_literal: true
class SmsSettingsController < ApplicationController
before_action :load_encrypted_config
authorize_resource :encrypted_config, only: :index
authorize_resource :encrypted_config, parent: false, except: :index
def index; end
private
def load_encrypted_config
@encrypted_config =
EncryptedConfig.find_or_initialize_by(account: current_account, key: 'sms_configs')
end
end
+1
View File
@@ -4,6 +4,7 @@ class StartFormController < ApplicationController
layout 'form'
skip_before_action :authenticate_user!
skip_authorization_check
before_action :load_template
@@ -2,6 +2,8 @@
class StorageSettingsController < ApplicationController
before_action :load_encrypted_config
authorize_resource :encrypted_config, only: :index
authorize_resource :encrypted_config, parent: false, only: :create
def index; end
+14 -10
View File
@@ -2,19 +2,26 @@
class SubmissionsController < ApplicationController
before_action :load_template, only: %i[new create]
authorize_resource :template, only: %i[new create]
load_and_authorize_resource :submission, only: %i[show destroy]
def show
@submission =
Submission.joins(:template).where(template: { account_id: current_account.id })
.preload(:template, template_schema_documents: [:blob, { preview_images_attachments: :blob }])
.find(params[:id])
ActiveRecord::Associations::Preloader.new(
records: [@submission],
associations: [:template, { template_schema_documents: [:blob, { preview_images_attachments: :blob }] }]
).call
render :show, layout: 'plain'
end
def new; end
def new
authorize!(:new, Submission)
end
def create
authorize!(:create, Submission)
submissions =
if params[:emails].present?
Submissions.create_from_emails(template: @template,
@@ -37,12 +44,9 @@ class SubmissionsController < ApplicationController
end
def destroy
submission = Submission.joins(:template).where(template: { account_id: current_account.id })
.find(params[:id])
@submission.update!(deleted_at: Time.current)
submission.update!(deleted_at: Time.current)
redirect_back(fallback_location: template_path(submission.template), notice: 'Submission has been archived')
redirect_back(fallback_location: template_path(@submission.template), notice: 'Submission has been archived')
end
private
@@ -4,6 +4,7 @@ class SubmissionsDebugController < ApplicationController
layout 'plain'
skip_before_action :authenticate_user!
skip_authorization_check
def index
@submitter = Submitter.preload({ attachments_attachments: :blob },
@@ -2,6 +2,7 @@
class SubmissionsDownloadController < ApplicationController
skip_before_action :authenticate_user!
skip_authorization_check
def index
submitter = Submitter.find_by(slug: params[:submitter_slug])
@@ -1,13 +1,14 @@
# frozen_string_literal: true
class SubmissionsExportController < ApplicationController
before_action :load_template
load_and_authorize_resource :template
load_and_authorize_resource :submission, through: :template, parent: false, only: :index
def index
submissions = @template.submissions.active
.preload(submitters: { documents_attachments: :blob,
attachments_attachments: :blob })
.order(id: :asc)
submissions = @submissions.active
.preload(submitters: { documents_attachments: :blob,
attachments_attachments: :blob })
.order(id: :asc)
if params[:format] == 'csv'
send_data Submissions::GenerateExportFiles.call(submissions, format: params[:format]),
@@ -19,10 +20,4 @@ class SubmissionsExportController < ApplicationController
end
def new; end
private
def load_template
@template = current_account.templates.find(params[:template_id])
end
end
@@ -4,6 +4,7 @@ class SubmitFormController < ApplicationController
layout 'form'
skip_before_action :authenticate_user!
skip_authorization_check
def show
@submitter =
@@ -1,18 +1,16 @@
# frozen_string_literal: true
class SubmittersSendEmailController < ApplicationController
load_and_authorize_resource :submitter, id_param: :submitter_slug, find_by: :slug
def create
submitter = Submitter.joins(:template)
.where(template: { account_id: current_account.id })
.find_by!(slug: params[:submitter_slug])
SubmitterMailer.invitation_email(@submitter).deliver_later!
SubmitterMailer.invitation_email(submitter).deliver_later!
SubmissionEvent.create!(submitter: @submitter, event_type: 'send_email')
SubmissionEvent.create!(submitter:, event_type: 'send_email')
@submitter.sent_at ||= Time.current
@submitter.save!
submitter.sent_at ||= Time.current
submitter.save!
redirect_back(fallback_location: submission_path(submitter.submission), notice: 'Email has been sent')
redirect_back(fallback_location: submission_path(@submitter.submission), notice: 'Email has been sent')
end
end
@@ -1,10 +1,12 @@
# frozen_string_literal: true
class TemplatesArchivedController < ApplicationController
def index
templates = current_account.templates.where.not(deleted_at: nil).preload(:author).order(id: :desc)
templates = Templates.search(templates, params[:q])
load_and_authorize_resource :template, parent: false
@pagy, @templates = pagy(templates, items: 12)
def index
@templates = @templates.where.not(deleted_at: nil).preload(:author).order(id: :desc)
@templates = Templates.search(@templates, params[:q])
@pagy, @templates = pagy(@templates, items: 12)
end
end
@@ -1,13 +1,14 @@
# frozen_string_literal: true
class TemplatesArchivedSubmissionsController < ApplicationController
def show
@template = current_account.templates.find(params[:template_id])
load_and_authorize_resource :template
load_and_authorize_resource :submission, through: :template, parent: false
submissions = @template.submissions.where.not(deleted_at: nil)
submissions = Submissions.search(submissions, params[:q])
def index
@submissions = @submissions.where.not(deleted_at: nil)
@submissions = Submissions.search(@submissions, params[:q])
@pagy, @submissions = pagy(submissions.preload(:submitters).order(id: :desc))
@pagy, @submissions = pagy(@submissions.preload(:submitters).order(id: :desc))
rescue ActiveRecord::RecordNotFound
redirect_to root_path
end
+7 -9
View File
@@ -1,10 +1,11 @@
# frozen_string_literal: true
class TemplatesController < ApplicationController
load_and_authorize_resource :template
before_action :load_base_template, only: %i[new create]
def show
@template = current_account.templates.find(params[:id])
submissions = @template.submissions
submissions = submissions.active if @template.deleted_at.blank?
submissions = Submissions.search(submissions, params[:q])
@@ -15,19 +16,19 @@ class TemplatesController < ApplicationController
end
def new
@template = current_account.templates.new
@template.name = "#{@base_template.name} (Clone)" if @base_template
end
def edit
@template = current_account.templates.preload(schema_documents: { preview_images_attachments: :blob })
.find(params[:id])
ActiveRecord::Associations::Preloader.new(
records: [@template],
associations: [schema_documents: { preview_images_attachments: :blob }]
).call
render :edit, layout: 'plain'
end
def create
@template = current_account.templates.new(template_params)
@template.author = current_user
@template.assign_attributes(@base_template.slice(:fields, :schema, :submitters)) if @base_template
@@ -41,7 +42,6 @@ class TemplatesController < ApplicationController
end
def destroy
@template = current_account.templates.find(params[:id])
@template.update!(deleted_at: Time.current)
redirect_back(fallback_location: root_path, notice: 'Template has been archived.')
@@ -56,8 +56,6 @@ class TemplatesController < ApplicationController
def load_base_template
return if params[:base_template_id].blank?
@base_template = current_account.templates
.preload(documents_attachments: :preview_images_attachments)
.find_by(id: params[:base_template_id])
@base_template = current_account.templates.find_by(id: params[:base_template_id])
end
end
@@ -1,11 +1,11 @@
# frozen_string_literal: true
class TemplatesRestoreController < ApplicationController
load_and_authorize_resource :template
def create
template = current_account.templates.find(params[:template_id])
@template.update!(deleted_at: nil)
template.update!(deleted_at: nil)
redirect_to template_path(template), notice: 'Template has been unarchived'
redirect_to template_path(@template), notice: 'Template has been unarchived'
end
end
@@ -1,18 +1,20 @@
# frozen_string_literal: true
class TemplatesUploadsController < ApplicationController
load_and_authorize_resource :template, parent: false
def create
template = current_account.templates.new(author: current_user)
template.name = File.basename(params[:files].first.original_filename, '.*')
@template.author = current_user
@template.name = File.basename(params[:files].first.original_filename, '.*')
template.save!
@template.save!
documents = Templates::CreateAttachments.call(template, params)
documents = Templates::CreateAttachments.call(@template, params)
schema = documents.map { |doc| { attachment_uuid: doc.uuid, name: doc.filename.base } }
template.update!(schema:)
@template.update!(schema:)
redirect_to edit_template_path(template)
redirect_to edit_template_path(@template)
end
end
+17 -16
View File
@@ -1,26 +1,20 @@
# frozen_string_literal: true
class UsersController < ApplicationController
before_action :load_user, only: %i[edit update destroy]
load_and_authorize_resource :user, only: %i[index edit new update destroy]
before_action :build_user, only: :create
authorize_resource :user, only: :create
def index
@pagy, @users = pagy(current_account.users.active.order(id: :desc))
@pagy, @users = pagy(@users.active.order(id: :desc))
end
def new
@user = current_account.users.new
end
def new; end
def edit; end
def create
@user = current_account.users.find_by(email: user_params[:email])&.tap do |user|
user.assign_attributes(user_params)
user.deleted_at = nil
end
@user ||= current_account.users.new(user_params)
if @user.save
UserMailer.invitation_email(@user).deliver_later!
@@ -33,7 +27,7 @@ class UsersController < ApplicationController
def update
return redirect_to settings_users_path, notice: 'Unable to update user.' if Docuseal.demo?
if @user.update(user_params.compact_blank)
if @user.update(user_params.compact_blank.except(current_user == @user ? :role : nil))
redirect_to settings_users_path, notice: 'User has been updated'
else
render turbo_stream: turbo_stream.replace(:modal, template: 'users/edit'), status: :unprocessable_entity
@@ -52,11 +46,18 @@ class UsersController < ApplicationController
private
def load_user
@user = current_account.users.find(params[:id])
def build_user
@user = current_account.users.find_by(email: user_params[:email])&.tap do |user|
user.assign_attributes(user_params)
user.deleted_at = nil
end
@user ||= current_account.users.new(user_params)
@user
end
def user_params
params.require(:user).permit(:email, :first_name, :last_name, :password)
params.require(:user).permit(:email, :first_name, :last_name, :password, :role)
end
end
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class VerifyPdfSignatureController < ApplicationController
skip_authorization_check
def create
pdfs =
params[:files].map do |file|
@@ -1,15 +1,12 @@
# frozen_string_literal: true
class WebhookSettingsController < ApplicationController
def show
@encrypted_config =
current_account.encrypted_configs.find_or_initialize_by(key: EncryptedConfig::WEBHOOK_URL_KEY)
end
before_action :load_encrypted_config
authorize_resource :encrypted_config, parent: false
def show; end
def create
@encrypted_config =
current_account.encrypted_configs.find_or_initialize_by(key: EncryptedConfig::WEBHOOK_URL_KEY)
@encrypted_config.update!(encrypted_config_params)
redirect_back(fallback_location: settings_webhooks_path, notice: 'Webhook URL has been saved.')
@@ -25,6 +22,11 @@ class WebhookSettingsController < ApplicationController
private
def load_encrypted_config
@encrypted_config =
current_account.encrypted_configs.find_or_initialize_by(key: EncryptedConfig::WEBHOOK_URL_KEY)
end
def encrypted_config_params
params.require(:encrypted_config).permit(:value)
end