mirror of https://github.com/boxyhq/jackson.git
304 lines
9.2 KiB
TypeScript
304 lines
9.2 KiB
TypeScript
import { IDirectorySyncController, Directory, DirectorySyncEvent } from '../../src/typings';
|
|
import tap from 'tap';
|
|
import groups from './data/groups';
|
|
import users from './data/users';
|
|
import { default as usersRequest } from './data/user-requests';
|
|
import { default as groupRequest } from './data/group-requests';
|
|
import { getFakeDirectory } from './data/directories';
|
|
import { jacksonOptions } from '../utils';
|
|
import sinon from 'sinon';
|
|
import axios from '../../src/event/axios';
|
|
import { createSignatureString } from '../../src/event/webhook';
|
|
|
|
let directorySync: IDirectorySyncController;
|
|
let directory: Directory;
|
|
const fakeDirectory = getFakeDirectory();
|
|
|
|
const webhook: Directory['webhook'] = {
|
|
endpoint: 'http://localhost',
|
|
secret: 'secret',
|
|
};
|
|
|
|
tap.before(async () => {
|
|
const jackson = await (await import('../../src/index')).default(jacksonOptions);
|
|
|
|
directorySync = jackson.directorySyncController;
|
|
|
|
// Create a directory before starting the test
|
|
const { data, error } = await directorySync.directories.create({
|
|
...fakeDirectory,
|
|
webhook_url: webhook.endpoint,
|
|
webhook_secret: webhook.secret,
|
|
});
|
|
|
|
if (error || !data) {
|
|
tap.fail("Couldn't create a directory");
|
|
return;
|
|
}
|
|
|
|
directory = data;
|
|
|
|
// Turn on webhook event logging for the directory
|
|
await directorySync.directories.update(directory.id, {
|
|
log_webhook_events: true,
|
|
});
|
|
|
|
directorySync.webhookLogs.setTenantAndProduct(directory.tenant, directory.product);
|
|
directorySync.users.setTenantAndProduct(directory.tenant, directory.product);
|
|
});
|
|
|
|
tap.teardown(async () => {
|
|
process.exit(0);
|
|
});
|
|
|
|
tap.test('Webhook Events /', async (t) => {
|
|
t.teardown(async () => {
|
|
await directorySync.directories.delete(directory.id);
|
|
});
|
|
|
|
t.test('Webhook Events / ', async (t) => {
|
|
t.afterEach(async () => {
|
|
await directorySync.webhookLogs.deleteAll(directory.id);
|
|
await directorySync.users.deleteAll(directory.id);
|
|
});
|
|
|
|
t.test("Should be able to get the directory's webhook", async (t) => {
|
|
t.match(directory.webhook.endpoint, webhook.endpoint);
|
|
t.match(directory.webhook.secret, webhook.secret);
|
|
});
|
|
|
|
t.test('Should not log events if the directory has no webhook', async (t) => {
|
|
await directorySync.directories.update(directory.id, {
|
|
webhook: {
|
|
endpoint: '',
|
|
secret: '',
|
|
},
|
|
});
|
|
|
|
// Create a user
|
|
await directorySync.requests.handle(usersRequest.create(directory, users[0]));
|
|
|
|
const events = await directorySync.webhookLogs.getAll();
|
|
|
|
t.equal(events.length, 0);
|
|
|
|
// Restore the directory's webhook
|
|
await directorySync.directories.update(directory.id, {
|
|
webhook: {
|
|
endpoint: webhook.endpoint,
|
|
secret: webhook.secret,
|
|
},
|
|
});
|
|
});
|
|
|
|
t.test('Should not log webhook events if the logging is turned off', async (t) => {
|
|
// Turn off webhook event logging for the directory
|
|
await directorySync.directories.update(directory.id, {
|
|
log_webhook_events: false,
|
|
});
|
|
|
|
// Create a user
|
|
await directorySync.requests.handle(usersRequest.create(directory, users[0]));
|
|
|
|
const events = await directorySync.webhookLogs.getAll();
|
|
|
|
t.equal(events.length, 0);
|
|
|
|
// Turn on webhook event logging for the directory
|
|
await directorySync.directories.update(directory.id, {
|
|
log_webhook_events: true,
|
|
});
|
|
});
|
|
|
|
t.test('Should be able to get an event by id', async (t) => {
|
|
// Create a user
|
|
await directorySync.requests.handle(usersRequest.create(directory, users[0]));
|
|
|
|
const logs = await directorySync.webhookLogs.getAll();
|
|
|
|
const log = await directorySync.webhookLogs.get(logs[0].id);
|
|
|
|
t.equal(log.id, logs[0].id);
|
|
});
|
|
|
|
t.test('Should send user related events', async (t) => {
|
|
const mock = sinon.mock(axios);
|
|
|
|
mock.expects('post').thrice().withArgs(webhook.endpoint).throws();
|
|
|
|
// Create the user
|
|
const { data: createdUser } = await directorySync.requests.handle(
|
|
usersRequest.create(directory, users[0])
|
|
);
|
|
|
|
// Update the user
|
|
const { data: updatedUser } = await directorySync.requests.handle(
|
|
usersRequest.updateById(directory, createdUser.id, users[0])
|
|
);
|
|
|
|
// Delete the user
|
|
const { data: deletedUser } = await directorySync.requests.handle(
|
|
usersRequest.deleteById(directory, createdUser.id)
|
|
);
|
|
|
|
mock.verify();
|
|
mock.restore();
|
|
|
|
const logs = await directorySync.webhookLogs.getAll();
|
|
|
|
t.ok(logs);
|
|
t.equal(logs.length, 3);
|
|
|
|
if (!Array.isArray(logs[0].payload)) {
|
|
t.match(logs[0].payload.event, 'user.deleted');
|
|
t.match(logs[0].payload.directory_id, directory.id);
|
|
t.hasStrict(logs[0].payload.data.raw, deletedUser);
|
|
}
|
|
|
|
if (!Array.isArray(logs[1].payload)) {
|
|
t.match(logs[1].payload.event, 'user.updated');
|
|
t.match(logs[1].payload.directory_id, directory.id);
|
|
t.hasStrict(logs[1].payload.data.raw, updatedUser);
|
|
}
|
|
|
|
if (!Array.isArray(logs[2].payload)) {
|
|
t.match(logs[2].payload.event, 'user.created');
|
|
t.match(logs[2].payload.directory_id, directory.id);
|
|
t.hasStrict(logs[2].payload.data.raw, createdUser);
|
|
}
|
|
|
|
await directorySync.users.deleteAll(directory.id);
|
|
});
|
|
|
|
t.test('Should send group related events', async (t) => {
|
|
const mock = sinon.mock(axios);
|
|
|
|
mock.expects('post').thrice().withArgs(webhook.endpoint).throws();
|
|
|
|
// Create the group
|
|
const { data: createdGroup } = await directorySync.requests.handle(
|
|
groupRequest.create(directory, groups[0])
|
|
);
|
|
|
|
// Update the group
|
|
const { data: updatedGroup } = await directorySync.requests.handle(
|
|
groupRequest.updateById(directory, createdGroup.id, groups[0])
|
|
);
|
|
|
|
// Delete the group
|
|
const { data: deletedGroup } = await directorySync.requests.handle(
|
|
groupRequest.deleteById(directory, createdGroup.id)
|
|
);
|
|
|
|
mock.verify();
|
|
mock.restore();
|
|
|
|
const logs = await directorySync.webhookLogs.getAll();
|
|
|
|
t.ok(logs);
|
|
t.equal(logs.length, 3);
|
|
|
|
if (!Array.isArray(logs[0].payload)) {
|
|
t.match(logs[0].payload.event, 'group.deleted');
|
|
t.match(logs[0].payload.directory_id, directory.id);
|
|
t.hasStrict(logs[0].payload.data.raw, deletedGroup);
|
|
}
|
|
|
|
if (!Array.isArray(logs[1].payload)) {
|
|
t.match(logs[1].payload.event, 'group.updated');
|
|
t.match(logs[1].payload.directory_id, directory.id);
|
|
t.hasStrict(logs[1].payload.data.raw, updatedGroup);
|
|
}
|
|
|
|
if (!Array.isArray(logs[2].payload)) {
|
|
t.match(logs[2].payload.event, 'group.created');
|
|
t.match(logs[2].payload.directory_id, directory.id);
|
|
t.hasStrict(logs[2].payload.data.raw, createdGroup);
|
|
}
|
|
});
|
|
});
|
|
|
|
t.test('Should send group membership related events', async (t) => {
|
|
const mock = sinon.mock(axios);
|
|
|
|
mock.expects('post').exactly(4).withArgs(webhook.endpoint).throws();
|
|
|
|
// Create the user
|
|
const { data: createdUser } = await directorySync.requests.handle(
|
|
usersRequest.create(directory, users[0])
|
|
);
|
|
|
|
// Create the group
|
|
const { data: createdGroup } = await directorySync.requests.handle(
|
|
groupRequest.create(directory, groups[0])
|
|
);
|
|
|
|
// Add the user to the group
|
|
await directorySync.requests.handle(
|
|
groupRequest.addMembers(directory, createdGroup.id, [{ value: createdUser.id }])
|
|
);
|
|
|
|
// Remove the user from the group
|
|
await directorySync.requests.handle(
|
|
groupRequest.removeMembers(
|
|
directory,
|
|
createdGroup.id,
|
|
[{ value: createdUser.id }],
|
|
`members[value eq "${createdUser.id}"]`
|
|
)
|
|
);
|
|
|
|
mock.verify();
|
|
mock.restore();
|
|
|
|
const logs = await directorySync.webhookLogs.getAll();
|
|
|
|
t.ok(logs);
|
|
t.equal(logs.length, 4);
|
|
|
|
if (!Array.isArray(logs[0].payload)) {
|
|
t.match(logs[0].payload.event, 'group.user_removed');
|
|
t.match(logs[0].payload.directory_id, directory.id);
|
|
t.hasStrict(logs[0].payload.data.raw, createdUser);
|
|
}
|
|
|
|
if (!Array.isArray(logs[1].payload)) {
|
|
t.match(logs[1].payload.event, 'group.user_added');
|
|
t.match(logs[1].payload.directory_id, directory.id);
|
|
t.hasStrict(logs[1].payload.data.raw, createdUser);
|
|
}
|
|
|
|
await directorySync.users.delete(createdUser.id);
|
|
await directorySync.groups.delete(createdGroup.id);
|
|
});
|
|
|
|
t.test('createSignatureString()', async (t) => {
|
|
const event: DirectorySyncEvent = {
|
|
event: 'user.created',
|
|
directory_id: directory.id,
|
|
tenant: directory.tenant,
|
|
product: directory.product,
|
|
data: {
|
|
raw: [],
|
|
id: 'user-id',
|
|
first_name: 'Kiran',
|
|
last_name: 'Krishnan',
|
|
email: 'kiran@boxyhq.com',
|
|
active: true,
|
|
},
|
|
};
|
|
|
|
const signatureString = createSignatureString(directory.webhook.secret, event);
|
|
const parts = signatureString.split(',');
|
|
|
|
t.ok(signatureString);
|
|
t.ok(parts[0].match(/^t=[0-9a-f]/));
|
|
t.ok(parts[1].match(/^s=[0-9a-f]/));
|
|
|
|
// Empty secret should create an empty signature
|
|
const emptySignatureString = createSignatureString('', event);
|
|
|
|
t.match(emptySignatureString, '');
|
|
});
|
|
});
|