-
Notifications
You must be signed in to change notification settings - Fork 107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Encrypted payload support #263
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
module IntercomRails | ||
class EncryptedMode | ||
attr_reader :secret, :initialization_vector, :enabled | ||
|
||
ENCRYPTED_MODE_SETTINGS_WHITELIST = [:app_id, :session_duration, :widget, :custom_launcher_selector, :hide_default_launcher, :alignment, :horizontal_padding, :vertical_padding] | ||
|
||
def initialize(secret, initialization_vector, options) | ||
@secret = secret | ||
@initialization_vector = initialization_vector || SecureRandom.random_bytes(12) | ||
@enabled = options.fetch(:enabled, false) | ||
end | ||
|
||
def plaintext_part(settings) | ||
enabled ? settings.slice(*ENCRYPTED_MODE_SETTINGS_WHITELIST) : settings | ||
end | ||
|
||
def encrypted_javascript(payload) | ||
enabled ? "window.intercomEncryptedPayload = \"#{encrypt(payload)}\";" : "" | ||
end | ||
|
||
def encrypt(payload) | ||
return nil unless enabled | ||
payload = payload.except(*ENCRYPTED_MODE_SETTINGS_WHITELIST) | ||
key = Digest::SHA256.digest(secret) | ||
cipher = OpenSSL::Cipher.new('aes-256-gcm') | ||
cipher.encrypt | ||
cipher.key = key | ||
cipher.iv = initialization_vector | ||
json = ActiveSupport::JSON.encode(payload).gsub('<', '\u003C') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pretty sure that this gsub is not necessary as the results are encrypted and Base64'd anyway. However retaining it for now. |
||
encrypted = initialization_vector + cipher.update(json) + cipher.final + cipher.auth_tag | ||
Base64.encode64(encrypted).gsub("\n", "\\n") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is just so that the result can be interpolated as JavaScript without a syntax error caused by line breaks. |
||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
require 'spec_helper' | ||
|
||
describe IntercomRails::EncryptedMode do | ||
it 'whitelists certain attributes' do | ||
encrypted_mode = IntercomRails::EncryptedMode.new("foo", nil, {:enabled => true}) | ||
expect(encrypted_mode.plaintext_part({:app_id => "bar", :baz => "bang"})).to eq({:app_id => "bar"}) | ||
end | ||
|
||
it "encrypts correctly" do | ||
encrypted_mode = IntercomRails::EncryptedMode.new("foo", "a"*12, {:enabled => true}) | ||
encrypted = encrypted_mode.encrypt({"baz" => "bang"}) | ||
|
||
decoded = Base64.decode64(encrypted) | ||
|
||
cipher = OpenSSL::Cipher.new('aes-256-gcm') | ||
cipher.decrypt | ||
cipher.key = Digest::SHA256.digest("foo") | ||
cipher.iv = decoded[0, 12] | ||
auth_tag_index = decoded.length - 16 | ||
cipher.auth_tag = decoded[auth_tag_index, 16] | ||
ciphertext = decoded[12, decoded.length - 16 - 12] | ||
result = cipher.update(ciphertext) + cipher.final | ||
|
||
original = JSON.parse(result) | ||
expect(original).to eq({"baz" => "bang"}) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we just encapsulate the IV generation (through securerandom) and drop it from the list of the function args?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It helps to able to Dependency Inject it so that we can specify fixed IVs for things like testing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that it is optional, we fall back to SecureRandom https://github.com/intercom/intercom-rails/pull/263/files#diff-a86f56ee7fcbd0a1aac0f6800d8c0435R9