From 478167ea4f89b34623d7aa4d1b2f2d7680a1b53a Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Mon, 5 Aug 2024 13:30:04 +0300 Subject: [PATCH] add webhook secret --- app/controllers/webhook_secret_controller.rb | 29 +++++++++++++++++++ ...send_form_completed_webhook_request_job.rb | 14 ++++++--- .../send_form_started_webhook_request_job.rb | 5 +++- .../send_form_viewed_webhook_request_job.rb | 5 +++- ...submission_archived_webhook_request_job.rb | 6 +++- ..._submission_created_webhook_request_job.rb | 6 +++- ...nd_template_created_webhook_request_job.rb | 6 +++- ...nd_template_updated_webhook_request_job.rb | 6 +++- app/models/encrypted_config.rb | 3 +- app/views/webhook_secret/index.html.erb | 19 ++++++++++++ app/views/webhook_settings/show.html.erb | 5 +++- config/routes.rb | 1 + 12 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 app/controllers/webhook_secret_controller.rb create mode 100644 app/views/webhook_secret/index.html.erb diff --git a/app/controllers/webhook_secret_controller.rb b/app/controllers/webhook_secret_controller.rb new file mode 100644 index 000000000..12c1edae2 --- /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 1012c60ac..62c6e1d57 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 @@ def perform(params = {}) 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 @@ def perform(params = {}) 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 @@ def perform(params = {}) 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 @@ def load_url(submitter, params) 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 9bf8f6c83..747e93388 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 @@ def perform(params = {}) 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 @@ def perform(params = {}) 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 9cf6cc545..391064e31 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 @@ def perform(params = {}) 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 @@ def perform(params = {}) 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 76273ceec..ff62419eb 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 @@ def perform(params = {}) 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 @@ def perform(params = {}) 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 e5ec70700..aeb3f18ff 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 @@ def perform(params = {}) 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 @@ def perform(params = {}) 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 ed6434509..e2d7ac714 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 @@ def perform(params = {}) 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 @@ def perform(params = {}) 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 638ba196b..8d969eb5b 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 @@ def perform(params = {}) 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 @@ def perform(params = {}) 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 f3c364415..5d2422af9 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 000000000..5c7ad9edb --- /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 c9b1e3c1d..b05dbe0cd 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 7874959f6..2de99d5f9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -75,6 +75,7 @@ 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'