From feb0c3b17364b7de9a033f9160cec2af0f488496 Mon Sep 17 00:00:00 2001 From: Joshua Klina Date: Wed, 3 Sep 2025 16:15:06 -0400 Subject: [PATCH] Ensure that signed fields maintain validity The script tag checks for validity by making sure there's a `user_id` or an `email`. When using signed fields, however, these fields are removed from the `user_details` hash, so each time both the `user_id` and the `email` fields are promoted to the JWT payload, they will invalidate the script tag even though the information is there, just moved into the payload. This attempts to fix the issue by ensuring the state of the `user_fields` hash is maintained for validation purposes. --- lib/intercom-rails/script_tag.rb | 14 ++++++++------ spec/script_tag_spec.rb | 9 +++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/lib/intercom-rails/script_tag.rb b/lib/intercom-rails/script_tag.rb index 3f368af..39238ec 100644 --- a/lib/intercom-rails/script_tag.rb +++ b/lib/intercom-rails/script_tag.rb @@ -17,8 +17,8 @@ class ScriptTag include ::ActionView::Helpers::JavaScriptHelper include ::ActionView::Helpers::TagHelper - attr_reader :user_details, :company_details, :show_everywhere, :session_duration - attr_accessor :secret, :widget_options, :controller, :nonce, :encrypted_mode_enabled, :encrypted_mode, :jwt_enabled, :jwt_expiry + attr_reader :published_user_details, :company_details, :show_everywhere, :session_duration + attr_accessor :user_details, :secret, :widget_options, :controller, :nonce, :encrypted_mode_enabled, :encrypted_mode, :jwt_enabled, :jwt_expiry def initialize(options = {}) self.secret = options[:secret] || Config.api_secret @@ -38,6 +38,8 @@ def initialize(options = {}) lead_attributes = find_lead_attributes self.user_details = initial_user_details.merge(lead_attributes) + user_details[:app_id] = app_id + @published_user_details = sanitize_user_details(user_details) self.encrypted_mode_enabled = options[:encrypted_mode] || Config.encrypted_mode self.encrypted_mode = IntercomRails::EncryptedMode.new(secret, options[:initialization_vector], {:enabled => encrypted_mode_enabled}) @@ -73,7 +75,7 @@ def valid_nonce? end def intercom_settings - hsh = user_details + hsh = published_user_details hsh[:session_duration] = @session_duration if @session_duration.present? hsh[:widget] = widget_options if widget_options.present? hsh[:company] = company_details if company_details.present? @@ -141,9 +143,9 @@ def generate_jwt JWT.encode(payload, secret, 'HS256') end - def user_details=(user_details) - @user_details = DateHelper.convert_dates_to_unix_timestamps(user_details || {}) - @user_details = @user_details.with_indifferent_access.tap do |u| + def sanitize_user_details(user_details) + sanitize_user_details = DateHelper.convert_dates_to_unix_timestamps(user_details || {}) + sanitize_user_details.with_indifferent_access.tap do |u| [:email, :name, :user_id].each { |k| u.delete(k) if u[k].nil? } if secret.present? diff --git a/spec/script_tag_spec.rb b/spec/script_tag_spec.rb index 2f385eb..a752901 100644 --- a/spec/script_tag_spec.rb +++ b/spec/script_tag_spec.rb @@ -313,6 +313,7 @@ def user user_details: { user_id: '1234' }, jwt_enabled: false ) + expect(script_tag).to be_valid expect(script_tag.intercom_settings[:intercom_user_jwt]).to be_nil end @@ -321,6 +322,7 @@ def user user_details: { user_id: '1234' }, jwt_enabled: true ) + expect(script_tag).to be_valid expect(script_tag.intercom_settings[:intercom_user_jwt]).to be_present end @@ -329,6 +331,7 @@ def user user_details: { user_id: '1234' }, jwt_enabled: true ) + expect(script_tag).to be_valid expect(script_tag.intercom_settings[:user_hash]).to be_nil end @@ -339,6 +342,7 @@ def user jwt_enabled: true ) + expect(script_tag).to be_valid jwt = script_tag.intercom_settings[:intercom_user_jwt] decoded_payload = JWT.decode(jwt, 'super-secret', true, { algorithm: 'HS256' })[0] @@ -350,6 +354,7 @@ def user user_details: { email: 'test@example.com' }, jwt_enabled: true ) + expect(script_tag).to be_valid expect(script_tag.intercom_settings[:intercom_user_jwt]).to be_nil end @@ -359,6 +364,7 @@ def user user_details: { user_id: '1234' }, jwt_enabled: true ) + expect(script_tag).to be_valid expect(script_tag.intercom_settings[:intercom_user_jwt]).to be_nil end @@ -372,6 +378,7 @@ def user jwt_enabled: true ) + expect(script_tag).to be_valid expect(script_tag.intercom_settings[:intercom_user_jwt]).to be_present expect(script_tag.intercom_settings[:user_id]).to be_nil expect(script_tag.intercom_settings[:email]).to eq('test@example.com') @@ -388,6 +395,7 @@ def user jwt_enabled: false ) + expect(script_tag).to be_valid expect(script_tag.intercom_settings[:user_id]).to eq('1234') expect(script_tag.intercom_settings[:email]).to eq('test@example.com') expect(script_tag.intercom_settings[:name]).to eq('Test User') @@ -410,6 +418,7 @@ def user jwt_enabled: true ) + expect(script_tag).to be_valid jwt = script_tag.intercom_settings[:intercom_user_jwt] decoded_payload = JWT.decode(jwt, 'super-secret', true, { algorithm: 'HS256' })[0]