mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
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:
parent
9b4856e7de
commit
2064f7f251
52
cypress/e2e/33-settings-personal.cy.ts
Normal file
52
cypress/e2e/33-settings-personal.cy.ts
Normal 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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -11,7 +11,7 @@ export function NoXss() {
|
||||||
options: { message: `Malicious ${propertyName}` },
|
options: { message: `Malicious ${propertyName}` },
|
||||||
validator: {
|
validator: {
|
||||||
validate(value: string) {
|
validate(value: string) {
|
||||||
return !/<(\s*)?(script|a|http)/.test(value);
|
return !/(^http|^www)|<(\s*)?(script|a)|(\.[\p{L}\d-]+)/u.test(value);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -24,6 +24,7 @@
|
||||||
v-if="buttonText"
|
v-if="buttonText"
|
||||||
:label="buttonText"
|
:label="buttonText"
|
||||||
:loading="buttonLoading"
|
:loading="buttonLoading"
|
||||||
|
data-test-id="form-submit-button"
|
||||||
size="large"
|
size="large"
|
||||||
@click="onButtonClick"
|
@click="onButtonClick"
|
||||||
/>
|
/>
|
||||||
|
|
Loading…
Reference in a new issue