-
Notifications
You must be signed in to change notification settings - Fork 10.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[NEW] Add omnichannel external frame feature (#17038)
- Loading branch information
Showing
16 changed files
with
211 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
function ab2str(buf: ArrayBuffer): string { | ||
return String.fromCharCode(...new Uint16Array(buf)); | ||
} | ||
|
||
function str2ab(str: string): ArrayBuffer { | ||
const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char | ||
const bufView = new Uint16Array(buf); | ||
for (let i = 0, strLen = str.length; i < strLen; i++) { | ||
bufView[i] = str.charCodeAt(i); | ||
} | ||
return buf; | ||
} | ||
|
||
export async function generateKey(): Promise<string> { | ||
const key = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']); | ||
const exportedKey = await crypto.subtle.exportKey('jwk', key); | ||
return JSON.stringify(exportedKey); | ||
} | ||
|
||
export async function getKeyFromString(keyStr: string): Promise<CryptoKey> { | ||
const key = JSON.parse(keyStr); | ||
return crypto.subtle.importKey('jwk', key, { name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']); | ||
} | ||
|
||
export async function encrypt(text: string, key: CryptoKey): Promise<string> { | ||
const vector = crypto.getRandomValues(new Uint8Array(16)); | ||
const data = new TextEncoder().encode(text); | ||
const enc = await crypto.subtle.encrypt({ name: 'AES-GCM', iv: vector }, key, data); | ||
const cipherText = new Uint8Array(enc); | ||
return encodeURIComponent(btoa(ab2str(vector) + ab2str(cipherText))); | ||
} | ||
|
||
export async function decrypt(data: string, key: CryptoKey): Promise<string> { | ||
const binaryData = atob(decodeURIComponent(data)); | ||
const vector = new Uint8Array(new Uint16Array(str2ab(binaryData.slice(0, 16)))); | ||
const buffer = new Uint8Array(new Uint16Array(str2ab(binaryData.slice(16)))); | ||
const decoded = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: vector }, key, buffer); | ||
return new TextDecoder().decode(decoded); | ||
} |
5 changes: 5 additions & 0 deletions
5
app/livechat/client/externalFrame/externalFrameContainer.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<template name="ExternalFrameContainer"> | ||
<div class="flex-nav"> | ||
<iframe class="external-frame" src="{{ externalFrameUrl }}"></iframe> | ||
</div> | ||
</template> |
49 changes: 49 additions & 0 deletions
49
app/livechat/client/externalFrame/externalFrameContainer.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { Meteor } from 'meteor/meteor'; | ||
import { Template } from 'meteor/templating'; | ||
import { Session } from 'meteor/session'; | ||
import { ReactiveVar } from 'meteor/reactive-var'; | ||
|
||
import { APIClient } from '../../../utils/client'; | ||
import { settings } from '../../../settings/client'; | ||
import { encrypt, getKeyFromString } from './crypto'; | ||
|
||
import './externalFrameContainer.html'; | ||
|
||
Template.ExternalFrameContainer.helpers({ | ||
externalFrameUrl() { | ||
const authToken = Template.instance().authToken.get(); | ||
|
||
if (!authToken) { | ||
return ''; | ||
} | ||
|
||
const frameURLSetting = settings.get('Omnichannel_External_Frame_URL'); | ||
|
||
try { | ||
const frameURL = new URL(frameURLSetting); | ||
|
||
frameURL.searchParams.append('uid', Meteor.userId()); | ||
frameURL.searchParams.append('rid', Session.get('openedRoom')); | ||
frameURL.searchParams.append('t', authToken); | ||
|
||
return frameURL.toString(); | ||
} catch { | ||
console.error('Invalid URL provided to external frame'); | ||
|
||
return ''; | ||
} | ||
}, | ||
}); | ||
|
||
Template.ExternalFrameContainer.onCreated(async function() { | ||
this.authToken = new ReactiveVar(); | ||
|
||
const { 'X-Auth-Token': authToken } = APIClient.getCredentials(); | ||
const keyStr = settings.get('Omnichannel_External_Frame_Encryption_JWK'); | ||
|
||
if (keyStr) { | ||
return this.authToken.set(await encrypt(authToken, await getKeyFromString(keyStr))); | ||
} | ||
|
||
this.authToken.set(authToken); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { Meteor } from 'meteor/meteor'; | ||
|
||
import { generateKey } from './crypto'; | ||
|
||
Meteor.methods({ | ||
async omnichannelExternalFrameGenerateKey() { | ||
const key = await generateKey(); | ||
Meteor.call('saveSetting', 'Omnichannel_External_Frame_Encryption_JWK', key); | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import './generateNewKey'; | ||
import './tabBar'; | ||
import './externalFrameContainer'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { Meteor } from 'meteor/meteor'; | ||
import { Tracker } from 'meteor/tracker'; | ||
|
||
import { TabBar } from '../../../ui-utils/client'; | ||
import { settings } from '../../../settings/client'; | ||
|
||
|
||
Meteor.startup(function() { | ||
Tracker.autorun(function() { | ||
if (!settings.get('Omnichannel_External_Frame_Enabled')) { | ||
return TabBar.removeButton('omnichannelExternalFrame'); | ||
} | ||
|
||
TabBar.addButton({ | ||
groups: ['live'], | ||
id: 'omnichannelExternalFrame', | ||
i18nTitle: 'Omnichannel_External_Frame', | ||
icon: 'cube', | ||
template: 'ExternalFrameContainer', | ||
order: -1, | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { Meteor } from 'meteor/meteor'; | ||
|
||
Meteor.methods({ | ||
// eslint-disable-next-line @typescript-eslint/no-empty-function | ||
omnichannelExternalFrameGenerateKey() { | ||
return { | ||
message: 'Generating_key', | ||
}; | ||
}, // only to prevent error when calling the client method | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import './settings'; | ||
import './generateNewKey'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { settings } from '../../../settings/server/functions/settings'; | ||
|
||
settings.addGroup('Omnichannel', function() { | ||
this.section('External Frame', function() { | ||
this.add('Omnichannel_External_Frame_Enabled', false, { | ||
type: 'boolean', | ||
public: true, | ||
alert: 'Experimental_Feature_Alert', | ||
}); | ||
|
||
this.add('Omnichannel_External_Frame_URL', '', { | ||
type: 'string', | ||
public: true, | ||
enableQuery: { | ||
_id: 'Omnichannel_External_Frame_Enabled', | ||
value: true, | ||
}, | ||
}); | ||
|
||
this.add('Omnichannel_External_Frame_Encryption_JWK', '', { | ||
type: 'string', | ||
public: true, | ||
enableQuery: { | ||
_id: 'Omnichannel_External_Frame_Enabled', | ||
value: true, | ||
}, | ||
}); | ||
|
||
this.add('Omnichannel_External_Frame_GenerateKey', 'omnichannelExternalFrameGenerateKey', { | ||
type: 'action', | ||
actionText: 'Generate_new_key', | ||
enableQuery: { | ||
_id: 'Omnichannel_External_Frame_Enabled', | ||
value: true, | ||
}, | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export namespace settings { | ||
export function get(name: string, callback: (key: string, value: any) => void): string; | ||
export function get(name: string, callback?: (key: string, value: any) => void): string; | ||
export function updateById(_id: string, value: any, editor?: string): number; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters