Skip to content

Commit

Permalink
feat(framework): Add disableOutputSanitization flag for channel ste…
Browse files Browse the repository at this point in the history
…p definitions (#6521)
  • Loading branch information
rifont authored Oct 8, 2024
1 parent 19fcb06 commit 6740e50
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 4 deletions.
79 changes: 77 additions & 2 deletions packages/framework/src/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1244,7 +1244,7 @@ describe('Novu Client', () => {
await expect(client.executeWorkflow(event)).rejects.toThrow(Error);
});

it('should sanitize the step result of all delivery channel step types', async () => {
it('should sanitize the step output of all channel step types by default', async () => {
const script = `<script>alert('Hello there')</script>`;

client.addWorkflows([
Expand Down Expand Up @@ -1274,9 +1274,84 @@ describe('Novu Client', () => {
expect(executionResult.outputs.subject).toBe('Start of subject. ');
});

it('should not sanitize the step result of custom step type', async () => {
it('should sanitize the step output of channel step types when `disableOutputSanitization: false`', async () => {
const script = `<script>alert('Hello there')</script>`;

client.addWorkflows([
workflow('test-workflow', async ({ step }) => {
await step.email(
'send-email',
async () => ({
body: `Start of body. ${script}`,
subject: `Start of subject. ${script}`,
}),
{
disableOutputSanitization: false,
}
);
}),
]);

const event: Event = {
action: PostActionEnum.EXECUTE,
workflowId: 'test-workflow',
stepId: 'send-email',
subscriber: {},
state: [],
data: {},
payload: {},
inputs: {},
controls: {},
};

const executionResult = await client.executeWorkflow(event);
expect(executionResult.outputs).toBeDefined();
expect(executionResult.outputs.body).toBe('Start of body. ');
expect(executionResult.outputs.subject).toBe('Start of subject. ');
});

it('should NOT sanitize the step output of channel step type when `disableOutputSanitization: true`', async () => {
const link =
'/pipeline/Oee4d54-ca52-4d70-86b3-cd10a67b6810/requirements?requirementId=dc25a578-ecf1-4835-9310-2236f8244bd&commentId=e259b16b-68f9-43af-b252-fce68bc7cb2f';

client.addWorkflows([
workflow('test-workflow', async ({ step }) => {
await step.inApp(
'send-inapp',
async () => ({
body: `Start of body.`,
data: {
someVal: link,
},
}),
{
disableOutputSanitization: true,
}
);
}),
]);

const event: Event = {
action: PostActionEnum.EXECUTE,
workflowId: 'test-workflow',
stepId: 'send-inapp',
subscriber: {},
state: [],
data: {},
payload: {},
inputs: {},
controls: {},
};

const executionResult = await client.executeWorkflow(event);
expect(executionResult.outputs).toBeDefined();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
expect((executionResult.outputs.data as any).someVal).toBe(link);
});

it('should not sanitize the step result of custom step type', async () => {
const script = `<script>alert('Hello there')</a>`;

client.addWorkflows([
workflow('test-workflow', async ({ step }) => {
await step.custom(
Expand Down
8 changes: 6 additions & 2 deletions packages/framework/src/client.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { JSONSchemaFaker } from 'json-schema-faker';
import { Liquid } from 'liquidjs';
import ora from 'ora';
import {} from './types';

import { ChannelStepEnum, FRAMEWORK_VERSION, PostActionEnum, SDK_VERSION } from './constants';
import {
Expand Down Expand Up @@ -309,7 +308,12 @@ export class Client {
resolve: stepResolve as typeof step.resolve,
});

if (Object.values(ChannelStepEnum).includes(step.type as ChannelStepEnum)) {
if (
Object.values(ChannelStepEnum).includes(step.type as ChannelStepEnum) &&
// TODO: Update return type to include ChannelStep and fix typings
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(options as any)?.disableOutputSanitization !== true
) {
// Sanitize the outputs to avoid XSS attacks via Channel content.
stepResult = {
...stepResult,
Expand Down
6 changes: 6 additions & 0 deletions packages/framework/src/types/step.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,12 @@ export type ChannelStep<
* The providers for the step. Used to override the behaviour of the providers for the step.
*/
providers?: Prettify<Providers<T_StepType, T_Controls, T_Outputs>>;
/**
* A flag to disable output sanitization for the step.
*
* @default false
*/
disableOutputSanitization?: boolean;
}
) => StepOutput<T_Result>;

Expand Down

0 comments on commit 6740e50

Please sign in to comment.