mirror of
https://github.com/documenso/documenso.git
synced 2025-11-23 21:21:37 +10:00
chore: team url slugify and profanity filter
Signed-off-by: Adithya Krishna <adi@documenso.com>
This commit is contained in:
27
package-lock.json
generated
27
package-lock.json
generated
@ -6008,6 +6008,12 @@
|
||||
"@types/estree": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/bad-words": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/bad-words/-/bad-words-3.0.3.tgz",
|
||||
"integrity": "sha512-jYdpTxDOJ+EENnsCwt8cOZhV/+4+qcwhks1igrOSg4zwwA17rsPqLsZpTo1l+OwViNu+5SPus0v5g7iGx+ofzA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/bcrypt": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz",
|
||||
@ -6906,6 +6912,22 @@
|
||||
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz",
|
||||
"integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw=="
|
||||
},
|
||||
"node_modules/bad-words": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/bad-words/-/bad-words-3.0.4.tgz",
|
||||
"integrity": "sha512-v/Q9uRPH4+yzDVLL4vR1+S9KoFgOEUl5s4axd6NIAq8SV2mradgi4E8lma/Y0cw1ltVdvyegCQQKffCPRCp8fg==",
|
||||
"dependencies": {
|
||||
"badwords-list": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/badwords-list": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/badwords-list/-/badwords-list-1.0.0.tgz",
|
||||
"integrity": "sha512-oWhaSG67e+HQj3OGHQt2ucP+vAPm1wTbdp2aDHeuh4xlGXBdWwzZ//pfu6swf5gZ8iX0b7JgmSo8BhgybbqszA=="
|
||||
},
|
||||
"node_modules/bail": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
|
||||
@ -19475,12 +19497,15 @@
|
||||
"@trpc/next": "^10.36.0",
|
||||
"@trpc/react-query": "^10.36.0",
|
||||
"@trpc/server": "^10.36.0",
|
||||
"bad-words": "^3.0.4",
|
||||
"luxon": "^3.4.0",
|
||||
"superjson": "^1.13.1",
|
||||
"ts-pattern": "^5.0.5",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {}
|
||||
"devDependencies": {
|
||||
"@types/bad-words": "^3.0.3"
|
||||
}
|
||||
},
|
||||
"packages/tsconfig": {
|
||||
"name": "@documenso/tsconfig",
|
||||
|
||||
25
packages/lib/utils/generate-url-slug.ts
Normal file
25
packages/lib/utils/generate-url-slug.ts
Normal file
@ -0,0 +1,25 @@
|
||||
const diacriticRegex = /\p{Diacritic}/gu;
|
||||
const nonAlphanumericRegex = /[^.\p{L}\p{N}\p{Zs}\p{Emoji}]+/gu;
|
||||
const whitespaceUnderscoreRegex = /[\s_#]+/g;
|
||||
const dashStartRegex = /^-+/;
|
||||
const multipleDotsRegex = /\.{2,}/g;
|
||||
|
||||
export const generateURLSlug = (str: string, forDisplayingInput?: boolean) => {
|
||||
if (!str) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const slug = str
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.normalize('NFD')
|
||||
.replace(diacriticRegex, '')
|
||||
.replace(nonAlphanumericRegex, '-')
|
||||
.replace(whitespaceUnderscoreRegex, '-')
|
||||
.replace(dashStartRegex, '') // Remove dashes from start
|
||||
.replace(multipleDotsRegex, '.'); // Replace consecutive periods with a single period
|
||||
|
||||
return forDisplayingInput ? slug : slug.replace(/-*$/g, ''); // Remove dashes from end
|
||||
};
|
||||
|
||||
export default generateURLSlug;
|
||||
@ -17,10 +17,13 @@
|
||||
"@trpc/next": "^10.36.0",
|
||||
"@trpc/react-query": "^10.36.0",
|
||||
"@trpc/server": "^10.36.0",
|
||||
"bad-words": "^3.0.4",
|
||||
"luxon": "^3.4.0",
|
||||
"superjson": "^1.13.1",
|
||||
"ts-pattern": "^5.0.5",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {}
|
||||
"devDependencies": {
|
||||
"@types/bad-words": "^3.0.3"
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,12 @@ import { z } from 'zod';
|
||||
|
||||
import { TeamMemberRole } from '@documenso/prisma/client';
|
||||
|
||||
import { generateURLSlug } from '@documenso/lib/utils/generate-url-slug';
|
||||
|
||||
import badWords from 'bad-words';
|
||||
|
||||
const filter = new badWords();
|
||||
|
||||
const GenericFindQuerySchema = z.object({
|
||||
term: z.string().optional(),
|
||||
page: z.number().optional(),
|
||||
@ -20,7 +26,12 @@ export const ZAddTeamEmailVerificationMutationSchema = z.object({
|
||||
|
||||
export const ZCreateTeamMutationSchema = z.object({
|
||||
name: z.string().min(1),
|
||||
url: z.string().min(1), // Todo: Teams - Apply lowercase, disallow certain symbols, disallow profanity.
|
||||
url: z.string().min(1).refine((value) => {
|
||||
const generatedSlug = generateURLSlug(value);
|
||||
return !filter.isProfane(value.toLowerCase()) && generatedSlug === value.toLowerCase();
|
||||
}, {
|
||||
message: 'URL contains inappropriate language or unsupported characters',
|
||||
}),
|
||||
});
|
||||
|
||||
export const ZCreateTeamMemberInvitesMutationSchema = z.object({
|
||||
@ -100,7 +111,12 @@ export const ZUpdateTeamMutationSchema = z.object({
|
||||
data: z.object({
|
||||
// Todo: Teams
|
||||
name: z.string().min(1),
|
||||
url: z.string().min(1), // Todo: Apply regex. Todo: lowercase, etc
|
||||
url: z.string().min(1).refine((value) => {
|
||||
const generatedSlug = generateURLSlug(value);
|
||||
return !filter.isProfane(value.toLowerCase()) && generatedSlug === value.toLowerCase();
|
||||
}, {
|
||||
message: 'URL contains inappropriate language or unsupported characters',
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user