diff --git a/test/api/v3/integration/user/PUT-user.test.js b/test/api/v3/integration/user/PUT-user.test.js index d978b34552..71e8500263 100644 --- a/test/api/v3/integration/user/PUT-user.test.js +++ b/test/api/v3/integration/user/PUT-user.test.js @@ -92,6 +92,14 @@ describe('PUT /user', () => { error: 'BadRequest', message: t('displaynameIssueSlur'), }); + + await expect(user.put('/user', { + 'profile.name': 'namecontainsnewline\n', + })).to.eventually.be.rejected.and.eql({ + code: 400, + error: 'BadRequest', + message: t('displaynameIssueNewline'), + }); }); }); diff --git a/test/api/v4/user/auth/POST-user_verify_display_name.test.js b/test/api/v4/user/auth/POST-user_verify_display_name.test.js index 77f30f6a4f..2b56f137db 100644 --- a/test/api/v4/user/auth/POST-user_verify_display_name.test.js +++ b/test/api/v4/user/auth/POST-user_verify_display_name.test.js @@ -53,5 +53,11 @@ describe('POST /user/auth/verify-display-name', async () => { displayName: 'this is a very long display name over 30 characters', })).to.eventually.eql({ isUsable: false, issues: [t('displaynameIssueLength')] }); }); + + it('errors if display name contains a newline', async () => { + await expect(user.post(ENDPOINT, { + displayName: 'namecontainsnewline\n', + })).to.eventually.eql({ isUsable: false, issues: [t('displaynameIssueNewline')] }); + }); }); }); diff --git a/website/common/locales/en/settings.json b/website/common/locales/en/settings.json index cf6e7d08d8..137252db59 100644 --- a/website/common/locales/en/settings.json +++ b/website/common/locales/en/settings.json @@ -202,6 +202,7 @@ "currentUsername": "Current username:", "displaynameIssueLength": "Display Names must be between 1 and 30 characters.", "displaynameIssueSlur": "Display Names may not contain inappropriate language.", + "displaynameIssueNewline": "Display Names may not contain backslashes followed by the letter N.", "goToSettings": "Go to Settings", "usernameVerifiedConfirmation": "Your username, <%= username %>, is confirmed!", "usernameNotVerified": "Please confirm your username.", diff --git a/website/server/libs/user/index.js b/website/server/libs/user/index.js index da1aa35141..26790993ec 100644 --- a/website/server/libs/user/index.js +++ b/website/server/libs/user/index.js @@ -6,7 +6,7 @@ import { NotAuthorized, } from '../errors'; import { model as User, schema as UserSchema } from '../../models/user'; -import { nameContainsSlur } from './validation'; +import { nameContainsSlur, nameContainsNewline } from './validation'; export async function get (req, res, { isV3 = false }) { const { user } = res.locals; @@ -112,6 +112,7 @@ export async function update (req, res, { isV3 = false }) { if (newName === null) throw new BadRequest(res.t('invalidReqParams')); if (newName.length > 30) throw new BadRequest(res.t('displaynameIssueLength')); if (nameContainsSlur(newName)) throw new BadRequest(res.t('displaynameIssueSlur')); + if (nameContainsNewline(newName)) throw new BadRequest(res.t('displaynameIssueNewline')); } _.each(req.body, (val, key) => { diff --git a/website/server/libs/user/validation.js b/website/server/libs/user/validation.js index cbdc6487d0..48fb9eca73 100644 --- a/website/server/libs/user/validation.js +++ b/website/server/libs/user/validation.js @@ -15,6 +15,10 @@ export function nameContainsSlur (username) { return false; } +export function nameContainsNewline (username) { + return username.includes('\n'); +} + function usernameIsForbidden (username) { const forbidddenWordsMatched = getMatchesByWordArray(username, forbiddenUsernames); return forbidddenWordsMatched.length > 0; @@ -30,6 +34,7 @@ export function verifyDisplayName (displayName, res) { const issues = []; if (displayName.length < 1 || displayName.length > 30) issues.push(res.t('displaynameIssueLength')); if (nameContainsSlur(displayName)) issues.push(res.t('displaynameIssueSlur')); + if (nameContainsNewline(displayName)) issues.push(res.t('displaynameIssueNewline')); return issues; }