Add checks for profanity to profile updates (#12445)

* fix(profile): detect attempt to use banned words as display name. refactor profanity detection method.

* fix(profile): detect attempt to use banned words in blurb. further refactor profanity detection. inform the user their chat privileges have been revoked.

* refactor: add function to normalize Unicode strings and remove diacritics

* fix: improve regEx to prevent false partial matches e.g. 'hello' being recognised as banned words. porting fix from #12309

* fix(profile): refactor of profanity detection for #12445

* fix(profile): add test for swear words in new profile. fix existing tests

* fix(profile): show different error message for attempted slur use in username by new users.

* fix(profile): remove incorrect slur test

* fix(profile): fix slurs not caught at start of end of strings connect by punctuation

* tests(profile): fix tests for profanity checking

* remove exclusive test

* 11865 - update text for slur warnings

* 11865 - remove unused string from locale files

* 11865 - improve naming of banned word usage locale string

* 11865 - improve logic so that differentiated warnings are shown depending on whether a slur or other profanity has been used in a display name

* 11865 - construct slur regexes outside the validation function in which they are used

* 11865 - fix tests
This commit is contained in:
Carlton McFarlane
2021-04-30 22:47:39 +02:00
committed by GitHub
parent 4d7304ab8d
commit a53355872b
9 changed files with 82 additions and 39 deletions

View File

@@ -1,13 +1,23 @@
import bannedSlurs from '../bannedSlurs';
import { getMatchesByWordArray } from '../stringUtils';
import bannedWords from '../bannedWords';
import {
getMatchesByWordArray,
normalizeUnicodeString,
removePunctuationFromString,
} from '../stringUtils';
import forbiddenUsernames from '../forbiddenUsernames';
const bannedSlurRegexs = bannedSlurs.map(word => new RegExp(`.*${word}.*`, 'i'));
const bannedSlurRegexes = bannedSlurs.map(word => new RegExp(`\\b([^a-z]+)?${word}([^a-z]+)?\\b`, 'i'));
const bannedWordRegexes = bannedWords.map(word => new RegExp(`\\b([^a-z]+)?${word}([^a-z]+)?\\b`, 'i'));
export function nameContainsSlur (username) {
for (let i = 0; i < bannedSlurRegexs.length; i += 1) {
const regEx = bannedSlurRegexs[i];
const match = username.match(regEx);
export function stringContainsProfanity (str, profanityType = 'bannedWord') {
const bannedRegexes = profanityType === 'slur'
? bannedSlurRegexes
: bannedWordRegexes;
for (let i = 0; i < bannedRegexes.length; i += 1) {
const regEx = bannedRegexes[i];
const match = removePunctuationFromString(normalizeUnicodeString(str)).match(regEx);
if (match !== null && match[0] !== null) {
return true;
}
@@ -33,17 +43,21 @@ function usernameContainsInvalidCharacters (username) {
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 (stringContainsProfanity(displayName)) issues.push(res.t('bannedWordUsedInProfile'));
if (stringContainsProfanity(displayName, 'slur')) issues.push(res.t('bannedSlurUsedInProfile'));
if (nameContainsNewline(displayName)) issues.push(res.t('displaynameIssueNewline'));
return issues;
}
export function verifyUsername (username, res) {
export function verifyUsername (username, res, newUser = true) {
const slurMessage = newUser
? res.t('usernameIssueSlur')
: res.t('bannedSlurUsedInProfile');
const issues = [];
if (username.length < 1 || username.length > 20) issues.push(res.t('usernameIssueLength'));
if (usernameContainsInvalidCharacters(username)) issues.push(res.t('usernameIssueInvalidCharacters'));
if (nameContainsSlur(username)) issues.push(res.t('usernameIssueSlur'));
if (stringContainsProfanity(username, 'slur') || stringContainsProfanity(username)) issues.push(slurMessage);
if (usernameIsForbidden(username)) issues.push(res.t('usernameIssueForbidden'));
return issues;