intercom-rails 1.0.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +48 -1
- data/lib/intercom-rails/config.rb +10 -0
- data/lib/intercom-rails/script_tag.rb +49 -7
- data/lib/intercom-rails/version.rb +1 -1
- metadata +22 -22
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ff14436633adc07b04ea0fff8507abf54e6fd34e4c4ab943c3a26aa691d69801
|
|
4
|
+
data.tar.gz: 7fe20bd0ce9cff4efe03a935886b43ac8bed8f56366e75f1733a5948f7145299
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 744323aa7316eebe9923ef4a15897e6cf0ee24fda86e42f19ee865f1050e09840a4921be0b8f706a4fd610d66d584f4155a83a7483686949ec46e858ca2a9623
|
|
7
|
+
data.tar.gz: a93f75e039d873083243e3c847b8ccc4e2f35e812c4e05d5423fca83c36419aa908348003770133384044629584e63d4f55feafa6ff6b9f68e9d4b172274e2e0
|
data/README.md
CHANGED
|
@@ -69,6 +69,53 @@ It is possible to enable Identity Verification for the Intercom Messenger and yo
|
|
|
69
69
|
```
|
|
70
70
|
**Note: This example is just for the sake of simplicity, you should never include this secret in source control. Instead, you should use the Rails [secret config](http://guides.rubyonrails.org/4_1_release_notes.html#config-secrets-yml) feature.**
|
|
71
71
|
|
|
72
|
+
### JWT Authentication
|
|
73
|
+
You can enable JWT authentication for enhanced security with the Intercom Messenger. This feature uses JSON Web Tokens (JWTs) to authenticate users instead of the traditional user_hash method. To enable JWT authentication, add the following to your `config/initializers/intercom.rb`:
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
config.jwt.enabled = true
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
#### JWT Expiry
|
|
80
|
+
You can set an expiry time for JWTs. This determines how long the token remains valid:
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
config.jwt.expiry = 12.hours # Token expires after 12 hours
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
If no expiry is set, the JWT will not include an expiration claim.
|
|
87
|
+
|
|
88
|
+
#### Signed User Fields
|
|
89
|
+
You can specify which user fields should be included in the JWT payload and removed from the client-side settings for enhanced security:
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
config.jwt.signed_user_fields = [:email, :name, :plan, :team_id]
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
With this configuration, these fields will be:
|
|
96
|
+
- Included in the signed JWT payload
|
|
97
|
+
- Removed from the client-side `intercomSettings` object
|
|
98
|
+
- Still available to Intercom through the secure JWT
|
|
99
|
+
|
|
100
|
+
#### Per-Request JWT Configuration
|
|
101
|
+
You can also configure JWT settings on a per-request basis using the `intercom_script_tag` helper:
|
|
102
|
+
|
|
103
|
+
```erb
|
|
104
|
+
<%= intercom_script_tag({
|
|
105
|
+
:user_id => current_user.id,
|
|
106
|
+
:email => current_user.email
|
|
107
|
+
}, {
|
|
108
|
+
:jwt_enabled => true,
|
|
109
|
+
:jwt_expiry => 1.hour
|
|
110
|
+
}) %>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Important Notes:**
|
|
114
|
+
- JWT authentication requires an `api_secret` to be configured
|
|
115
|
+
- JWT is only generated when a `user_id` is present
|
|
116
|
+
- When JWT is enabled, the `user_id` is removed from client-side settings and only included in the secure JWT
|
|
117
|
+
- Other configured signed fields are also removed from client-side settings when JWT is used
|
|
118
|
+
|
|
72
119
|
### Shutdown
|
|
73
120
|
We make use of first-party cookies so that we can identify your users the next time they open your messenger. When people share devices with someone else, they might be able to see the most recently logged in user’s conversation history until the cookie expires. Because of this, it’s very important to properly shutdown Intercom when a user’s session on your app ends (either manually or due to an automated logout).
|
|
74
121
|
|
|
@@ -342,7 +389,7 @@ CSP support for automatic insertion exposes two namespaces that can be defined b
|
|
|
342
389
|
- String CoreExtensions::IntercomRails::AutoInclude.csp_nonce_hook(controller)
|
|
343
390
|
- nil CoreExtensions::IntercomRails::AutoInclude.csp_sha256_hook(controller, SHA-256 whitelist entry)
|
|
344
391
|
|
|
345
|
-
For instance, a CSP nonce can be inserted using the [
|
|
392
|
+
For instance, a CSP nonce can be inserted using the [Github Secure Headers](https://github.com/github/secure_headers) gem with the following code:
|
|
346
393
|
```ruby
|
|
347
394
|
module CoreExtensions
|
|
348
395
|
module IntercomRails
|
|
@@ -143,6 +143,16 @@ module IntercomRails
|
|
|
143
143
|
end
|
|
144
144
|
end
|
|
145
145
|
|
|
146
|
+
config_group :jwt do
|
|
147
|
+
config_accessor :enabled
|
|
148
|
+
config_accessor :expiry
|
|
149
|
+
config_accessor :signed_user_fields do |value|
|
|
150
|
+
unless value.nil? || (value.kind_of?(Array) && value.all? { |v| v.kind_of?(Symbol) || v.kind_of?(String) })
|
|
151
|
+
raise ArgumentError, "jwt.signed_user_fields must be an array of symbols or strings"
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
146
156
|
end
|
|
147
157
|
|
|
148
158
|
end
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'active_support/all'
|
|
4
4
|
require 'action_view'
|
|
5
|
+
require 'jwt'
|
|
5
6
|
|
|
6
7
|
module IntercomRails
|
|
7
8
|
|
|
@@ -17,7 +18,7 @@ module IntercomRails
|
|
|
17
18
|
include ::ActionView::Helpers::TagHelper
|
|
18
19
|
|
|
19
20
|
attr_reader :user_details, :company_details, :show_everywhere, :session_duration
|
|
20
|
-
attr_accessor :secret, :widget_options, :controller, :nonce, :encrypted_mode_enabled, :encrypted_mode
|
|
21
|
+
attr_accessor :secret, :widget_options, :controller, :nonce, :encrypted_mode_enabled, :encrypted_mode, :jwt_enabled, :jwt_expiry
|
|
21
22
|
|
|
22
23
|
def initialize(options = {})
|
|
23
24
|
self.secret = options[:secret] || Config.api_secret
|
|
@@ -25,14 +26,22 @@ module IntercomRails
|
|
|
25
26
|
self.controller = options[:controller]
|
|
26
27
|
@show_everywhere = options[:show_everywhere]
|
|
27
28
|
@session_duration = session_duration_from_config
|
|
28
|
-
self.
|
|
29
|
+
self.jwt_enabled = options[:jwt_enabled] || Config.jwt.enabled
|
|
30
|
+
self.jwt_expiry = options[:jwt_expiry] || Config.jwt.expiry
|
|
31
|
+
|
|
32
|
+
initial_user_details = if options[:find_current_user_details]
|
|
33
|
+
find_current_user_details
|
|
34
|
+
else
|
|
35
|
+
options[:user_details] || {}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
lead_attributes = find_lead_attributes
|
|
39
|
+
|
|
40
|
+
self.user_details = initial_user_details.merge(lead_attributes)
|
|
29
41
|
|
|
30
42
|
self.encrypted_mode_enabled = options[:encrypted_mode] || Config.encrypted_mode
|
|
31
43
|
self.encrypted_mode = IntercomRails::EncryptedMode.new(secret, options[:initialization_vector], {:enabled => encrypted_mode_enabled})
|
|
32
44
|
|
|
33
|
-
# Request specific custom data for non-signed up users base on lead_attributes
|
|
34
|
-
self.user_details = self.user_details.merge(find_lead_attributes)
|
|
35
|
-
|
|
36
45
|
self.company_details = if options[:find_current_company_details]
|
|
37
46
|
find_current_company_details
|
|
38
47
|
elsif options[:user_details]
|
|
@@ -45,7 +54,7 @@ module IntercomRails
|
|
|
45
54
|
return false if user_details[:excluded_user] == true
|
|
46
55
|
valid = user_details[:app_id].present?
|
|
47
56
|
unless @show_everywhere
|
|
48
|
-
valid = valid &&
|
|
57
|
+
valid = valid && @has_identity
|
|
49
58
|
end
|
|
50
59
|
if nonce
|
|
51
60
|
valid = valid && valid_nonce?
|
|
@@ -113,12 +122,45 @@ module IntercomRails
|
|
|
113
122
|
"window.intercomSettings = #{plaintext_javascript};#{intercom_encrypted_payload_javascript}(function(){var w=window;var ic=w.Intercom;if(typeof ic===\"function\"){ic('update',intercomSettings);}else{var d=document;var i=function(){i.c(arguments)};i.q=[];i.c=function(args){i.q.push(args)};w.Intercom=i;function l(){var s=d.createElement('script');s.type='text/javascript';s.async=true;s.src='#{Config.library_url || "https://widget.intercom.io/widget/#{j app_id}"}';var x=d.getElementsByTagName('script')[0];x.parentNode.insertBefore(s,x);}if(document.readyState==='complete'){l();}else if(w.attachEvent){w.attachEvent('onload',l);}else{w.addEventListener('load',l,false);}};})()"
|
|
114
123
|
end
|
|
115
124
|
|
|
125
|
+
def generate_jwt
|
|
126
|
+
return nil unless user_details[:user_id].present?
|
|
127
|
+
|
|
128
|
+
payload = { user_id: user_details[:user_id].to_s }
|
|
129
|
+
|
|
130
|
+
if jwt_expiry
|
|
131
|
+
payload[:exp] = jwt_expiry.from_now.to_i
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
if Config.jwt.signed_user_fields.present?
|
|
135
|
+
Config.jwt.signed_user_fields.each do |field|
|
|
136
|
+
field = field.to_sym
|
|
137
|
+
payload[field] = user_details[field].to_s if user_details[field].present?
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
JWT.encode(payload, secret, 'HS256')
|
|
142
|
+
end
|
|
143
|
+
|
|
116
144
|
def user_details=(user_details)
|
|
117
145
|
@user_details = DateHelper.convert_dates_to_unix_timestamps(user_details || {})
|
|
118
146
|
@user_details = @user_details.with_indifferent_access.tap do |u|
|
|
119
147
|
[:email, :name, :user_id].each { |k| u.delete(k) if u[k].nil? }
|
|
120
148
|
|
|
121
|
-
|
|
149
|
+
@has_identity = (u[:user_id] || u[:email]).present?
|
|
150
|
+
|
|
151
|
+
if secret.present?
|
|
152
|
+
if jwt_enabled && u[:user_id].present?
|
|
153
|
+
u[:intercom_user_jwt] ||= generate_jwt
|
|
154
|
+
|
|
155
|
+
u.delete(:user_id)
|
|
156
|
+
Config.jwt.signed_user_fields&.each do |field|
|
|
157
|
+
u.delete(field.to_sym)
|
|
158
|
+
end
|
|
159
|
+
elsif (u[:user_id] || u[:email]).present?
|
|
160
|
+
u[:user_hash] ||= user_hash
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
122
164
|
u[:app_id] ||= app_id
|
|
123
165
|
end
|
|
124
166
|
end
|
metadata
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: intercom-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ben McRedmond
|
|
8
8
|
- Ciaran Lee
|
|
9
9
|
- Darragh Curran
|
|
10
|
-
autorequire:
|
|
10
|
+
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date:
|
|
13
|
+
date: 2026-04-20 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: activesupport
|
|
@@ -26,6 +26,20 @@ dependencies:
|
|
|
26
26
|
- - ">"
|
|
27
27
|
- !ruby/object:Gem::Version
|
|
28
28
|
version: '4.0'
|
|
29
|
+
- !ruby/object:Gem::Dependency
|
|
30
|
+
name: jwt
|
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
|
32
|
+
requirements:
|
|
33
|
+
- - ">="
|
|
34
|
+
- !ruby/object:Gem::Version
|
|
35
|
+
version: '2.0'
|
|
36
|
+
type: :runtime
|
|
37
|
+
prerelease: false
|
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
- - ">="
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: '2.0'
|
|
29
43
|
- !ruby/object:Gem::Dependency
|
|
30
44
|
name: rake
|
|
31
45
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -102,28 +116,14 @@ dependencies:
|
|
|
102
116
|
requirements:
|
|
103
117
|
- - "~>"
|
|
104
118
|
- !ruby/object:Gem::Version
|
|
105
|
-
version: '
|
|
106
|
-
type: :development
|
|
107
|
-
prerelease: false
|
|
108
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
109
|
-
requirements:
|
|
110
|
-
- - "~>"
|
|
111
|
-
- !ruby/object:Gem::Version
|
|
112
|
-
version: '2.0'
|
|
113
|
-
- !ruby/object:Gem::Dependency
|
|
114
|
-
name: thin
|
|
115
|
-
requirement: !ruby/object:Gem::Requirement
|
|
116
|
-
requirements:
|
|
117
|
-
- - "~>"
|
|
118
|
-
- !ruby/object:Gem::Version
|
|
119
|
-
version: 1.8.0
|
|
119
|
+
version: '3.0'
|
|
120
120
|
type: :development
|
|
121
121
|
prerelease: false
|
|
122
122
|
version_requirements: !ruby/object:Gem::Requirement
|
|
123
123
|
requirements:
|
|
124
124
|
- - "~>"
|
|
125
125
|
- !ruby/object:Gem::Version
|
|
126
|
-
version:
|
|
126
|
+
version: '3.0'
|
|
127
127
|
- !ruby/object:Gem::Dependency
|
|
128
128
|
name: tzinfo
|
|
129
129
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -187,7 +187,7 @@ homepage: http://www.intercom.io
|
|
|
187
187
|
licenses:
|
|
188
188
|
- MIT
|
|
189
189
|
metadata: {}
|
|
190
|
-
post_install_message:
|
|
190
|
+
post_install_message:
|
|
191
191
|
rdoc_options: []
|
|
192
192
|
require_paths:
|
|
193
193
|
- lib
|
|
@@ -202,8 +202,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
202
202
|
- !ruby/object:Gem::Version
|
|
203
203
|
version: '0'
|
|
204
204
|
requirements: []
|
|
205
|
-
rubygems_version: 3.
|
|
206
|
-
signing_key:
|
|
205
|
+
rubygems_version: 3.0.3.1
|
|
206
|
+
signing_key:
|
|
207
207
|
specification_version: 4
|
|
208
208
|
summary: Rails helper for emitting javascript script tags for Intercom
|
|
209
209
|
test_files: []
|