fix(editor): Validate user info before submiting (#7608)

Validate first and last names before saving them to database. This
should prevent security issue with un-sanitized data that ends up in
emails.

---------

Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
Milorad FIlipović 2023-11-22 12:14:44 +01:00 committed by GitHub
parent 9b4856e7de
commit 2064f7f251
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 97 additions and 1 deletions

View file

@ -0,0 +1,52 @@
import { WorkflowPage } from "../pages";
const workflowPage = new WorkflowPage();
const INVALID_NAMES = [
'https://n8n.io',
'http://n8n.io',
'www.n8n.io',
'n8n.io',
'n8n.бг',
'n8n.io/home',
'n8n.io/home?send=true',
'<a href="#">Jack</a>',
'<script>alert("Hello")</script>',
];
const VALID_NAMES = [
['a', 'a'],
['alice', 'alice'],
['Robert', 'Downey Jr.'],
['Mia', 'Mia-Downey'],
['Mark', "O'neil"],
['Thomas', 'Müler'],
['ßáçøñ', 'ßáçøñ'],
['أحمد', 'فلسطين'],
['Милорад', 'Филиповић'],
];
describe('Personal Settings', () => {
it ('should allow to change first and last name', () => {
cy.visit('/settings/personal');
VALID_NAMES.forEach((name) => {
cy.getByTestId('personal-data-form').find('input[name="firstName"]').clear().type(name[0]);
cy.getByTestId('personal-data-form').find('input[name="lastName"]').clear().type(name[1]);
cy.getByTestId('save-settings-button').click();
workflowPage.getters.successToast().should('contain', 'Personal details updated');
workflowPage.getters.successToast().find('.el-notification__closeBtn').click();
});
});
it('not allow malicious values for personal data', () => {
cy.visit('/settings/personal');
INVALID_NAMES.forEach((name) => {
cy.getByTestId('personal-data-form').find('input[name="firstName"]').clear().type(name);
cy.getByTestId('personal-data-form').find('input[name="lastName"]').clear().type(name);
cy.getByTestId('save-settings-button').click();
workflowPage.getters
.errorToast()
.should('contain', 'Malicious firstName | Malicious lastName');
workflowPage.getters.errorToast().find('.el-notification__closeBtn').click();
});
});
});

View file

@ -11,7 +11,7 @@ export function NoXss() {
options: { message: `Malicious ${propertyName}` },
validator: {
validate(value: string) {
return !/<(\s*)?(script|a|http)/.test(value);
return !/(^http|^www)|<(\s*)?(script|a)|(\.[\p{L}\d-]+)/u.test(value);
},
},
});

View file

@ -0,0 +1,43 @@
import { NoXss } from '@db/utils/customValidators';
import { validate } from 'class-validator';
describe('customValidators', () => {
describe('NoXss', () => {
class Person {
@NoXss()
name: string;
}
const person = new Person();
const invalidNames = ['http://google.com', '<script src/>', 'www.domain.tld'];
const validNames = [
'Johann Strauß',
'Вагиф Сәмәдоғлу',
'René Magritte',
'সুকুমার রায়',
'མགོན་པོ་རྡོ་རྗེ།',
'عبدالحليم حافظ',
];
describe('Block XSS', () => {
for (const name of invalidNames) {
test(name, async () => {
person.name = name;
const validationErrors = await validate(person);
expect(validationErrors[0].property).toEqual('name');
expect(validationErrors[0].constraints).toEqual({ NoXss: 'Malicious name' });
});
}
});
describe('Allow Valid names', () => {
for (const name of validNames) {
test(name, async () => {
person.name = name;
expect(await validate(person)).toBeEmptyArray();
});
}
});
});
});

View file

@ -24,6 +24,7 @@
v-if="buttonText"
:label="buttonText"
:loading="buttonLoading"
data-test-id="form-submit-button"
size="large"
@click="onButtonClick"
/>