Skip to content

Commit

Permalink
feat(conversation): config encrypt decrypt payload transforms (#3977)
Browse files Browse the repository at this point in the history
Co-authored-by: rstachof <rstachof@cisco.com>
  • Loading branch information
robstax and rstachof authored Nov 19, 2024
1 parent 52fb49e commit 045b1ac
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 45 deletions.
10 changes: 10 additions & 0 deletions packages/@webex/internal-plugin-conversation/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,15 @@ export default {
*/
keepEncryptedProperties: false,
decryptionFailureMessage: 'This message cannot be decrypted',

/**
* config value to perform decryption on inbound conversations and activities
*/
includeDecryptionTransforms: true,

/**
* config value to perform decryption on outbound conversations and activities
*/
includeEncryptionTransforms: true,
},
};
12 changes: 12 additions & 0 deletions packages/@webex/internal-plugin-conversation/src/conversation.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import {
} from 'lodash';
import {readExifData} from '@webex/helper-image';
import uuid from 'uuid';
import {transforms as encryptionTransforms} from './encryption-transforms';
import {transforms as decryptionTransforms} from './decryption-transforms';

import {InvalidUserCreation} from './convo-error';
import ShareActivity from './share-activity';
Expand Down Expand Up @@ -77,6 +79,16 @@ const getConvoLimit = (options = {}) => {

const Conversation = WebexPlugin.extend({
namespace: 'Conversation',
initialize() {
this.listenToOnce(this.webex, 'ready', () => {
if (Array.isArray(this.webex.config.payloadTransformer?.transforms)) {
this.webex.config.payloadTransformer.transforms =
this.webex.config.payloadTransformer.transforms
.concat(this.config.includeDecryptionTransforms ? decryptionTransforms : [])
.concat(this.config.includeEncryptionTransforms ? encryptionTransforms : []);
}
});
},

/**
* @param {String} cluster the cluster containing the id
Expand Down
6 changes: 1 addition & 5 deletions packages/@webex/internal-plugin-conversation/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import {capitalize, get, has} from 'lodash';

import Conversation from './conversation';
import config from './config';
import {transforms as encryptionTransforms} from './encryption-transforms';
import {transforms as decryptionTransforms} from './decryption-transforms';

registerInternalPlugin('conversation', Conversation, {
payloadTransformer: {
Expand Down Expand Up @@ -315,9 +313,7 @@ registerInternalPlugin('conversation', Conversation, {
});
},
},
]
.concat(decryptionTransforms)
.concat(encryptionTransforms),
],
},
config,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
activityManager,
} from '../../../src/activity-thread-ordering';
import {ACTIVITY_TYPES, getActivityType, OLDER, NEWER} from '../../../src/activities';
import {transforms as encryptionTransforms} from '../../../src/encryption-transforms';
import {transforms as decryptionTransforms} from '../../../src/decryption-transforms';

describe('plugin-conversation', () => {
describe('Conversation', () => {
Expand All @@ -38,39 +40,36 @@ describe('plugin-conversation', () => {
it('should add recipients to the payload if provided', () => {
const {conversation} = webex.internal;
const recipientId = 'example-recipient-id';
const expected = {items: [{id: recipientId, objectType: 'person'}]}
conversation.sendReaction = sinon.stub().returns(Promise.resolve())
conversation.createReactionHmac = sinon.stub().returns(Promise.resolve('hmac'))

return conversation.addReaction({}, 'example-display-name', {}, recipientId)
.then(() => {
assert.deepEqual(conversation.sendReaction.args[0][1].recipients, expected);
});
const expected = {items: [{id: recipientId, objectType: 'person'}]};
conversation.sendReaction = sinon.stub().returns(Promise.resolve());
conversation.createReactionHmac = sinon.stub().returns(Promise.resolve('hmac'));

return conversation.addReaction({}, 'example-display-name', {}, recipientId).then(() => {
assert.deepEqual(conversation.sendReaction.args[0][1].recipients, expected);
});
});
});

describe('deleteReaction()', () => {
it('should add recipients to the payload if provided', () => {
const {conversation} = webex.internal;
const recipientId = 'example-recipient-id';
const expected = {items: [{id: recipientId, objectType: 'person'}]}
conversation.sendReaction = sinon.stub().returns(Promise.resolve())

return conversation.deleteReaction({}, 'example-reaction-id', recipientId)
.then(() => {
assert.deepEqual(conversation.sendReaction.args[0][1].recipients, expected);
});
const expected = {items: [{id: recipientId, objectType: 'person'}]};
conversation.sendReaction = sinon.stub().returns(Promise.resolve());

return conversation.deleteReaction({}, 'example-reaction-id', recipientId).then(() => {
assert.deepEqual(conversation.sendReaction.args[0][1].recipients, expected);
});
});
});

describe('prepare()', () => {
it('should ammend activity recipients to the returned object', () => {
const {conversation} = webex.internal;
const activity = { recipients: 'example-recipients' };
const activity = {recipients: 'example-recipients'};

return conversation.prepare(activity)
.then((results) => {
assert.deepEqual(results.recipients, activity.recipients);
return conversation.prepare(activity).then((results) => {
assert.deepEqual(results.recipients, activity.recipients);
});
});
});
Expand All @@ -79,39 +78,36 @@ describe('plugin-conversation', () => {
it('should add recipients to the payload if provided', () => {
const {conversation} = webex.internal;
const recipientId = 'example-recipient-id';
const expected = {items: [{id: recipientId, objectType: 'person'}]}
conversation.sendReaction = sinon.stub().returns(Promise.resolve())
conversation.createReactionHmac = sinon.stub().returns(Promise.resolve('hmac'))

return conversation.addReaction({}, 'example-display-name', {}, recipientId)
.then(() => {
assert.deepEqual(conversation.sendReaction.args[0][1].recipients, expected);
});
const expected = {items: [{id: recipientId, objectType: 'person'}]};
conversation.sendReaction = sinon.stub().returns(Promise.resolve());
conversation.createReactionHmac = sinon.stub().returns(Promise.resolve('hmac'));

return conversation.addReaction({}, 'example-display-name', {}, recipientId).then(() => {
assert.deepEqual(conversation.sendReaction.args[0][1].recipients, expected);
});
});
});

describe('deleteReaction()', () => {
it('should add recipients to the payload if provided', () => {
const {conversation} = webex.internal;
const recipientId = 'example-recipient-id';
const expected = {items: [{id: recipientId, objectType: 'person'}]}
conversation.sendReaction = sinon.stub().returns(Promise.resolve())

return conversation.deleteReaction({}, 'example-reaction-id', recipientId)
.then(() => {
assert.deepEqual(conversation.sendReaction.args[0][1].recipients, expected);
});
const expected = {items: [{id: recipientId, objectType: 'person'}]};
conversation.sendReaction = sinon.stub().returns(Promise.resolve());

return conversation.deleteReaction({}, 'example-reaction-id', recipientId).then(() => {
assert.deepEqual(conversation.sendReaction.args[0][1].recipients, expected);
});
});
});

describe('prepare()', () => {
it('should ammend activity recipients to the returned object', () => {
const {conversation} = webex.internal;
const activity = { recipients: 'example-recipients' };
const activity = {recipients: 'example-recipients'};

return conversation.prepare(activity)
.then((results) => {
assert.deepEqual(results.recipients, activity.recipients);
return conversation.prepare(activity).then((results) => {
assert.deepEqual(results.recipients, activity.recipients);
});
});
});
Expand Down Expand Up @@ -220,13 +216,17 @@ describe('plugin-conversation', () => {
it('should convert a "us" cluster to WEBEX_CONVERSATION_DEFAULT_CLUSTER cluster', async () => {
await webex.internal.conversation.getUrlFromClusterId({cluster: 'us'});

sinon.assert.calledWith(webex.internal.services.getServiceUrlFromClusterId, {cluster: 'us'});
sinon.assert.calledWith(webex.internal.services.getServiceUrlFromClusterId, {
cluster: 'us',
});
});

it('should add the cluster service when missing', async () => {
await webex.internal.conversation.getUrlFromClusterId({cluster: 'urn:TEAM:us-west-2_r'});

sinon.assert.calledWith(webex.internal.services.getServiceUrlFromClusterId, {cluster: 'urn:TEAM:us-west-2_r'});
sinon.assert.calledWith(webex.internal.services.getServiceUrlFromClusterId, {
cluster: 'urn:TEAM:us-west-2_r',
});
});
});

Expand Down Expand Up @@ -902,4 +902,59 @@ describe('plugin-conversation', () => {
});
});
});
describe('#payloadTransform encrypt/decrypt', () => {
let webex;
let conversation;

const setup = (options = {}) => {
const {includeDecryptionTransforms, includeEncryptionTransforms} = options;
webex = new MockWebex({
children: {
conversation: Conversation,
},
});
webex.config.payloadTransformer = {transforms: []};
conversation = webex.internal.conversation;
conversation.config.includeDecryptionTransforms = !!includeDecryptionTransforms;
conversation.config.includeEncryptionTransforms = !!includeEncryptionTransforms;
};

const checkTransforms = (receivedTransforms, expectedTransforms) =>
receivedTransforms
.map((transform) => transform.name)
.every((name) => expectedTransforms.map((transform) => transform.name).includes(name));

it.each([
{
includeDecryptionTransforms: false,
includeEncryptionTransforms: false,
expectedTransforms: [],
},
{
includeDecryptionTransforms: false,
includeEncryptionTransforms: true,
expectedTransforms: encryptionTransforms,
},
{
includeDecryptionTransforms: true,
includeEncryptionTransforms: false,
expectedTransforms: decryptionTransforms,
},
{
includeDecryptionTransforms: true,
includeEncryptionTransforms: true,
expectedTransforms: encryptionTransforms.concat(decryptionTransforms),
},
])(
'%s sets initFailed to true when collectPreauthCatalog errors',
async ({includeDecryptionTransforms, includeEncryptionTransforms, expectedTransforms}) => {
setup({includeDecryptionTransforms, includeEncryptionTransforms});
webex.trigger('ready');
assert.isTrue(
checkTransforms(webex.config.payloadTransformer.transforms, expectedTransforms),
'transforms should match expected configuration'
);
}
);
});
});

0 comments on commit 045b1ac

Please sign in to comment.