diff --git a/app/controllers/webhook_secret_controller.rb b/app/controllers/webhook_secret_controller.rb new file mode 100644 index 00000000..12c1edae --- /dev/null +++ b/app/controllers/webhook_secret_controller.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class WebhookSecretController < ApplicationController + before_action :load_encrypted_config + authorize_resource :encrypted_config, parent: false + + def index; end + + def create + @encrypted_config.assign_attributes(value: { + encrypted_config_params[:key] => encrypted_config_params[:value] + }.compact_blank) + + @encrypted_config.value.present? ? @encrypted_config.save! : @encrypted_config.delete + + redirect_back(fallback_location: settings_webhooks_path, notice: 'Webhook Secret has been saved.') + end + + private + + def load_encrypted_config + @encrypted_config = + current_account.encrypted_configs.find_or_initialize_by(key: EncryptedConfig::WEBHOOK_SECRET_KEY) + end + + def encrypted_config_params + params.require(:encrypted_config).permit(value: %i[key value]).fetch(:value, {}) + end +end diff --git a/app/jobs/send_form_completed_webhook_request_job.rb b/app/jobs/send_form_completed_webhook_request_job.rb index 1012c60a..62c6e1d5 100644 --- a/app/jobs/send_form_completed_webhook_request_job.rb +++ b/app/jobs/send_form_completed_webhook_request_job.rb @@ -14,7 +14,7 @@ class SendFormCompletedWebhookRequestJob attempt = params['attempt'].to_i - url = load_url(submitter, params) + url, secret = load_url_and_secret(submitter, params) return if url.blank? @@ -29,6 +29,7 @@ class SendFormCompletedWebhookRequestJob timestamp: Time.current, data: Submitters::SerializeForWebhook.call(submitter) }.to_json, + **secret.to_h, 'Content-Type' => 'application/json', 'User-Agent' => USER_AGENT) rescue Faraday::Error @@ -45,9 +46,11 @@ class SendFormCompletedWebhookRequestJob end end - def load_url(submitter, params) + def load_url_and_secret(submitter, params) if params['encrypted_config_id'] - url = EncryptedConfig.find(params['encrypted_config_id']).value + config = EncryptedConfig.find(params['encrypted_config_id']) + + url = config.value return if url.blank? @@ -55,7 +58,10 @@ class SendFormCompletedWebhookRequestJob return if preferences['form.completed'] == false - url + secret = EncryptedConfig.find_or_initialize_by(account_id: config.account_id, + key: EncryptedConfig::WEBHOOK_SECRET_KEY)&.value.to_h + + [url, secret] elsif params['webhook_url_id'] webhook_url = submitter.account.webhook_urls.find(params['webhook_url_id']) diff --git a/app/jobs/send_form_started_webhook_request_job.rb b/app/jobs/send_form_started_webhook_request_job.rb index 9bf8f6c8..747e9338 100644 --- a/app/jobs/send_form_started_webhook_request_job.rb +++ b/app/jobs/send_form_started_webhook_request_job.rb @@ -13,7 +13,8 @@ class SendFormStartedWebhookRequestJob submitter = Submitter.find(params['submitter_id']) attempt = params['attempt'].to_i - url = Accounts.load_webhook_url(submitter.submission.account) + config = Accounts.load_webhook_config(submitter.submission.account) + url = config&.value.presence return if url.blank? @@ -30,6 +31,8 @@ class SendFormStartedWebhookRequestJob timestamp: Time.current, data: Submitters::SerializeForWebhook.call(submitter) }.to_json, + **EncryptedConfig.find_or_initialize_by(account_id: config.account_id, + key: EncryptedConfig::WEBHOOK_SECRET_KEY)&.value.to_h, 'Content-Type' => 'application/json', 'User-Agent' => USER_AGENT) rescue Faraday::Error diff --git a/app/jobs/send_form_viewed_webhook_request_job.rb b/app/jobs/send_form_viewed_webhook_request_job.rb index 9cf6cc54..391064e3 100644 --- a/app/jobs/send_form_viewed_webhook_request_job.rb +++ b/app/jobs/send_form_viewed_webhook_request_job.rb @@ -13,7 +13,8 @@ class SendFormViewedWebhookRequestJob submitter = Submitter.find(params['submitter_id']) attempt = params['attempt'].to_i - url = Accounts.load_webhook_url(submitter.submission.account) + config = Accounts.load_webhook_config(submitter.submission.account) + url = config&.value.presence return if url.blank? @@ -30,6 +31,8 @@ class SendFormViewedWebhookRequestJob timestamp: Time.current, data: Submitters::SerializeForWebhook.call(submitter) }.to_json, + **EncryptedConfig.find_or_initialize_by(account_id: config.account_id, + key: EncryptedConfig::WEBHOOK_SECRET_KEY)&.value.to_h, 'Content-Type' => 'application/json', 'User-Agent' => USER_AGENT) rescue Faraday::Error diff --git a/app/jobs/send_submission_archived_webhook_request_job.rb b/app/jobs/send_submission_archived_webhook_request_job.rb index 76273cee..ff62419e 100644 --- a/app/jobs/send_submission_archived_webhook_request_job.rb +++ b/app/jobs/send_submission_archived_webhook_request_job.rb @@ -13,7 +13,9 @@ class SendSubmissionArchivedWebhookRequestJob submission = Submission.find(params['submission_id']) attempt = params['attempt'].to_i - url = Accounts.load_webhook_url(submission.account) + + config = Accounts.load_webhook_config(submission.account) + url = config&.value.presence return if url.blank? @@ -28,6 +30,8 @@ class SendSubmissionArchivedWebhookRequestJob timestamp: Time.current, data: submission.as_json(only: %i[id archived_at]) }.to_json, + **EncryptedConfig.find_or_initialize_by(account_id: config.account_id, + key: EncryptedConfig::WEBHOOK_SECRET_KEY)&.value.to_h, 'Content-Type' => 'application/json', 'User-Agent' => USER_AGENT) rescue Faraday::Error diff --git a/app/jobs/send_submission_created_webhook_request_job.rb b/app/jobs/send_submission_created_webhook_request_job.rb index e5ec7070..aeb3f18f 100644 --- a/app/jobs/send_submission_created_webhook_request_job.rb +++ b/app/jobs/send_submission_created_webhook_request_job.rb @@ -13,7 +13,9 @@ class SendSubmissionCreatedWebhookRequestJob submission = Submission.find(params['submission_id']) attempt = params['attempt'].to_i - url = Accounts.load_webhook_url(submission.account) + + config = Accounts.load_webhook_config(submission.account) + url = config&.value.presence return if url.blank? @@ -28,6 +30,8 @@ class SendSubmissionCreatedWebhookRequestJob timestamp: Time.current, data: Submissions::SerializeForApi.call(submission) }.to_json, + **EncryptedConfig.find_or_initialize_by(account_id: config.account_id, + key: EncryptedConfig::WEBHOOK_SECRET_KEY)&.value.to_h, 'Content-Type' => 'application/json', 'User-Agent' => USER_AGENT) rescue Faraday::Error diff --git a/app/jobs/send_template_created_webhook_request_job.rb b/app/jobs/send_template_created_webhook_request_job.rb index ed643450..e2d7ac71 100644 --- a/app/jobs/send_template_created_webhook_request_job.rb +++ b/app/jobs/send_template_created_webhook_request_job.rb @@ -13,7 +13,9 @@ class SendTemplateCreatedWebhookRequestJob template = Template.find(params['template_id']) attempt = params['attempt'].to_i - url = Accounts.load_webhook_url(template.account) + + config = Accounts.load_webhook_config(template.account) + url = config&.value.presence return if url.blank? @@ -28,6 +30,8 @@ class SendTemplateCreatedWebhookRequestJob timestamp: Time.current, data: Templates::SerializeForApi.call(template) }.to_json, + **EncryptedConfig.find_or_initialize_by(account_id: config.account_id, + key: EncryptedConfig::WEBHOOK_SECRET_KEY)&.value.to_h, 'Content-Type' => 'application/json', 'User-Agent' => USER_AGENT) rescue Faraday::Error diff --git a/app/jobs/send_template_updated_webhook_request_job.rb b/app/jobs/send_template_updated_webhook_request_job.rb index 638ba196..8d969eb5 100644 --- a/app/jobs/send_template_updated_webhook_request_job.rb +++ b/app/jobs/send_template_updated_webhook_request_job.rb @@ -13,7 +13,9 @@ class SendTemplateUpdatedWebhookRequestJob template = Template.find(params['template_id']) attempt = params['attempt'].to_i - url = Accounts.load_webhook_url(template.account) + + config = Accounts.load_webhook_config(template.account) + url = config&.value.presence return if url.blank? @@ -28,6 +30,8 @@ class SendTemplateUpdatedWebhookRequestJob timestamp: Time.current, data: Templates::SerializeForApi.call(template) }.to_json, + **EncryptedConfig.find_or_initialize_by(account_id: config.account_id, + key: EncryptedConfig::WEBHOOK_SECRET_KEY)&.value.to_h, 'Content-Type' => 'application/json', 'User-Agent' => USER_AGENT) rescue Faraday::Error diff --git a/app/models/encrypted_config.rb b/app/models/encrypted_config.rb index f3c36441..5d2422af 100644 --- a/app/models/encrypted_config.rb +++ b/app/models/encrypted_config.rb @@ -27,7 +27,8 @@ class EncryptedConfig < ApplicationRecord ESIGN_CERTS_KEY = 'esign_certs', TIMESTAMP_SERVER_URL_KEY = 'timestamp_server_url', APP_URL_KEY = 'app_url', - WEBHOOK_URL_KEY = 'webhook_url' + WEBHOOK_URL_KEY = 'webhook_url', + WEBHOOK_SECRET_KEY = 'webhook_secret' ].freeze belongs_to :account diff --git a/app/views/webhook_secret/index.html.erb b/app/views/webhook_secret/index.html.erb new file mode 100644 index 00000000..5c7ad9ed --- /dev/null +++ b/app/views/webhook_secret/index.html.erb @@ -0,0 +1,19 @@ +<%= render 'shared/turbo_modal', title: 'Webhook Secret' do %> + <%= form_for @encrypted_config, url: webhook_secret_index_path, method: :post, html: { class: 'space-y-4' }, data: { turbo_frame: :_top } do |f| %> +
+ <%= f.fields_for :value, Struct.new(:key, :value).new(*@encrypted_config.value.to_a.first) do |ff| %> +
+ <%= ff.label :key, class: 'label' %> + <%= ff.text_field :key, class: 'base-input', placeholder: 'X-Example-Header' %> +
+
+ <%= ff.label :value, class: 'label' %> + <%= ff.text_field :value, class: 'base-input' %> +
+ <% end %> +
+
+ <%= f.button button_title, class: 'base-button' %> +
+ <% end %> +<% end %> diff --git a/app/views/webhook_settings/show.html.erb b/app/views/webhook_settings/show.html.erb index c9b1e3c1..b05dbe0c 100644 --- a/app/views/webhook_settings/show.html.erb +++ b/app/views/webhook_settings/show.html.erb @@ -9,9 +9,12 @@
<%= form_for @encrypted_config, url: settings_webhooks_path, method: :post, html: { autocomplete: 'off' } do |f| %> <%= f.label :value, 'Webhook URL', class: 'text-sm font-semibold' %> -
+
<%= f.url_field :value, class: 'input font-mono input-bordered w-full', placeholder: 'https://example.com/hook' %> <%= f.button button_title(title: 'Save', disabled_with: 'Saving'), class: 'base-button w-full md:w-32' %> + + Add Secret +
<% end %> <% preference = current_account.account_configs.find_by(key: AccountConfig::WEBHOOK_PREFERENCES_KEY)&.value || {} %> diff --git a/config/routes.rb b/config/routes.rb index 7874959f..2de99d5f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -75,6 +75,7 @@ Rails.application.routes.draw do resources :submitters_autocomplete, only: %i[index] resources :template_folders_autocomplete, only: %i[index] resources :webhook_preferences, only: %i[create] + resources :webhook_secret, only: %i[index create] resource :templates_upload, only: %i[create] authenticated do resource :templates_upload, only: %i[show], path: 'new'