|
// Node: Express + Jade |
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
// index.js |
|
|
|
var express = require('express'); |
|
var router = express.Router(); |
|
var crypto = require('crypto'); |
|
|
|
// Settings |
|
const intercomSettings = {app_id: "YOUR_APP_ID", user_id: "1"}; |
|
const secret = "YOUR_WORKSPACE_IDENTITY_VERIFICATION_FOR_WEB_SECRET"; // https://app.intercom.io/a/apps/_/settings/identity-verification/web |
|
|
|
|
|
// Demo implementation of using `aes-256-gcm` with node.js's `crypto` lib. |
|
// https://gist.github.com/rjz/15baffeab434b8125ca4d783f4116d81 |
|
const aes256gcm = (key) => { |
|
const ALGO = 'aes-256-gcm'; |
|
|
|
// encrypt returns base64-encoded ciphertext |
|
const encrypt = (str) => { |
|
// Hint: the `iv` should be unique (but not necessarily random). |
|
// `randomBytes` here are (relatively) slow but convenient for |
|
// demonstration. |
|
const iv = new Buffer(crypto.randomBytes(12), 'utf8'); // Uses 12 https://github.com/intercom/intercom-rails/blob/1478cd606478a0254f7efc2a5960cf5db44e9ee3/lib/intercom-rails/encrypted_mode.rb#L9 which seems to be what is typically used https://crypto.stackexchange.com/questions/41601/aes-gcm-recommended-iv-size-why-12-bytes/41610 |
|
const cipher = crypto.createCipheriv(ALGO, key, iv); |
|
|
|
// Hint: Larger inputs (it's GCM, after all!) should use the stream API |
|
let enc = cipher.update(str, 'utf8', 'base64'); |
|
enc += cipher.final('base64'); |
|
return [enc, iv, cipher.getAuthTag()]; |
|
}; |
|
|
|
// decrypt decodes base64-encoded ciphertext into a utf8-encoded string |
|
const decrypt = (enc, iv, authTag) => { |
|
const decipher = crypto.createDecipheriv(ALGO, key, iv); |
|
decipher.setAuthTag(authTag); |
|
let str = decipher.update(enc, 'base64', 'utf8'); |
|
str += decipher.final('utf8'); |
|
return str; |
|
}; |
|
|
|
return { |
|
encrypt, |
|
decrypt, |
|
}; |
|
}; |
|
|
|
function getEncryptionModeSettings(settings,get_encryptable_data=true){ |
|
const ENCRYPTED_MODE_SETTINGS_WHITELIST = ["app_id", "session_duration", "widget", "custom_launcher_selector", "hide_default_launcher", "alignment", "horizontal_padding", "vertical_padding"]; |
|
const output_settings = {}; |
|
Object.keys(settings).forEach(function (key) { |
|
if (get_encryptable_data && ENCRYPTED_MODE_SETTINGS_WHITELIST.includes(key)) return; |
|
if (!get_encryptable_data && !ENCRYPTED_MODE_SETTINGS_WHITELIST.includes(key)) return; |
|
output_settings[key] = settings[key]; |
|
}); |
|
return output_settings; |
|
} |
|
|
|
function encryptData(encryptSettings, secret){ |
|
const KEY = crypto.createHash('sha256') |
|
.update(secret) |
|
.digest(); |
|
const aesCipher = aes256gcm(KEY); |
|
const [encrypted, iv, authTag] = aesCipher.encrypt(JSON.stringify(encryptSettings)); |
|
return iv.toString('base64') + encrypted + authTag.toString('base64'); |
|
} |
|
|
|
/* GET home page. */ |
|
router.get('/', function(req, res, next) { |
|
|
|
const intercomSettingsOutput = JSON.stringify(getEncryptionModeSettings(intercomSettings,false)); |
|
|
|
const encryptSettings = getEncryptionModeSettings(intercomSettings); |
|
const encryptedOutput = encryptData(encryptSettings, secret); |
|
|
|
|
|
res.render('index', { title: 'Express', app_id: intercomSettings.app_id, intercomSettings: intercomSettings, intercomSettingsOutput: intercomSettingsOutput, encryptedOutput: encryptedOutput}); |
|
}); |
|
|
|
module.exports = router; |
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
// layout.jade |
|
|
|
doctype html |
|
html |
|
head |
|
title= title |
|
link(rel='stylesheet', href='/stylesheets/style.css') |
|
body |
|
block content |
|
script APP_ID = "#{app_id}" |
|
script (function(){var w=window;var ic=w.Intercom;if(typeof ic==="function"){ic('reattach_activator');ic('update',w.intercomSettings);}else{var d=document;var i=function(){i.c(arguments);};i.q=[];i.c=function(args){i.q.push(args);};w.Intercom=i;var l=function(){var s=d.createElement('script');s.type='text/javascript';s.async=true;s.src='https://widget.intercom.io/widget/' + APP_ID;var x=d.getElementsByTagName('script')[0];x.parentNode.insertBefore(s,x);};if(w.attachEvent){w.attachEvent('onload',l);}else{w.addEventListener('load',l,false);}}})(); |
|
script window.intercomSettings= !{intercomSettingsOutput} |
|
script window.intercomEncryptedPayload= "!{encryptedOutput}" |
|
|
This code is a little outdated for nodeJS, after some experimentation this is what I have found works:
Our Encryption Package
Encrypting Intercom Settings
Frontend