mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2025-12-07 20:17:02 +03:00
Add request validator rule names
This commit is contained in:
@@ -59,7 +59,7 @@ export async function postBranding(req: Request, res: Response) {
|
|||||||
const hashedIP = await getHashCache(getIP(req) + config.globalSalt as IPAddress);
|
const hashedIP = await getHashCache(getIP(req) + config.globalSalt as IPAddress);
|
||||||
const isBanned = await checkBanStatus(hashedUserID, hashedIP);
|
const isBanned = await checkBanStatus(hashedUserID, hashedIP);
|
||||||
|
|
||||||
if (isRequestInvalid({
|
const matchedRule = isRequestInvalid({
|
||||||
userAgent,
|
userAgent,
|
||||||
userAgentHeader: req.headers["user-agent"],
|
userAgentHeader: req.headers["user-agent"],
|
||||||
videoDuration,
|
videoDuration,
|
||||||
@@ -72,8 +72,9 @@ export async function postBranding(req: Request, res: Response) {
|
|||||||
downvote,
|
downvote,
|
||||||
},
|
},
|
||||||
endpoint: "dearrow-postBranding",
|
endpoint: "dearrow-postBranding",
|
||||||
})) {
|
});
|
||||||
sendNewUserWebhook(config.discordRejectedNewUserWebhookURL, hashedUserID, videoID, userAgent, req, videoDuration, title);
|
if (matchedRule !== null) {
|
||||||
|
sendNewUserWebhook(config.discordRejectedNewUserWebhookURL, hashedUserID, videoID, userAgent, req, videoDuration, title, matchedRule);
|
||||||
Logger.warn(`Dearrow submission rejected by request validator: ${hashedUserID} ${videoID} ${videoDuration} ${userAgent} ${req.headers["user-agent"]} ${title.title} ${thumbnail.timestamp}`);
|
Logger.warn(`Dearrow submission rejected by request validator: ${hashedUserID} ${videoID} ${videoDuration} ${userAgent} ${req.headers["user-agent"]} ${title.title} ${thumbnail.timestamp}`);
|
||||||
res.status(200).send("OK");
|
res.status(200).send("OK");
|
||||||
return;
|
return;
|
||||||
@@ -86,7 +87,7 @@ export async function postBranding(req: Request, res: Response) {
|
|||||||
res.status(403).send(permission.reason);
|
res.status(403).send(permission.reason);
|
||||||
return;
|
return;
|
||||||
} else if (permission.newUser) {
|
} else if (permission.newUser) {
|
||||||
sendNewUserWebhook(config.discordNewUserWebhookURL, hashedUserID, videoID, userAgent, req, videoDuration, title);
|
sendNewUserWebhook(config.discordNewUserWebhookURL, hashedUserID, videoID, userAgent, req, videoDuration, title, undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (videoDuration && thumbnail && await checkForWrongVideoDuration(videoID, videoDuration)) {
|
if (videoDuration && thumbnail && await checkForWrongVideoDuration(videoID, videoDuration)) {
|
||||||
@@ -210,7 +211,7 @@ export async function postBranding(req: Request, res: Response) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendNewUserWebhook(webhookUrl: string, hashedUserID: HashedUserID, videoID: VideoID, userAgent: any, req: Request, videoDuration: number, title: TitleSubmission) {
|
function sendNewUserWebhook(webhookUrl: string, hashedUserID: HashedUserID, videoID: VideoID, userAgent: any, req: Request, videoDuration: number, title: TitleSubmission, ruleName: string | undefined) {
|
||||||
if (!webhookUrl) return;
|
if (!webhookUrl) return;
|
||||||
|
|
||||||
axios.post(webhookUrl, {
|
axios.post(webhookUrl, {
|
||||||
@@ -226,6 +227,9 @@ function sendNewUserWebhook(webhookUrl: string, hashedUserID: HashedUserID, vide
|
|||||||
"thumbnail": {
|
"thumbnail": {
|
||||||
"url": getMaxResThumbnail(videoID),
|
"url": getMaxResThumbnail(videoID),
|
||||||
},
|
},
|
||||||
|
"footer": {
|
||||||
|
"text": ruleName === undefined ? `Caught by permission check` : `Caught by rule '${ruleName}'`,
|
||||||
|
},
|
||||||
}],
|
}],
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
|
|||||||
@@ -510,7 +510,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
|
|||||||
}
|
}
|
||||||
const userID: HashedUserID = await getHashCache(paramUserID);
|
const userID: HashedUserID = await getHashCache(paramUserID);
|
||||||
|
|
||||||
if (isRequestInvalid({
|
const matchedRule = isRequestInvalid({
|
||||||
userAgent,
|
userAgent,
|
||||||
userAgentHeader: req.headers["user-agent"],
|
userAgentHeader: req.headers["user-agent"],
|
||||||
videoDuration,
|
videoDuration,
|
||||||
@@ -519,8 +519,9 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
|
|||||||
service,
|
service,
|
||||||
segments,
|
segments,
|
||||||
endpoint: "sponsorblock-postSkipSegments"
|
endpoint: "sponsorblock-postSkipSegments"
|
||||||
})) {
|
});
|
||||||
sendNewUserWebhook(config.discordRejectedNewUserWebhookURL, userID, videoID, userAgent, req, videoDurationParam);
|
if (matchedRule !== null) {
|
||||||
|
sendNewUserWebhook(config.discordRejectedNewUserWebhookURL, userID, videoID, userAgent, req, videoDurationParam, matchedRule);
|
||||||
Logger.warn(`Sponsorblock submission rejected by request validator: ${userID} ${videoID} ${videoDurationParam} ${userAgent} ${req.headers["user-agent"]}`);
|
Logger.warn(`Sponsorblock submission rejected by request validator: ${userID} ${videoID} ${videoDurationParam} ${userAgent} ${req.headers["user-agent"]}`);
|
||||||
return res.status(200).send("OK");
|
return res.status(200).send("OK");
|
||||||
}
|
}
|
||||||
@@ -572,7 +573,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
|
|||||||
Logger.warn(`New user trying to submit: ${userID} ${videoID} ${videoDurationParam} ${userAgent} ${req.headers["user-agent"]}`);
|
Logger.warn(`New user trying to submit: ${userID} ${videoID} ${videoDurationParam} ${userAgent} ${req.headers["user-agent"]}`);
|
||||||
return res.status(403).send(permission.reason);
|
return res.status(403).send(permission.reason);
|
||||||
} else if (permission.newUser) {
|
} else if (permission.newUser) {
|
||||||
sendNewUserWebhook(config.discordNewUserWebhookURL, userID, videoID, userAgent, req, videoDurationParam);
|
sendNewUserWebhook(config.discordNewUserWebhookURL, userID, videoID, userAgent, req, videoDurationParam, undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Will be filled when submitting
|
// Will be filled when submitting
|
||||||
@@ -661,7 +662,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendNewUserWebhook(webhookUrl: string, userID: HashedUserID, videoID: any, userAgent: any, req: Request, videoDurationParam: VideoDuration) {
|
function sendNewUserWebhook(webhookUrl: string, userID: HashedUserID, videoID: any, userAgent: any, req: Request, videoDurationParam: VideoDuration, ruleName: string | undefined) {
|
||||||
if (!webhookUrl) return;
|
if (!webhookUrl) return;
|
||||||
|
|
||||||
axios.post(webhookUrl, {
|
axios.post(webhookUrl, {
|
||||||
@@ -676,6 +677,9 @@ function sendNewUserWebhook(webhookUrl: string, userID: HashedUserID, videoID: a
|
|||||||
"thumbnail": {
|
"thumbnail": {
|
||||||
"url": getMaxResThumbnail(videoID),
|
"url": getMaxResThumbnail(videoID),
|
||||||
},
|
},
|
||||||
|
"footer": {
|
||||||
|
"text": ruleName === undefined ? "Caught by permission check" : `Caught by rule '${ruleName}'`,
|
||||||
|
},
|
||||||
}],
|
}],
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export interface CustomPostgresReadOnlyConfig extends CustomPostgresConfig {
|
|||||||
|
|
||||||
export type ValidatorPattern = string | [string, string];
|
export type ValidatorPattern = string | [string, string];
|
||||||
export interface RequestValidatorRule {
|
export interface RequestValidatorRule {
|
||||||
|
ruleName?: string;
|
||||||
// mostly universal
|
// mostly universal
|
||||||
userAgent?: ValidatorPattern;
|
userAgent?: ValidatorPattern;
|
||||||
userAgentHeader?: ValidatorPattern;
|
userAgentHeader?: ValidatorPattern;
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export interface RequestValidatorInput {
|
|||||||
newUsername?: string;
|
newUsername?: string;
|
||||||
endpoint?: string;
|
endpoint?: string;
|
||||||
}
|
}
|
||||||
export type CompiledValidityCheck = (input: RequestValidatorInput) => boolean;
|
export type CompiledValidityCheck = (input: RequestValidatorInput) => string | null;
|
||||||
|
type CompiledPatternCheck = (input: RequestValidatorInput) => boolean;
|
||||||
type CompiledSegmentCheck = (input: IncomingSegment) => boolean;
|
type CompiledSegmentCheck = (input: IncomingSegment) => boolean;
|
||||||
type InputExtractor = (
|
type InputExtractor = (
|
||||||
input: RequestValidatorInput,
|
input: RequestValidatorInput,
|
||||||
@@ -46,7 +47,7 @@ function patternToRegex(pattern: ValidatorPattern): RegExp {
|
|||||||
function compilePattern(
|
function compilePattern(
|
||||||
pattern: ValidatorPattern,
|
pattern: ValidatorPattern,
|
||||||
extractor: InputExtractor,
|
extractor: InputExtractor,
|
||||||
): CompiledValidityCheck {
|
): CompiledPatternCheck {
|
||||||
const regex = patternToRegex(pattern);
|
const regex = patternToRegex(pattern);
|
||||||
|
|
||||||
return (input: RequestValidatorInput) => {
|
return (input: RequestValidatorInput) => {
|
||||||
@@ -72,11 +73,12 @@ function compileSegmentPattern(
|
|||||||
export function compileRules(
|
export function compileRules(
|
||||||
ruleDefinitions: RequestValidatorRule[],
|
ruleDefinitions: RequestValidatorRule[],
|
||||||
): CompiledValidityCheck {
|
): CompiledValidityCheck {
|
||||||
if (ruleDefinitions.length === 0) return () => false;
|
if (ruleDefinitions.length === 0) return () => null;
|
||||||
|
|
||||||
const rules: CompiledValidityCheck[] = [];
|
const rules: CompiledValidityCheck[] = [];
|
||||||
|
let untitledRuleCounter = 0;
|
||||||
for (const ruleDefinition of ruleDefinitions) {
|
for (const ruleDefinition of ruleDefinitions) {
|
||||||
const ruleComponents: CompiledValidityCheck[] = [];
|
const ruleComponents: CompiledPatternCheck[] = [];
|
||||||
const segmentRuleComponents: CompiledSegmentCheck[] = [];
|
const segmentRuleComponents: CompiledSegmentCheck[] = [];
|
||||||
for (const [ruleKey, rulePattern] of Object.entries(
|
for (const [ruleKey, rulePattern] of Object.entries(
|
||||||
ruleDefinition,
|
ruleDefinition,
|
||||||
@@ -217,6 +219,9 @@ export function compileRules(
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "ruleName":
|
||||||
|
// not a rule component
|
||||||
|
break;
|
||||||
default: {
|
default: {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const _exhaustive: never = ruleKey;
|
const _exhaustive: never = ruleKey;
|
||||||
@@ -239,22 +244,24 @@ export function compileRules(
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const ruleName = ruleDefinition.ruleName ?? `Untitled rule ${++untitledRuleCounter}`;
|
||||||
rules.push((input) => {
|
rules.push((input) => {
|
||||||
for (const rule of ruleComponents) {
|
for (const rule of ruleComponents) {
|
||||||
if (!rule(input)) return false;
|
if (!rule(input)) return null;
|
||||||
}
|
}
|
||||||
return true;
|
return ruleName;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return (input) => {
|
return (input) => {
|
||||||
for (const rule of rules) {
|
for (const rule of rules) {
|
||||||
if (rule(input)) return true;
|
const result = rule(input);
|
||||||
|
if (result !== null) return result;
|
||||||
}
|
}
|
||||||
return false;
|
return null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isRequestInvalid(input: RequestValidatorInput) {
|
export function isRequestInvalid(input: RequestValidatorInput): string | null {
|
||||||
compiledRules ??= compileRules(config.requestValidatorRules);
|
compiledRules ??= compileRules(config.requestValidatorRules);
|
||||||
return compiledRules(input);
|
return compiledRules(input);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,38 +21,43 @@ describe("Request validator", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("simple expected match", () => {
|
it("simple expected match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
compiledRuleset({
|
compiledRuleset({
|
||||||
userID: "asdfg",
|
userID: "asdfg",
|
||||||
}),
|
}),
|
||||||
|
"Untitled rule 1",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("case insensitive match", () => {
|
it("case insensitive match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
compiledRuleset({
|
compiledRuleset({
|
||||||
userID: "asDfg",
|
userID: "asDfg",
|
||||||
}),
|
}),
|
||||||
|
"Untitled rule 1",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("simple expected no match", () => {
|
it("simple expected no match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
userID: "125aaa",
|
userID: "125aaa",
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("missing field - no match", () => {
|
it("missing field - no match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
userAgent: "Mozilla/5.0",
|
userAgent: "Mozilla/5.0",
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("single case sensitive rule", () => {
|
describe("single case sensitive rule with name", () => {
|
||||||
const ruleset: RequestValidatorRule[] = [
|
const ruleset: RequestValidatorRule[] = [
|
||||||
{
|
{
|
||||||
|
ruleName: "Testing rule",
|
||||||
// tuple patterns allow setting regex flags
|
// tuple patterns allow setting regex flags
|
||||||
userID: ["^[a-z]+$", ""],
|
userID: ["^[a-z]+$", ""],
|
||||||
},
|
},
|
||||||
@@ -64,39 +69,44 @@ describe("Request validator", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("simple expected match", () => {
|
it("simple expected match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
compiledRuleset({
|
compiledRuleset({
|
||||||
userID: "asdfg",
|
userID: "asdfg",
|
||||||
}),
|
}),
|
||||||
|
"Testing rule",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("different casing", () => {
|
it("different casing", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
userID: "asDfg",
|
userID: "asDfg",
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("extra field match", () => {
|
it("extra field match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
compiledRuleset({
|
compiledRuleset({
|
||||||
userID: "asdfg",
|
userID: "asdfg",
|
||||||
userAgent: "Mozilla/5.0",
|
userAgent: "Mozilla/5.0",
|
||||||
}),
|
}),
|
||||||
|
"Testing rule",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("simple expected no match", () => {
|
it("simple expected no match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
userID: "125aaa",
|
userID: "125aaa",
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("missing field - no match", () => {
|
it("missing field - no match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
userAgent: "Mozilla/5.0",
|
userAgent: "Mozilla/5.0",
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -104,6 +114,7 @@ describe("Request validator", () => {
|
|||||||
describe("2-pattern rule", () => {
|
describe("2-pattern rule", () => {
|
||||||
const ruleset: RequestValidatorRule[] = [
|
const ruleset: RequestValidatorRule[] = [
|
||||||
{
|
{
|
||||||
|
ruleName: "Testing rule",
|
||||||
userID: ["^[a-z]+$", ""],
|
userID: ["^[a-z]+$", ""],
|
||||||
userAgent: "^Mozilla/5\\.0",
|
userAgent: "^Mozilla/5\\.0",
|
||||||
},
|
},
|
||||||
@@ -115,48 +126,54 @@ describe("Request validator", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("simple expected match", () => {
|
it("simple expected match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
compiledRuleset({
|
compiledRuleset({
|
||||||
userID: "asdfg",
|
userID: "asdfg",
|
||||||
userAgent: "Mozilla/5.0 Chromeium/213.7",
|
userAgent: "Mozilla/5.0 Chromeium/213.7",
|
||||||
}),
|
}),
|
||||||
|
"Testing rule",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("only matching one pattern - fail #1", () => {
|
it("only matching one pattern - fail #1", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
userID: "asDfg",
|
userID: "asDfg",
|
||||||
userAgent: "Mozilla/5.0 Chromeium/213.7",
|
userAgent: "Mozilla/5.0 Chromeium/213.7",
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("only matching one pattern - fail #2", () => {
|
it("only matching one pattern - fail #2", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
userID: "asdfg",
|
userID: "asdfg",
|
||||||
userAgent: "ReVanced/20.07.39",
|
userAgent: "ReVanced/20.07.39",
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("missing one of the fields - fail #1", () => {
|
it("missing one of the fields - fail #1", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
userID: "asdfg",
|
userID: "asdfg",
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("missing one of the fields - fail #2", () => {
|
it("missing one of the fields - fail #2", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
userAgent: "Mozilla/5.0 Chromeium/213.7",
|
userAgent: "Mozilla/5.0 Chromeium/213.7",
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("missing all fields - fail", () => {
|
it("missing all fields - fail", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
videoDuration: 21.37,
|
videoDuration: 21.37,
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -164,6 +181,7 @@ describe("Request validator", () => {
|
|||||||
describe("1-pattern segment rule", () => {
|
describe("1-pattern segment rule", () => {
|
||||||
const ruleset: RequestValidatorRule[] = [
|
const ruleset: RequestValidatorRule[] = [
|
||||||
{
|
{
|
||||||
|
ruleName: "Testing rule",
|
||||||
description: "mini_bomba",
|
description: "mini_bomba",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -174,7 +192,7 @@ describe("Request validator", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("simple expected match", () => {
|
it("simple expected match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
@@ -185,10 +203,11 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
"Testing rule",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("match on one of multiple segments", () => {
|
it("match on one of multiple segments", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
@@ -205,10 +224,11 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
"Testing rule",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("match on one of multiple segments with other missing field", () => {
|
it("match on one of multiple segments with other missing field", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
@@ -224,11 +244,12 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
"Testing rule",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("no match with one segment", () => {
|
it("no match with one segment", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
segment: ["1", "2"],
|
segment: ["1", "2"],
|
||||||
@@ -238,11 +259,12 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("no match with multiple segments", () => {
|
it("no match with multiple segments", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
segment: ["1", "2"],
|
segment: ["1", "2"],
|
||||||
@@ -258,11 +280,12 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("one segment missing field", () => {
|
it("one segment missing field", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
segment: ["1", "2"],
|
segment: ["1", "2"],
|
||||||
@@ -271,11 +294,12 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("multiple segments missing field", () => {
|
it("multiple segments missing field", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
segment: ["1", "2"],
|
segment: ["1", "2"],
|
||||||
@@ -289,20 +313,23 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("zero segments", () => {
|
it("zero segments", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [],
|
segments: [],
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("missing segments", () => {
|
it("missing segments", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
userAgent: "Mozilla/5.0",
|
userAgent: "Mozilla/5.0",
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -310,6 +337,7 @@ describe("Request validator", () => {
|
|||||||
describe("2-pattern segment rule", () => {
|
describe("2-pattern segment rule", () => {
|
||||||
const ruleset: RequestValidatorRule[] = [
|
const ruleset: RequestValidatorRule[] = [
|
||||||
{
|
{
|
||||||
|
ruleName: "Testing rule",
|
||||||
description: "mini_bomba",
|
description: "mini_bomba",
|
||||||
startTime: "\\.\\d",
|
startTime: "\\.\\d",
|
||||||
},
|
},
|
||||||
@@ -321,7 +349,7 @@ describe("Request validator", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("simple expected match", () => {
|
it("simple expected match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
@@ -332,10 +360,11 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
"Testing rule",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("match on one of multiple segments", () => {
|
it("match on one of multiple segments", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
@@ -352,10 +381,11 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
"Testing rule",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("match on one of multiple segments with other missing field", () => {
|
it("match on one of multiple segments with other missing field", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
@@ -371,11 +401,12 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
"Testing rule",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("no match with one segment #1", () => {
|
it("no match with one segment #1", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
segment: ["1", "2"],
|
segment: ["1", "2"],
|
||||||
@@ -385,11 +416,12 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("no match with one segment #2", () => {
|
it("no match with one segment #2", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
segment: ["1.1", "2"],
|
segment: ["1.1", "2"],
|
||||||
@@ -399,11 +431,12 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("no match with one segment #2", () => {
|
it("no match with one segment #2", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
segment: ["1", "2"],
|
segment: ["1", "2"],
|
||||||
@@ -413,11 +446,12 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("no match with multiple segments", () => {
|
it("no match with multiple segments", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
segment: ["1", "2"],
|
segment: ["1", "2"],
|
||||||
@@ -433,11 +467,12 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("no match with multiple segments with partial matches", () => {
|
it("no match with multiple segments with partial matches", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
segment: ["1.1", "2"],
|
segment: ["1.1", "2"],
|
||||||
@@ -453,11 +488,12 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("one segment missing field", () => {
|
it("one segment missing field", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
segment: ["1", "2"],
|
segment: ["1", "2"],
|
||||||
@@ -466,11 +502,12 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("multiple segments missing field", () => {
|
it("multiple segments missing field", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [
|
segments: [
|
||||||
{
|
{
|
||||||
segment: ["1", "2"],
|
segment: ["1", "2"],
|
||||||
@@ -484,20 +521,23 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("zero segments", () => {
|
it("zero segments", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
segments: [],
|
segments: [],
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("missing segments", () => {
|
it("missing segments", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
userAgent: "Mozilla/5.0",
|
userAgent: "Mozilla/5.0",
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -505,6 +545,7 @@ describe("Request validator", () => {
|
|||||||
describe("boolean rule", () => {
|
describe("boolean rule", () => {
|
||||||
const ruleset: RequestValidatorRule[] = [
|
const ruleset: RequestValidatorRule[] = [
|
||||||
{
|
{
|
||||||
|
ruleName: "Testing rule",
|
||||||
dearrowDownvote: true,
|
dearrowDownvote: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -515,28 +556,31 @@ describe("Request validator", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("simple expected match", () => {
|
it("simple expected match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
compiledRuleset({
|
compiledRuleset({
|
||||||
dearrow: {
|
dearrow: {
|
||||||
downvote: true,
|
downvote: true,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
"Testing rule",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("simple expected no match", () => {
|
it("simple expected no match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
dearrow: {
|
dearrow: {
|
||||||
downvote: false,
|
downvote: false,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("missing field - no match", () => {
|
it("missing field - no match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
userAgent: "Mozilla/5.0",
|
userAgent: "Mozilla/5.0",
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -544,6 +588,7 @@ describe("Request validator", () => {
|
|||||||
describe("mixed type rules", () => {
|
describe("mixed type rules", () => {
|
||||||
const ruleset: RequestValidatorRule[] = [
|
const ruleset: RequestValidatorRule[] = [
|
||||||
{
|
{
|
||||||
|
ruleName: "Testing rule",
|
||||||
titleOriginal: true,
|
titleOriginal: true,
|
||||||
title: "mini_bomba",
|
title: "mini_bomba",
|
||||||
},
|
},
|
||||||
@@ -555,7 +600,7 @@ describe("Request validator", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("simple expected match", () => {
|
it("simple expected match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
compiledRuleset({
|
compiledRuleset({
|
||||||
dearrow: {
|
dearrow: {
|
||||||
downvote: false,
|
downvote: false,
|
||||||
@@ -565,11 +610,12 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
"Testing rule",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("simple expected no match", () => {
|
it("simple expected no match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
dearrow: {
|
dearrow: {
|
||||||
downvote: false,
|
downvote: false,
|
||||||
title: {
|
title: {
|
||||||
@@ -578,11 +624,12 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("partial match #1", () => {
|
it("partial match #1", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
dearrow: {
|
dearrow: {
|
||||||
downvote: false,
|
downvote: false,
|
||||||
title: {
|
title: {
|
||||||
@@ -591,11 +638,12 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("partial match #2", () => {
|
it("partial match #2", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
dearrow: {
|
dearrow: {
|
||||||
downvote: false,
|
downvote: false,
|
||||||
title: {
|
title: {
|
||||||
@@ -604,34 +652,38 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("missing field - no match #1", () => {
|
it("missing field - no match #1", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
userAgent: "Mozilla/5.0",
|
userAgent: "Mozilla/5.0",
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("missing field - no match #2", () => {
|
it("missing field - no match #2", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
dearrow: {
|
dearrow: {
|
||||||
downvote: false,
|
downvote: false,
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("missing field - no match #3", () => {
|
it("missing field - no match #3", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
dearrow: {
|
dearrow: {
|
||||||
downvote: false,
|
downvote: false,
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
original: true,
|
original: true,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -639,11 +691,12 @@ describe("Request validator", () => {
|
|||||||
describe("two-rule ruleset", () => {
|
describe("two-rule ruleset", () => {
|
||||||
const ruleset: RequestValidatorRule[] = [
|
const ruleset: RequestValidatorRule[] = [
|
||||||
{
|
{
|
||||||
|
ruleName: "Rule one",
|
||||||
titleOriginal: true,
|
titleOriginal: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "mini_bomba",
|
title: "mini_bomba",
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
let compiledRuleset: CompiledValidityCheck;
|
let compiledRuleset: CompiledValidityCheck;
|
||||||
|
|
||||||
@@ -652,7 +705,7 @@ describe("Request validator", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("matches both", () => {
|
it("matches both", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
compiledRuleset({
|
compiledRuleset({
|
||||||
dearrow: {
|
dearrow: {
|
||||||
downvote: false,
|
downvote: false,
|
||||||
@@ -662,23 +715,11 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
"Rule one",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("matches 1", () => {
|
it("matches 1", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
compiledRuleset({
|
|
||||||
dearrow: {
|
|
||||||
downvote: false,
|
|
||||||
title: {
|
|
||||||
title: "mini_bomba gaming",
|
|
||||||
original: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("matches 2", () => {
|
|
||||||
assert.ok(
|
|
||||||
compiledRuleset({
|
compiledRuleset({
|
||||||
dearrow: {
|
dearrow: {
|
||||||
downvote: false,
|
downvote: false,
|
||||||
@@ -688,11 +729,26 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
"Rule one",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("matches 2", () => {
|
||||||
|
assert.equal(
|
||||||
|
compiledRuleset({
|
||||||
|
dearrow: {
|
||||||
|
downvote: false,
|
||||||
|
title: {
|
||||||
|
title: "mini_bomba gaming",
|
||||||
|
original: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
"Untitled rule 1",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("no match", () => {
|
it("no match", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
dearrow: {
|
dearrow: {
|
||||||
downvote: false,
|
downvote: false,
|
||||||
title: {
|
title: {
|
||||||
@@ -701,34 +757,38 @@ describe("Request validator", () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("missing both fields #1", () => {
|
it("missing both fields #1", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
userAgent: "Mozilla/5.0",
|
userAgent: "Mozilla/5.0",
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("missing both fields #2", () => {
|
it("missing both fields #2", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
dearrow: {
|
dearrow: {
|
||||||
downvote: false,
|
downvote: false,
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("missing both fields #3", () => {
|
it("missing both fields #3", () => {
|
||||||
assert.ok(
|
assert.equal(
|
||||||
!compiledRuleset({
|
compiledRuleset({
|
||||||
dearrow: {
|
dearrow: {
|
||||||
downvote: false,
|
downvote: false,
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
original: true,
|
original: true,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user