diff --git a/common/form/validators/isUsername.ts b/common/form/validators/isUsername.ts new file mode 100644 index 00000000..0aa33def --- /dev/null +++ b/common/form/validators/isUsername.ts @@ -0,0 +1,15 @@ +export const isUsername = () => { + return (value: string): string | false => { + for (const forbidden of ["discord", "```", "system message"]) { + if (value.toLowerCase().includes(forbidden)) { + return `Username cannot contain "${forbidden}"` + } + } + for (const forbidden of ["everyone", "here"]) { + if (value.toLowerCase() === forbidden) { + return `Username cannot be "${forbidden}"` + } + } + return false + } +} diff --git a/modules/editor/data/validation/isMessage.ts b/modules/editor/data/validation/isMessage.ts index 536f5ef7..c947fb62 100644 --- a/modules/editor/data/validation/isMessage.ts +++ b/modules/editor/data/validation/isMessage.ts @@ -5,6 +5,7 @@ import { isNumber } from "./isNumber" import { isShape } from "./isShape" import { isString } from "./isString" import { isUrl } from "./isUrl" +import { isUsername } from "./isUsername" import { length } from "./length" import { noExcessiveKeys } from "./noExcessiveKeys" import { nullable } from "./nullable" @@ -26,7 +27,7 @@ export const isMessage: Validator = first( isShape({ content: optional(nullable(first(isString, length(1, 2000)))), embeds: optional(nullable(first(contains(isEmbed), length(1, 10)))), - username: optional(first(isString, length(1, 256))), + username: optional(first(isUsername, length(1, 80))), avatar_url: optional(isUrl), thread_name: optional(first(isString, length(1, 100))), flags: optional(isNumber), diff --git a/modules/editor/data/validation/isUsername.ts b/modules/editor/data/validation/isUsername.ts new file mode 100644 index 00000000..db23a137 --- /dev/null +++ b/modules/editor/data/validation/isUsername.ts @@ -0,0 +1,11 @@ +import { first } from "./first" +import { isString } from "./isString" +import type { Validator } from "./Validator" + +export const isUsername: Validator = first(isString, (value, key) => + !/(^(everyone|here)$)|discord|```|system message/i.test(value as string) + ? [] + : [ + `${key}: Cannot contain "discord", "system message", or "\`\`\`", and cannot be "here" or "everyone"`, + ], +) diff --git a/modules/message/state/editorForm.ts b/modules/message/state/editorForm.ts index 9662e7bd..9a82e070 100644 --- a/modules/message/state/editorForm.ts +++ b/modules/message/state/editorForm.ts @@ -8,6 +8,7 @@ import { SubForm, } from "mstform" import { isUrl } from "../../../common/form/validators/isUrl" +import { isUsername } from "../../../common/form/validators/isUsername" import { matchesRegex } from "../../../common/form/validators/matchesRegex" import { maxLength } from "../../../common/form/validators/maxLength" import { EditorManager, EditorManagerLike } from "../../editor/EditorManager" @@ -21,7 +22,7 @@ export const editorForm = new Form(EditorManager, { }), username: new Field(converters.string, { controlled: controlled.object, - validators: [maxLength(80)], + validators: [isUsername(), maxLength(80)], }), avatar: new Field(converters.string, { controlled: controlled.object,