From df49297de212e397a90d55cea1758c5f8f3f124a Mon Sep 17 00:00:00 2001 From: Rene Pot Date: Tue, 8 Aug 2023 23:27:41 +0100 Subject: [PATCH] feat(api): improve performance with profanity filter replacement (#51112) Co-authored-by: Naomi Carrigan --- api-server/package.json | 2 +- api-server/src/common/models/user.js | 7 ++-- api/package.json | 3 +- api/src/routes/settings.ts | 6 ++-- pnpm-lock.yaml | 51 ++++++++++++---------------- 5 files changed, 30 insertions(+), 39 deletions(-) diff --git a/api-server/package.json b/api-server/package.json index ebd61d039df..532aa90b126 100644 --- a/api-server/package.json +++ b/api-server/package.json @@ -30,7 +30,6 @@ "@sentry/tracing": "7.37.1", "accepts": "1.3.8", "axios": "0.23.0", - "bad-words": "3.0.4", "body-parser": "1.20.0", "compression": "1.7.4", "connect-mongo": "3.2.0", @@ -59,6 +58,7 @@ "mongodb": "3.6.9", "morgan": "1.10.0", "nanoid": "3.3.4", + "no-profanity": "^1.4.2", "node-fetch": "^2.6.7", "nodemailer-ses-transport": "1.5.1", "passport": "0.4.1", diff --git a/api-server/src/common/models/user.js b/api-server/src/common/models/user.js index 526e363a140..9d5901017e6 100644 --- a/api-server/src/common/models/user.js +++ b/api-server/src/common/models/user.js @@ -5,7 +5,6 @@ * */ -import badwordFilter from 'bad-words'; import debugFactory from 'debug'; import dedent from 'dedent'; import _ from 'lodash'; @@ -15,6 +14,7 @@ import { Observable } from 'rx'; import uuid from 'uuid/v4'; import { isEmail } from 'validator'; +import { isProfane } from 'no-profanity'; import { blocklistedUsernames } from '../../../../config/constants'; import { wrapHandledError } from '../../server/utils/create-handled-error.js'; @@ -368,11 +368,10 @@ export default function initializeUser(User) { } log('check if username is available'); // check to see if username is on blocklist - const usernameFilter = new badwordFilter(); + if ( username && - (blocklistedUsernames.includes(username) || - usernameFilter.isProfane(username)) + (blocklistedUsernames.includes(username) || isProfane(username)) ) { return Promise.resolve(true); } diff --git a/api/package.json b/api/package.json index 459a2d1c7df..ba7910f50d0 100644 --- a/api/package.json +++ b/api/package.json @@ -15,7 +15,6 @@ "@prisma/client": "5.1.1", "ajv": "8.12.0", "ajv-formats": "^2.1.1", - "bad-words": "3.0.4", "connect-mongo": "4.6.0", "fast-uri": "2.2.0", "fastify": "4.21.0", @@ -24,6 +23,7 @@ "jsonwebtoken": "9.0.1", "mongodb": "^4.16.0", "nanoid": "3", + "no-profanity": "^1.4.2", "nodemon": "2.0.22", "nodemailer": "^6.9.3", "query-string": "^7.1.3" @@ -31,7 +31,6 @@ "description": "The freeCodeCamp.org open-source codebase and curriculum", "devDependencies": { "@fastify/type-provider-typebox": "3.4.0", - "@types/bad-words": "^3.0.1", "@types/express-session": "1.17.7", "@types/jsonwebtoken": "^9.0.2", "@types/nodemailer": "^6.4.8", diff --git a/api/src/routes/settings.ts b/api/src/routes/settings.ts index eb8de72c2de..8d0db308253 100644 --- a/api/src/routes/settings.ts +++ b/api/src/routes/settings.ts @@ -1,5 +1,5 @@ import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox'; -import badWordsFilter from 'bad-words'; +import { isProfane } from 'no-profanity'; import { isValidUsername } from '../../../utils/validate'; // we have to use this file as JavaScript because it is used by the old api. import { blocklistedUsernames } from '../../../config/constants.js'; @@ -181,7 +181,7 @@ export const settingRoutes: FastifyPluginCallbackTypebox = ( } as const; } - const isProfane = new badWordsFilter().isProfane(newUsername); + const isUserNameProfane = isProfane(newUsername); const onBlocklist = blocklistedUsernames.includes(newUsername); const usernameTaken = @@ -191,7 +191,7 @@ export const settingRoutes: FastifyPluginCallbackTypebox = ( where: { username: newUsername } }); - if (usernameTaken || isProfane || onBlocklist) { + if (usernameTaken || isUserNameProfane || onBlocklist) { void reply.code(400); return { message: 'flash.username-taken', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9c8192aae56..74586163390 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -207,9 +207,6 @@ importers: ajv-formats: specifier: ^2.1.1 version: 2.1.1(ajv@8.12.0) - bad-words: - specifier: 3.0.4 - version: 3.0.4 connect-mongo: specifier: 4.6.0 version: 4.6.0(express-session@1.17.3)(mongodb@4.16.0) @@ -234,6 +231,9 @@ importers: nanoid: specifier: '3' version: 3.3.4 + no-profanity: + specifier: ^1.4.2 + version: 1.4.2 nodemailer: specifier: ^6.9.3 version: 6.9.3 @@ -247,9 +247,6 @@ importers: '@fastify/type-provider-typebox': specifier: 3.4.0 version: 3.4.0(@sinclair/typebox@0.28.9) - '@types/bad-words': - specifier: ^3.0.1 - version: 3.0.1 '@types/express-session': specifier: 1.17.7 version: 1.17.7 @@ -298,9 +295,6 @@ importers: axios: specifier: 0.23.0 version: 0.23.0(debug@2.2.0) - bad-words: - specifier: 3.0.4 - version: 3.0.4 body-parser: specifier: 1.20.0 version: 1.20.0 @@ -385,6 +379,9 @@ importers: nanoid: specifier: 3.3.4 version: 3.3.4 + no-profanity: + specifier: ^1.4.2 + version: 1.4.2 node-fetch: specifier: ^2.6.7 version: 2.6.9 @@ -11033,10 +11030,6 @@ packages: dependencies: '@babel/types': 7.22.5 - /@types/bad-words@3.0.1: - resolution: {integrity: sha512-7la3ZDJG1tlRqySO+pnXycZpacaMEw/iLEm8kc4l+I+jN8KjBfoQVwO6jm98xzXVLrxV8vDrB5TaMoop8sKclQ==} - dev: true - /@types/body-parser@1.19.2: resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} dependencies: @@ -11382,7 +11375,7 @@ packages: /@types/node-fetch@2.6.4: resolution: {integrity: sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==} dependencies: - '@types/node': 18.17.1 + '@types/node': 18.17.3 form-data: 3.0.1 /@types/node@10.17.60: @@ -11416,6 +11409,7 @@ packages: /@types/node@18.17.1: resolution: {integrity: sha512-xlR1jahfizdplZYRU59JlUx9uzF1ARa8jbhM11ccpCJya8kvos5jwdm2ZAgxSCwOl0fq21svP18EVwPBXMQudw==} + dev: true /@types/node@18.17.3: resolution: {integrity: sha512-2x8HWtFk0S99zqVQABU9wTpr8wPoaDHZUcAkoTKH+nL7kPv3WUI9cRi/Kk5Mz4xdqXSqTkKP7IWNoQQYCnDsTA==} @@ -11426,7 +11420,7 @@ packages: /@types/nodemailer@6.4.8: resolution: {integrity: sha512-oVsJSCkqViCn8/pEu2hfjwVO+Gb3e+eTWjg3PcjeFKRItfKpKwHphQqbYmPQrlMk+op7pNNWPbsJIEthpFN/OQ==} dependencies: - '@types/node': 18.17.1 + '@types/node': 18.17.3 dev: true /@types/normalize-package-data@2.4.1: @@ -14484,17 +14478,6 @@ packages: /backo2@1.0.2: resolution: {integrity: sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==} - /bad-words@3.0.4: - resolution: {integrity: sha512-v/Q9uRPH4+yzDVLL4vR1+S9KoFgOEUl5s4axd6NIAq8SV2mradgi4E8lma/Y0cw1ltVdvyegCQQKffCPRCp8fg==} - engines: {node: '>=8.0.0'} - dependencies: - badwords-list: 1.0.0 - dev: false - - /badwords-list@1.0.0: - resolution: {integrity: sha512-oWhaSG67e+HQj3OGHQt2ucP+vAPm1wTbdp2aDHeuh4xlGXBdWwzZ//pfu6swf5gZ8iX0b7JgmSo8BhgybbqszA==} - dev: false - /bail@1.0.5: resolution: {integrity: sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==} @@ -18339,7 +18322,7 @@ packages: minimatch: 3.1.2 object.entries: 1.1.6 object.fromentries: 2.0.6 - semver: 6.3.0 + semver: 6.3.1 /eslint-plugin-jsx-a11y@6.7.1(eslint@8.46.0): resolution: {integrity: sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==} @@ -19234,7 +19217,7 @@ packages: fastify-plugin: 4.5.0 http-errors: 2.0.0 node-cache: 5.1.2 - node-fetch: 2.6.12 + node-fetch: 2.6.9 transitivePeerDependencies: - encoding dev: false @@ -24714,7 +24697,7 @@ packages: loopback-datasource-juggler: 3.36.1 loopback-filters: 1.1.1 loopback-phase: 3.4.0 - nodemailer: 6.9.3 + nodemailer: 6.9.4 nodemailer-direct-transport: 3.3.2 nodemailer-stub-transport: 1.1.0 serve-favicon: 2.5.0 @@ -26327,6 +26310,11 @@ packages: lower-case: 2.0.2 tslib: 2.6.1 + /no-profanity@1.4.2: + resolution: {integrity: sha512-mg9E7w0LitTCz6J3T65nZnSzPKN9qc1VHWW0Yn6HUkU/VDWdgLBWoB/fWd3tJcfAk9fuzxAFysYbqACLE0lRjg==} + engines: {node: '>=14.0.0'} + dev: false + /nocache@2.1.0: resolution: {integrity: sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==} engines: {node: '>=4.0.0'} @@ -26471,6 +26459,11 @@ packages: engines: {node: '>=6.0.0'} dev: false + /nodemailer@6.9.4: + resolution: {integrity: sha512-CXjQvrQZV4+6X5wP6ZIgdehJamI63MFoYFGGPtHudWym9qaEHDNdPzaj5bfMCvxG1vhAileSWW90q7nL0N36mA==} + engines: {node: '>=6.0.0'} + dev: false + /nodemon@2.0.16: resolution: {integrity: sha512-zsrcaOfTWRuUzBn3P44RDliLlp263Z/76FPoHFr3cFFkOz0lTPAcIw8dCzfdVIx/t3AtDYCZRCDkoCojJqaG3w==} engines: {node: '>=8.10.0'}