Skip to content

Commit

Permalink
Merge branch 'master' into ADO2-74-assistant-store-unit-tests
Browse files Browse the repository at this point in the history
* master:
  🚀 Release 1.56.0 (#10502)
  fix(editor): Sending 'Assistant session started event' to posthog (no-changelog) (#10500)
  fix(core): Use class-validator with XSS check for survey answers (#10490)
  fix(editor): Stop telemetry from triggering when initializing workflow in new canvas (no-changelog) (#10492)
  fix(AI Transform Node): Remove prompt as it's already set in ASK AI endpoint (no-changelog) (#10496)
  fix(editor): Prevent unloading when changes are pending in new canvas (no-changelog) (#10474)
  feat(core): Upgrade axios to address CVE-2024-39338 (no-changelog) (#10494)
  • Loading branch information
MiloradFilipovic committed Aug 22, 2024
2 parents 52d7df3 + bcc4bb3 commit d71ee57
Show file tree
Hide file tree
Showing 39 changed files with 899 additions and 495 deletions.
42 changes: 42 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,45 @@
# [1.56.0](https://github.com/n8n-io/n8n/compare/[email protected]@1.56.0) (2024-08-21)


### Bug Fixes

* Better errors in Switch, If and Filter nodes ([#10457](https://github.com/n8n-io/n8n/issues/10457)) ([aea82cb](https://github.com/n8n-io/n8n/commit/aea82cb74421d516919742127daf669808b57604))
* **Calendly Trigger Node:** Fix issue with webhook url matching ([#10378](https://github.com/n8n-io/n8n/issues/10378)) ([09c3a8b](https://github.com/n8n-io/n8n/commit/09c3a8b36733a9634ef5948922d6aa7a19bbb592))
* **core:** Fix payload property in `workflow-post-execute` event ([#10413](https://github.com/n8n-io/n8n/issues/10413)) ([d98e29e](https://github.com/n8n-io/n8n/commit/d98e29e3d53de87aec276260615fa60473a2692f))
* **core:** Fix XSS validation and separate URL validation ([#10424](https://github.com/n8n-io/n8n/issues/10424)) ([91467ab](https://github.com/n8n-io/n8n/commit/91467ab325e4c71c20c522f3143246d270101626))
* **core:** Replace `sanitize-html` with `xss` in XSS validator constraint ([#10479](https://github.com/n8n-io/n8n/issues/10479)) ([5dea51a](https://github.com/n8n-io/n8n/commit/5dea51aad7d9e7ffc676d16f4bbbdecce5876f0b))
* **core:** Use class-validator with XSS check for survey answers ([#10490](https://github.com/n8n-io/n8n/issues/10490)) ([547a606](https://github.com/n8n-io/n8n/commit/547a60642ce9e54819d4e600c822d87dabd59b2e))
* **core:** Use explicit types in configs to ensure valid decorator metadata ([#10433](https://github.com/n8n-io/n8n/issues/10433)) ([2043daa](https://github.com/n8n-io/n8n/commit/2043daa2570bc04b0b8d41f277901a8cc8a7b98f))
* **editor:** Add workflow scopes when initializing workflow ([#10455](https://github.com/n8n-io/n8n/issues/10455)) ([b857c2c](https://github.com/n8n-io/n8n/commit/b857c2cda0a9e4386a540d5e1e741570d9453588))
* **editor:** Buffer json chunks in stream response ([#10439](https://github.com/n8n-io/n8n/issues/10439)) ([37797f3](https://github.com/n8n-io/n8n/commit/37797f38d81b12d030ba85034baeb49192ea575c))
* **editor:** Fix flaky mapping tests ([#10453](https://github.com/n8n-io/n8n/issues/10453)) ([fc6d413](https://github.com/n8n-io/n8n/commit/fc6d4138d58282f676b32f1a6011b1b6d0184bf2))
* **editor:** Fix overflow in AI Assistant chat messages ([#10491](https://github.com/n8n-io/n8n/issues/10491)) ([4a6ca63](https://github.com/n8n-io/n8n/commit/4a6ca632100731f85875c639f2164bf1ef415009))
* **editor:** Highlight matching type in filter component ([#10425](https://github.com/n8n-io/n8n/issues/10425)) ([6bca879](https://github.com/n8n-io/n8n/commit/6bca879d4ae30c7f9a35e8d6672de42cf93be727))
* **editor:** Show item count in output panel schema view ([#10426](https://github.com/n8n-io/n8n/issues/10426)) ([4dee7cc](https://github.com/n8n-io/n8n/commit/4dee7cc36e5f7768d0b71095b194bf357c92e941))
* **editor:** Truncate long data pill labels in schema view ([#10427](https://github.com/n8n-io/n8n/issues/10427)) ([1bf2f4f](https://github.com/n8n-io/n8n/commit/1bf2f4f6171d666391bb3a3a312468bc083446e3))
* Filter component - improve errors ([#10456](https://github.com/n8n-io/n8n/issues/10456)) ([61ac0c7](https://github.com/n8n-io/n8n/commit/61ac0c77755210f570b887951fe6bbec1a323811))
* **Google Sheets Node:** Better error when column to match on is empty ([#10442](https://github.com/n8n-io/n8n/issues/10442)) ([ce46bf5](https://github.com/n8n-io/n8n/commit/ce46bf516a86d9779f37dd75b0c680d26d88e15d))
* **Google Sheets Node:** Update name and hint for useAppend option ([#10443](https://github.com/n8n-io/n8n/issues/10443)) ([c5a0c04](https://github.com/n8n-io/n8n/commit/c5a0c049eaf44419c690d151de42fb0c10bd406e))
* **Google Sheets Node:** Update to returnAllMatches option ([#10440](https://github.com/n8n-io/n8n/issues/10440)) ([f7fb02e](https://github.com/n8n-io/n8n/commit/f7fb02e92a756781f8e35bbbfc25d71c12cb70af))
* **Invoice Ninja Node:** Fix payment types ([#10462](https://github.com/n8n-io/n8n/issues/10462)) ([129245d](https://github.com/n8n-io/n8n/commit/129245da10be1d645f61e929e40b128bd7813f17))
* **n8n Form Trigger Node:** Show basic authentication modal on wrong credentials ([#10423](https://github.com/n8n-io/n8n/issues/10423)) ([0dc3e99](https://github.com/n8n-io/n8n/commit/0dc3e99b26bec45e747d83f383cfe5169d89e6b7))
* **OpenAI Node:** Throw node operations error in case of openAi client error ([#10448](https://github.com/n8n-io/n8n/issues/10448)) ([0d3ed46](https://github.com/n8n-io/n8n/commit/0d3ed461996bbad06015c455f133baab6506437f))
* Project Viewer always seeing a connection error when testing credentials ([#10417](https://github.com/n8n-io/n8n/issues/10417)) ([613cdd2](https://github.com/n8n-io/n8n/commit/613cdd2ba2c0f224c4857a5fc3eea36dbd683049))
* Remove unimplemented Postgres credentials options ([#10461](https://github.com/n8n-io/n8n/issues/10461)) ([17ac784](https://github.com/n8n-io/n8n/commit/17ac7844f29d819b91dfaf90b9fe386d98060c42))
* Rename Assistant back ([#10481](https://github.com/n8n-io/n8n/issues/10481)) ([c410aed](https://github.com/n8n-io/n8n/commit/c410aed4c22182943dc80ede63acda00b7898e10))
* Require mfa code to change email ([#10354](https://github.com/n8n-io/n8n/issues/10354)) ([39c8e50](https://github.com/n8n-io/n8n/commit/39c8e50ad0513649f5a8cef911b7d6cdd61c2372))
* **Respond to Webhook Node:** Fix issue preventing the chat trigger from working ([#9886](https://github.com/n8n-io/n8n/issues/9886)) ([9d6ad88](https://github.com/n8n-io/n8n/commit/9d6ad88c14a88fd0dfcb4f9981e38d19cf5f3067))
* Show input names when node has multiple inputs ([#10434](https://github.com/n8n-io/n8n/issues/10434)) ([973956c](https://github.com/n8n-io/n8n/commit/973956cc26c78c329ff6eb6934d4f0a24060c87c))
* **Toggl Trigger Node:** Update API version ([#10207](https://github.com/n8n-io/n8n/issues/10207)) ([9bdb1d6](https://github.com/n8n-io/n8n/commit/9bdb1d6dca43fe491c5eb96f093b7eec4509eaff))


### Features

* **core:** Support bidirectional communication between specific mains and specific workers ([#10377](https://github.com/n8n-io/n8n/issues/10377)) ([d0fc9de](https://github.com/n8n-io/n8n/commit/d0fc9dee0e17211c1ed130b19286e9573c9ebfbd))
* **Facebook Graph API Node:** Update node to support API v18 - v20 ([#10419](https://github.com/n8n-io/n8n/issues/10419)) ([e7ee10f](https://github.com/n8n-io/n8n/commit/e7ee10f243663d899d32e61bc6264b4df444e2af))



# [1.55.0](https://github.com/n8n-io/n8n/compare/[email protected]@1.55.0) (2024-08-14)


Expand Down
2 changes: 1 addition & 1 deletion cypress/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@
"cypress-real-events": "^1.12.0",
"lodash": "catalog:",
"nanoid": "catalog:",
"start-server-and-test": "^2.0.3"
"start-server-and-test": "^2.0.5"
}
}
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "n8n-monorepo",
"version": "1.55.0",
"version": "1.56.0",
"private": true,
"engines": {
"node": ">=20.15",
Expand Down Expand Up @@ -63,7 +63,6 @@
],
"overrides": {
"@types/node": "^18.16.16",
"axios": "1.7.3",
"chokidar": "3.5.2",
"esbuild": "^0.20.2",
"formidable": "3.5.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/@n8n/config/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@n8n/config",
"version": "1.5.0",
"version": "1.6.0",
"scripts": {
"clean": "rimraf dist .turbo",
"dev": "pnpm watch",
Expand Down
2 changes: 1 addition & 1 deletion packages/@n8n/nodes-langchain/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@n8n/n8n-nodes-langchain",
"version": "1.55.0",
"version": "1.56.0",
"description": "",
"main": "index.js",
"scripts": {
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "n8n",
"version": "1.55.0",
"version": "1.56.0",
"description": "n8n Workflow Automation Tool",
"main": "dist/index",
"types": "dist/index.d.ts",
Expand Down Expand Up @@ -93,7 +93,7 @@
"@n8n_io/ai-assistant-sdk": "1.9.4",
"@n8n_io/license-sdk": "2.13.1",
"@oclif/core": "4.0.7",
"@rudderstack/rudder-sdk-node": "2.0.7",
"@rudderstack/rudder-sdk-node": "2.0.9",
"@sentry/integrations": "7.87.0",
"@sentry/node": "7.87.0",
"aws4": "1.11.0",
Expand Down
41 changes: 4 additions & 37 deletions packages/cli/src/GenericHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ValidationError, validate } from 'class-validator';
import { validate } from 'class-validator';
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
import type { TagEntity } from '@db/entities/TagEntity';
Expand All @@ -9,7 +9,7 @@ import type {
UserUpdatePayload,
} from '@/requests';
import { BadRequestError } from './errors/response-errors/bad-request.error';
import { NoXss } from '@/validators/no-xss.validator';
import type { PersonalizationSurveyAnswersV4 } from './controllers/survey-answers.dto';

export async function validateEntity(
entity:
Expand All @@ -19,7 +19,8 @@ export async function validateEntity(
| User
| UserUpdatePayload
| UserRoleChangePayload
| UserSettingsUpdatePayload,
| UserSettingsUpdatePayload
| PersonalizationSurveyAnswersV4,
): Promise<void> {
const errors = await validate(entity);

Expand All @@ -37,37 +38,3 @@ export async function validateEntity(
}

export const DEFAULT_EXECUTIONS_GET_ALL_LIMIT = 20;

class StringWithNoXss {
@NoXss()
value: string;

constructor(value: string) {
this.value = value;
}
}

// Temporary solution until we implement payload validation middleware
export async function validateRecordNoXss(record: Record<string, string>) {
const errors: ValidationError[] = [];

for (const [key, value] of Object.entries(record)) {
const stringWithNoXss = new StringWithNoXss(value);
const validationErrors = await validate(stringWithNoXss);

if (validationErrors.length > 0) {
const error = new ValidationError();
error.property = key;
error.constraints = validationErrors[0].constraints;
errors.push(error);
}
}

if (errors.length > 0) {
const errorMessages = errors
.map((error) => `${error.property}: ${Object.values(error.constraints ?? {}).join(', ')}`)
.join(' | ');

throw new BadRequestError(errorMessages);
}
}
38 changes: 34 additions & 4 deletions packages/cli/src/controllers/__tests__/me.controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,10 +349,40 @@ describe('MeController', () => {
);
});

it('should throw BadRequestError on XSS attempt', async () => {
const req = mock<MeRequest.SurveyAnswers>({
body: { 'test-answer': '<script>alert("XSS")</script>' },
});
test.each([
'automationGoalDevops',
'companyIndustryExtended',
'otherCompanyIndustryExtended',
'automationGoalSm',
'usageModes',
])('should throw BadRequestError on XSS attempt for an array field %s', async (fieldName) => {
const req = mock<MeRequest.SurveyAnswers>();
req.body = {
version: 'v4',
personalization_survey_n8n_version: '1.0.0',
personalization_survey_submitted_at: new Date().toISOString(),
[fieldName]: ['<script>alert("XSS")</script>'],
};

await expect(controller.storeSurveyAnswers(req)).rejects.toThrowError(BadRequestError);
});

test.each([
'automationGoalDevopsOther',
'companySize',
'companyType',
'automationGoalSmOther',
'roleOther',
'reportedSource',
'reportedSourceOther',
])('should throw BadRequestError on XSS attempt for a string field %s', async (fieldName) => {
const req = mock<MeRequest.SurveyAnswers>();
req.body = {
version: 'v4',
personalization_survey_n8n_version: '1.0.0',
personalization_survey_submitted_at: new Date().toISOString(),
[fieldName]: '<script>alert("XSS")</script>',
};

await expect(controller.storeSurveyAnswers(req)).rejects.toThrowError(BadRequestError);
});
Expand Down
17 changes: 12 additions & 5 deletions packages/cli/src/controllers/me.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { randomBytes } from 'crypto';
import { AuthService } from '@/auth/auth.service';
import { Delete, Get, Patch, Post, RestController } from '@/decorators';
import { PasswordUtility } from '@/services/password.utility';
import { validateEntity, validateRecordNoXss } from '@/GenericHelpers';
import { validateEntity } from '@/GenericHelpers';
import type { User } from '@db/entities/User';
import {
AuthenticatedRequest,
Expand All @@ -25,6 +25,7 @@ import { isApiEnabled } from '@/PublicApi';
import { EventService } from '@/events/event.service';
import { MfaService } from '@/Mfa/mfa.service';
import { InvalidMfaCodeError } from '@/errors/response-errors/invalid-mfa-code.error';
import { PersonalizationSurveyAnswersV4 } from './survey-answers.dto';

export const API_KEY_PREFIX = 'n8n_api_';

Expand Down Expand Up @@ -195,20 +196,26 @@ export class MeController {

if (!personalizationAnswers) {
this.logger.debug(
'Request to store user personalization survey failed because of empty payload',
'Request to store user personalization survey failed because of undefined payload',
{
userId: req.user.id,
},
);
throw new BadRequestError('Personalization answers are mandatory');
}

await validateRecordNoXss(personalizationAnswers);
const validatedAnswers = plainToInstance(
PersonalizationSurveyAnswersV4,
personalizationAnswers,
{ excludeExtraneousValues: true },
);

await validateEntity(validatedAnswers);

await this.userRepository.save(
{
id: req.user.id,
personalizationAnswers,
personalizationAnswers: validatedAnswers,
},
{ transaction: false },
);
Expand All @@ -217,7 +224,7 @@ export class MeController {

this.eventService.emit('user-submitted-personalization-survey', {
userId: req.user.id,
answers: personalizationAnswers,
answers: validatedAnswers,
});

return { success: true };
Expand Down
109 changes: 109 additions & 0 deletions packages/cli/src/controllers/survey-answers.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { NoXss } from '@/validators/no-xss.validator';
import { Expose } from 'class-transformer';
import { IsString, IsArray, IsOptional, IsEmail, IsEnum } from 'class-validator';
import type { IPersonalizationSurveyAnswersV4 } from 'n8n-workflow';

export class PersonalizationSurveyAnswersV4 implements IPersonalizationSurveyAnswersV4 {
@NoXss()
@Expose()
@IsEnum(['v4'])
version: 'v4';

@NoXss()
@Expose()
@IsString()
personalization_survey_submitted_at: string;

@NoXss()
@Expose()
@IsString()
personalization_survey_n8n_version: string;

@Expose()
@IsOptional()
@IsArray()
@NoXss({ each: true })
@IsString({ each: true })
automationGoalDevops?: string[] | null;

@NoXss()
@Expose()
@IsOptional()
@IsString()
automationGoalDevopsOther?: string | null;

@NoXss({ each: true })
@Expose()
@IsOptional()
@IsArray()
@IsString({ each: true })
companyIndustryExtended?: string[] | null;

@NoXss({ each: true })
@Expose()
@IsOptional()
@IsString({ each: true })
otherCompanyIndustryExtended?: string[] | null;

@NoXss()
@Expose()
@IsOptional()
@IsString()
companySize?: string | null;

@NoXss()
@Expose()
@IsOptional()
@IsString()
companyType?: string | null;

@NoXss({ each: true })
@Expose()
@IsOptional()
@IsArray()
@IsString({ each: true })
automationGoalSm?: string[] | null;

@NoXss()
@Expose()
@IsOptional()
@IsString()
automationGoalSmOther?: string | null;

@NoXss({ each: true })
@Expose()
@IsOptional()
@IsArray()
@IsString({ each: true })
usageModes?: string[] | null;

@NoXss()
@Expose()
@IsOptional()
@IsEmail()
email?: string | null;

@NoXss()
@Expose()
@IsOptional()
@IsString()
role?: string | null;

@NoXss()
@Expose()
@IsOptional()
@IsString()
roleOther?: string | null;

@NoXss()
@Expose()
@IsOptional()
@IsString()
reportedSource?: string | null;

@NoXss()
@Expose()
@IsOptional()
@IsString()
reportedSourceOther?: string | null;
}
Loading

0 comments on commit d71ee57

Please sign in to comment.