diff --git a/package-lock.json b/package-lock.json index 1da7a64a..c0f72f58 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9882,13 +9882,23 @@ "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" + }, + "dependencies": { + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + } } }, "regexp-tree": { "version": "0.1.11", "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.11.tgz", - "integrity": "sha512-7/l/DgapVVDzZobwMCCgMlqiqyLFJ0cduo/j+3BcDJIB+yJdsYCfKuI3l/04NV+H/rfNRdPIDbXNZHM9XvQatg==", - "dev": true + "integrity": "sha512-7/l/DgapVVDzZobwMCCgMlqiqyLFJ0cduo/j+3BcDJIB+yJdsYCfKuI3l/04NV+H/rfNRdPIDbXNZHM9XvQatg==" }, "regexpu-core": { "version": "4.5.4", @@ -10122,12 +10132,11 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.0.2.tgz", + "integrity": "sha512-rRALJT0mh4qVFIJ9HvfjKDN77F9vp7kltOpFFI/8e6oKyHFmmxz4aSkY/YVauRDe7U0RrHdw9Lsxdel3E19s0A==", "requires": { - "ret": "~0.1.10" + "regexp-tree": "~0.1.1" } }, "safer-buffer": { @@ -10887,6 +10896,17 @@ "extend-shallow": "^3.0.2", "regex-not": "^1.0.2", "safe-regex": "^1.1.0" + }, + "dependencies": { + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + } } }, "to-regex-range": { diff --git a/package.json b/package.json index 87cb7144..117f548d 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "passport-custom": "^1.0.5", "passport-oauth2": "^1.5.0", "reflect-metadata": "^0.1.12", + "safe-regex": "^2.0.2", "seedrandom": "^3.0.1", "tlds": "^1.203.1", "tmp": "0.0.33", diff --git a/src/plugins/Censor.ts b/src/plugins/Censor.ts index 7ee32dca..5d67fa5a 100644 --- a/src/plugins/Censor.ts +++ b/src/plugins/Censor.ts @@ -17,6 +17,7 @@ import { SavedMessage } from "../data/entities/SavedMessage"; import { ZeppelinPlugin } from "./ZeppelinPlugin"; import cloneDeep from "lodash.clonedeep"; import * as t from "io-ts"; +import { TSafeRegexString } from "../validatorUtils"; const ConfigSchema = t.type({ filter_zalgo: t.boolean, @@ -31,12 +32,13 @@ const ConfigSchema = t.type({ domain_blacklist: tNullable(t.array(t.string)), blocked_tokens: tNullable(t.array(t.string)), blocked_words: tNullable(t.array(t.string)), - blocked_regex: tNullable(t.array(t.string)), + blocked_regex: tNullable(t.array(TSafeRegexString)), }); type TConfigSchema = t.TypeOf; export class CensorPlugin extends ZeppelinPlugin { public static pluginName = "censor"; + protected static configSchema = ConfigSchema; protected serverLogs: GuildLogs; protected savedMessages: GuildSavedMessages; diff --git a/src/validatorUtils.ts b/src/validatorUtils.ts index a1ca1944..1ddd758e 100644 --- a/src/validatorUtils.ts +++ b/src/validatorUtils.ts @@ -1,8 +1,19 @@ import * as t from "io-ts"; import { pipe } from "fp-ts/lib/pipeable"; -import { fold } from "fp-ts/lib/Either"; +import { fold, either } from "fp-ts/lib/Either"; import { noop } from "./utils"; import deepDiff from "deep-diff"; +import safeRegex from "safe-regex"; + +export const TSafeRegexString = new t.Type( + "TSafeRegexString", + (s): s is string => typeof s === "string", + (from, to) => + either.chain(t.string.validate(from, to), s => { + return safeRegex(s) ? t.success(s) : t.failure(from, to, "Unsafe regex"); + }), + s => s, +); // From io-ts/lib/PathReporter function stringify(v) { @@ -35,10 +46,12 @@ const report = fold((errors: any) => { return errors.map(err => { if (err.message) return err.message; const context = err.context.map(c => c.key).filter(k => k && !k.startsWith("{")); + if (context.length > 0 && !isNaN(context[context.length - 1])) context.splice(-1); + const value = stringify(err.value); return value === undefined ? `<${context.join("/")}> is required` - : `Invalid value <${stringify(err.value)}> supplied to <${context.join("/")}>`; + : `Invalid value supplied to <${context.join("/")}>`; }); }, noop);