@fsvreddit/bot-bouncer-evaluation 0.7.40 → 0.7.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/allEvaluators.d.ts +2 -2
- package/dist/userEvaluation/EvaluateBadDisplayname.js +1 -5
- package/dist/userEvaluation/EvaluateBadDisplaynameDefinedHandles.d.ts +2 -0
- package/dist/userEvaluation/EvaluateBadDisplaynameDefinedHandles.js +6 -3
- package/dist/userEvaluation/EvaluateBadUsername.d.ts +2 -0
- package/dist/userEvaluation/EvaluateBadUsername.js +6 -3
- package/dist/userEvaluation/EvaluateBioText.d.ts +3 -1
- package/dist/userEvaluation/EvaluateBioText.js +32 -18
- package/dist/userEvaluation/EvaluateBioTextDefinedHandles.d.ts +2 -0
- package/dist/userEvaluation/EvaluateBioTextDefinedHandles.js +11 -13
- package/dist/userEvaluation/EvaluateBotGroupAdvanced.d.ts +2 -1
- package/dist/userEvaluation/EvaluateBotGroupAdvanced.js +25 -4
- package/dist/userEvaluation/EvaluateCommentPhrase.d.ts +2 -0
- package/dist/userEvaluation/EvaluateCommentPhrase.js +9 -8
- package/dist/userEvaluation/EvaluatePostTitle.d.ts +2 -0
- package/dist/userEvaluation/EvaluatePostTitle.js +23 -7
- package/dist/userEvaluation/EvaluatePostTitleDefinedHandles.d.ts +2 -0
- package/dist/userEvaluation/EvaluatePostTitleDefinedHandles.js +8 -5
- package/dist/userEvaluation/EvaluatePostTitleMulti.d.ts +2 -0
- package/dist/userEvaluation/EvaluatePostTitleMulti.js +9 -5
- package/dist/userEvaluation/EvaluateSocialLinks.d.ts +0 -1
- package/dist/userEvaluation/EvaluateSocialLinks.js +0 -19
- package/dist/userEvaluation/EvaluateTextInNsfwImages.js +1 -1
- package/dist/userEvaluation/EvaluateWorldTraveller.d.ts +2 -0
- package/dist/userEvaluation/EvaluateWorldTraveller.js +8 -7
- package/dist/userEvaluation/UserEvaluatorBase.d.ts +2 -0
- package/dist/userEvaluation/UserEvaluatorBase.js +3 -0
- package/package.json +5 -5
package/dist/allEvaluators.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EvaluatePinnedPostTitles } from "./userEvaluation/EvaluatePinnedPostTitle.js";
|
|
2
|
+
import { EvaluateSocialLinks } from "./userEvaluation/EvaluateSocialLinks.js";
|
|
2
3
|
import { EvaluateBotGroupAdvanced } from "./userEvaluation/EvaluateBotGroupAdvanced.js";
|
|
3
|
-
import { EvaluateWarmupBot } from "./userEvaluation/EvaluateWarmupBot.js";
|
|
4
4
|
import { EvaluateBotGroupAdvancedInternal } from "./userEvaluation/EvaluateBotGroupAdvancedInternal.js";
|
|
5
5
|
import { EvaluateLinkReuse } from "./userEvaluation/EvaluateLinkReuse.js";
|
|
6
6
|
/**
|
|
@@ -12,5 +12,5 @@ import { EvaluateLinkReuse } from "./userEvaluation/EvaluateLinkReuse.js";
|
|
|
12
12
|
* As a result, order entries to prioritise faster evaluators that do not need to
|
|
13
13
|
* reference social links or account history first.
|
|
14
14
|
*/
|
|
15
|
-
export declare const ALL_EVALUATORS: (typeof EvaluatePinnedPostTitles | typeof
|
|
15
|
+
export declare const ALL_EVALUATORS: (typeof EvaluatePinnedPostTitles | typeof EvaluateSocialLinks | typeof EvaluateBotGroupAdvanced | typeof EvaluateLinkReuse)[];
|
|
16
16
|
export declare const ALL_INTERNAL_EVALUATORS: (typeof EvaluateBotGroupAdvancedInternal)[];
|
|
@@ -15,11 +15,7 @@ class EvaluateBadDisplayName extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
15
15
|
this.banContentThreshold = 0;
|
|
16
16
|
}
|
|
17
17
|
getBadDisplayNameRegexes() {
|
|
18
|
-
|
|
19
|
-
const bannableDisplayNameRegexes = this.getVariable("regexes", []);
|
|
20
|
-
const ignoredDisplayNameRegexes = this.getVariable("ignoredRegexes", []);
|
|
21
|
-
this.badDisplayNameRegexes = bannableDisplayNameRegexes.filter(regex => !ignoredDisplayNameRegexes.includes(regex));
|
|
22
|
-
}
|
|
18
|
+
this.badDisplayNameRegexes ?? (this.badDisplayNameRegexes = this.getVariable("regexes", []));
|
|
23
19
|
return this.badDisplayNameRegexes;
|
|
24
20
|
}
|
|
25
21
|
isBadDisplayName(displayName) {
|
|
@@ -8,6 +8,8 @@ export declare class EvaluateBadDisplayNameDefinedHandles extends UserEvaluatorB
|
|
|
8
8
|
banContentThreshold: number;
|
|
9
9
|
private isBadDisplayName;
|
|
10
10
|
gatherRegexes(): EvaluatorRegex[];
|
|
11
|
+
private compiledRegexes;
|
|
12
|
+
private getCompiledRegexes;
|
|
11
13
|
validateVariables(): ValidationIssue[];
|
|
12
14
|
preEvaluateComment(_: CommentCreate): boolean;
|
|
13
15
|
preEvaluatePost(_: Post): boolean;
|
|
@@ -15,12 +15,11 @@ class EvaluateBadDisplayNameDefinedHandles extends UserEvaluatorBase_js_1.UserEv
|
|
|
15
15
|
if (!displayName) {
|
|
16
16
|
return false;
|
|
17
17
|
}
|
|
18
|
-
const
|
|
19
|
-
const matchedRegexes = regexes.filter(regex => new RegExp(regex, "u").test(displayName));
|
|
18
|
+
const matchedRegexes = this.getCompiledRegexes().filter(regex => regex.test(displayName));
|
|
20
19
|
if (matchedRegexes.length === 0) {
|
|
21
20
|
return false;
|
|
22
21
|
}
|
|
23
|
-
this.addHitReason(`Display name matches regexes: ${matchedRegexes.map(r => `\`${r}\``).join(", ")}`);
|
|
22
|
+
this.addHitReason(`Display name matches regexes: ${matchedRegexes.map(r => `\`${r.source}\``).join(", ")}`);
|
|
24
23
|
return true;
|
|
25
24
|
}
|
|
26
25
|
gatherRegexes() {
|
|
@@ -41,6 +40,10 @@ class EvaluateBadDisplayNameDefinedHandles extends UserEvaluatorBase_js_1.UserEv
|
|
|
41
40
|
flags: "u",
|
|
42
41
|
})));
|
|
43
42
|
}
|
|
43
|
+
getCompiledRegexes() {
|
|
44
|
+
this.compiledRegexes ?? (this.compiledRegexes = this.gatherRegexes().map(r => new RegExp(r.regex, r.flags)));
|
|
45
|
+
return this.compiledRegexes;
|
|
46
|
+
}
|
|
44
47
|
validateVariables() {
|
|
45
48
|
const results = [];
|
|
46
49
|
let regexes;
|
|
@@ -9,6 +9,8 @@ export declare class EvaluateBadUsername extends UserEvaluatorBase {
|
|
|
9
9
|
private isBadUsername;
|
|
10
10
|
validateVariables(): ValidationIssue[];
|
|
11
11
|
gatherRegexes(): EvaluatorRegex[];
|
|
12
|
+
private compiledRegexes;
|
|
13
|
+
private getCompiledRegexes;
|
|
12
14
|
preEvaluateComment(event: CommentCreate): boolean;
|
|
13
15
|
preEvaluatePost(post: Post): boolean;
|
|
14
16
|
preEvaluateUser(user: UserExtended): boolean;
|
|
@@ -19,10 +19,9 @@ class EvaluateBadUsername extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
19
19
|
if (!username) {
|
|
20
20
|
return false;
|
|
21
21
|
}
|
|
22
|
-
const
|
|
23
|
-
const matchedRegex = regexes.find(regex => new RegExp(regex).test(username));
|
|
22
|
+
const matchedRegex = this.getCompiledRegexes().find(regex => regex.test(username));
|
|
24
23
|
if (matchedRegex) {
|
|
25
|
-
this.addHitReason(`Username matches regex: ${(0, markdown_escape_1.default)(matchedRegex)}`);
|
|
24
|
+
this.addHitReason(`Username matches regex: ${(0, markdown_escape_1.default)(matchedRegex.source)}`);
|
|
26
25
|
}
|
|
27
26
|
return matchedRegex !== undefined;
|
|
28
27
|
}
|
|
@@ -51,6 +50,10 @@ class EvaluateBadUsername extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
51
50
|
regex,
|
|
52
51
|
})));
|
|
53
52
|
}
|
|
53
|
+
getCompiledRegexes() {
|
|
54
|
+
this.compiledRegexes ?? (this.compiledRegexes = this.getVariable("regexes", []).map(regex => new RegExp(regex)));
|
|
55
|
+
return this.compiledRegexes;
|
|
56
|
+
}
|
|
54
57
|
preEvaluateComment(event) {
|
|
55
58
|
return this.isBadUsername(event.author?.name);
|
|
56
59
|
}
|
|
@@ -8,10 +8,12 @@ export declare class EvaluateBioText extends UserEvaluatorBase {
|
|
|
8
8
|
banContentThreshold: number;
|
|
9
9
|
private bioText;
|
|
10
10
|
private getBioText;
|
|
11
|
-
preEvaluateComment(event: CommentCreate): boolean;
|
|
12
11
|
validateVariables(): ValidationIssue[];
|
|
13
12
|
getVariableOverrides(): Record<string, unknown>;
|
|
14
13
|
gatherRegexes(): EvaluatorRegex[];
|
|
14
|
+
private compiledRegexes;
|
|
15
|
+
private getCompiledRegexes;
|
|
16
|
+
preEvaluateComment(event: CommentCreate): boolean;
|
|
15
17
|
preEvaluatePost(_: Post): boolean;
|
|
16
18
|
preEvaluateUser(user: UserExtended): boolean;
|
|
17
19
|
evaluate(user: UserExtended): boolean;
|
|
@@ -14,17 +14,9 @@ class EvaluateBioText extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
14
14
|
this.banContentThreshold = 0;
|
|
15
15
|
}
|
|
16
16
|
getBioText() {
|
|
17
|
-
|
|
18
|
-
const bannableBioText = this.getVariable("bantext", []);
|
|
19
|
-
const ignoredBanText = this.getVariable("ignoredBanText", []);
|
|
20
|
-
this.bioText = bannableBioText.filter(bioText => !ignoredBanText.includes(bioText));
|
|
21
|
-
}
|
|
17
|
+
this.bioText ?? (this.bioText = this.getVariable("bantext", []));
|
|
22
18
|
return this.bioText;
|
|
23
19
|
}
|
|
24
|
-
preEvaluateComment(event) {
|
|
25
|
-
const problematicBioText = this.getBioText();
|
|
26
|
-
return problematicBioText.some(bioText => event.author?.description && new RegExp(bioText, "u").test(event.author.description));
|
|
27
|
-
}
|
|
28
20
|
validateVariables() {
|
|
29
21
|
const results = [];
|
|
30
22
|
const regexes = this.getVariable("bantext", []);
|
|
@@ -62,30 +54,52 @@ class EvaluateBioText extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
62
54
|
flags: "u",
|
|
63
55
|
}));
|
|
64
56
|
}
|
|
57
|
+
getCompiledRegexes() {
|
|
58
|
+
this.compiledRegexes ?? (this.compiledRegexes = this.getBioText().map(bio => new RegExp(bio, "u")));
|
|
59
|
+
return this.compiledRegexes;
|
|
60
|
+
}
|
|
61
|
+
preEvaluateComment(event) {
|
|
62
|
+
if (!event.author?.description) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
return this.getCompiledRegexes().some(regex => event.author?.description && regex.test(event.author.description));
|
|
66
|
+
}
|
|
65
67
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
66
68
|
preEvaluatePost(_) {
|
|
67
69
|
const bannableBioText = this.getBioText();
|
|
68
70
|
return bannableBioText.length > 0;
|
|
69
71
|
}
|
|
70
72
|
preEvaluateUser(user) {
|
|
71
|
-
|
|
72
|
-
if (bannableBioText.length === 0) {
|
|
73
|
+
if (!user.userDescription) {
|
|
73
74
|
return false;
|
|
74
75
|
}
|
|
75
76
|
if (user.commentKarma > 2000 && user.linkKarma > 2000) {
|
|
76
77
|
return false;
|
|
77
78
|
}
|
|
78
|
-
return
|
|
79
|
+
return this.getCompiledRegexes().some(regex => user.userDescription && regex.test(user.userDescription));
|
|
79
80
|
}
|
|
80
81
|
evaluate(user) {
|
|
81
|
-
|
|
82
|
-
if (
|
|
83
|
-
|
|
82
|
+
let matchedRegex;
|
|
83
|
+
if (this.verboseLogging) {
|
|
84
|
+
matchedRegex = this.getCompiledRegexes().find((regex) => {
|
|
85
|
+
if (!user.userDescription) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
const start = Date.now();
|
|
89
|
+
const result = regex.test(user.userDescription);
|
|
90
|
+
const end = Date.now();
|
|
91
|
+
if (end - start > this.regexWarnThreshold) {
|
|
92
|
+
console.log(`${this.name}: Regex took ${end - start}ms for regex: ${regex.source}`);
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
matchedRegex = this.getCompiledRegexes().find(regex => user.userDescription && regex.test(user.userDescription));
|
|
84
99
|
}
|
|
85
|
-
|
|
86
|
-
if (bannableBioTextFound) {
|
|
100
|
+
if (matchedRegex) {
|
|
87
101
|
this.canAutoBan = true;
|
|
88
|
-
this.addHitReason(`Bio text matched regex: ${(0, markdown_escape_1.default)(
|
|
102
|
+
this.addHitReason(`Bio text matched regex: ${(0, markdown_escape_1.default)(matchedRegex.source)}`);
|
|
89
103
|
}
|
|
90
104
|
else {
|
|
91
105
|
return false;
|
|
@@ -7,6 +7,8 @@ export declare class EvaluateBioTextDefinedHandles extends UserEvaluatorBase {
|
|
|
7
7
|
shortname: string;
|
|
8
8
|
banContentThreshold: number;
|
|
9
9
|
private getHandles;
|
|
10
|
+
private compiledRegexes;
|
|
11
|
+
private getCompiledRegexes;
|
|
10
12
|
preEvaluateComment(event: CommentCreate): boolean;
|
|
11
13
|
validateVariables(): ValidationIssue[];
|
|
12
14
|
gatherRegexes(): EvaluatorRegex[];
|
|
@@ -22,9 +22,15 @@ class EvaluateBioTextDefinedHandles extends UserEvaluatorBase_js_1.UserEvaluator
|
|
|
22
22
|
}
|
|
23
23
|
return parsed.body.map(part => part.raw);
|
|
24
24
|
}
|
|
25
|
+
getCompiledRegexes() {
|
|
26
|
+
this.compiledRegexes ?? (this.compiledRegexes = this.gatherRegexes().map(r => new RegExp(r.regex, "u")));
|
|
27
|
+
return this.compiledRegexes;
|
|
28
|
+
}
|
|
25
29
|
preEvaluateComment(event) {
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
if (!event.author?.description) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
return this.getCompiledRegexes().some(regex => event.author?.description && regex.test(event.author.description));
|
|
28
34
|
}
|
|
29
35
|
validateVariables() {
|
|
30
36
|
const results = [];
|
|
@@ -70,29 +76,21 @@ class EvaluateBioTextDefinedHandles extends UserEvaluatorBase_js_1.UserEvaluator
|
|
|
70
76
|
if (!user.userDescription) {
|
|
71
77
|
return false;
|
|
72
78
|
}
|
|
73
|
-
const regexes = this.gatherRegexes().map(r => r.regex);
|
|
74
|
-
if (regexes.length === 0) {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
79
|
if (user.commentKarma > 2000 && user.linkKarma > 2000) {
|
|
78
80
|
return false;
|
|
79
81
|
}
|
|
80
|
-
return
|
|
82
|
+
return this.getCompiledRegexes().some(regex => user.userDescription && regex.test(user.userDescription));
|
|
81
83
|
}
|
|
82
84
|
evaluate(user) {
|
|
83
85
|
if (!user.userDescription) {
|
|
84
86
|
return false;
|
|
85
87
|
}
|
|
86
|
-
const
|
|
87
|
-
if (regexes.length === 0) {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
const bannableBioTextFound = regexes.filter(bio => user.userDescription && new RegExp(bio, "u").test(user.userDescription));
|
|
88
|
+
const bannableBioTextFound = this.getCompiledRegexes().filter(regex => user.userDescription && regex.test(user.userDescription));
|
|
91
89
|
if (bannableBioTextFound.length === 0) {
|
|
92
90
|
return false;
|
|
93
91
|
}
|
|
94
92
|
this.canAutoBan = true;
|
|
95
|
-
this.addHitReason(`Bio text matched regexes: ${bannableBioTextFound.map(
|
|
93
|
+
this.addHitReason(`Bio text matched regexes: ${bannableBioTextFound.map(regex => `\`${regex.source}\``).join(", ")}`);
|
|
96
94
|
return user.nsfw || this.getPosts().some(post => post.isNsfw());
|
|
97
95
|
}
|
|
98
96
|
}
|
|
@@ -85,11 +85,12 @@ export declare class EvaluateBotGroupAdvanced extends UserEvaluatorBase {
|
|
|
85
85
|
name: string;
|
|
86
86
|
shortname: string;
|
|
87
87
|
banContentThreshold: number;
|
|
88
|
-
private verboseLogging;
|
|
89
88
|
private redis;
|
|
90
89
|
allowNewFeatures: boolean;
|
|
91
90
|
private evaluationError;
|
|
92
91
|
constructor(context: TriggerContext, history: (Post | Comment)[], socialLinks: UserSocialLink[] | undefined, variables: Record<string, unknown>);
|
|
92
|
+
private compiledRegexes;
|
|
93
|
+
private getCompiledRegex;
|
|
93
94
|
private anyRegexMatches;
|
|
94
95
|
getBotGroups(): BotGroup[];
|
|
95
96
|
validateVariables(): ValidationIssue[];
|
|
@@ -457,8 +457,8 @@ class EvaluateBotGroupAdvanced extends UserEvaluatorBase_js_1.UserEvaluatorBase
|
|
|
457
457
|
this.name = "Bot Group Advanced";
|
|
458
458
|
this.shortname = "botgroupadvanced";
|
|
459
459
|
this.banContentThreshold = 0; // No content ban threshold for this evaluator to support account properties only checks
|
|
460
|
-
this.verboseLogging = false;
|
|
461
460
|
this.allowNewFeatures = false;
|
|
461
|
+
this.compiledRegexes = new Map();
|
|
462
462
|
this.cachedPostProperties = {};
|
|
463
463
|
this.postPropertiesStatistics = {
|
|
464
464
|
totalTime: 0,
|
|
@@ -467,11 +467,32 @@ class EvaluateBotGroupAdvanced extends UserEvaluatorBase_js_1.UserEvaluatorBase
|
|
|
467
467
|
cacheMisses: 0,
|
|
468
468
|
errors: 0,
|
|
469
469
|
};
|
|
470
|
-
this.verboseLogging = this.getVariable("verboseLogging", false);
|
|
471
470
|
this.redis = context.appSlug === constants_js_1.MAIN_APP_NAME ? context.redis.global : context.redis;
|
|
472
471
|
}
|
|
472
|
+
getCompiledRegex(regex) {
|
|
473
|
+
const result = this.compiledRegexes.get(regex);
|
|
474
|
+
if (result) {
|
|
475
|
+
return result;
|
|
476
|
+
}
|
|
477
|
+
const compiledRegex = new RegExp(regex, "u");
|
|
478
|
+
this.compiledRegexes.set(regex, compiledRegex);
|
|
479
|
+
return compiledRegex;
|
|
480
|
+
}
|
|
473
481
|
anyRegexMatches(input, regexes) {
|
|
474
|
-
|
|
482
|
+
if (this.verboseLogging) {
|
|
483
|
+
return regexes.some((regex) => {
|
|
484
|
+
const start = Date.now();
|
|
485
|
+
const result = this.getCompiledRegex(regex).test(input);
|
|
486
|
+
const end = Date.now();
|
|
487
|
+
if (end - start > this.regexWarnThreshold) {
|
|
488
|
+
console.warn(`Evaluation: Regex took ${end - start}ms: ${regex}`);
|
|
489
|
+
}
|
|
490
|
+
return result;
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
return regexes.some(regex => this.getCompiledRegex(regex).test(input));
|
|
495
|
+
}
|
|
475
496
|
}
|
|
476
497
|
getBotGroups() {
|
|
477
498
|
const groups = this.getAllVariables("group");
|
|
@@ -1310,7 +1331,7 @@ class EvaluateBotGroupAdvanced extends UserEvaluatorBase_js_1.UserEvaluatorBase
|
|
|
1310
1331
|
continue;
|
|
1311
1332
|
}
|
|
1312
1333
|
const validSubmitterNames = new Set(Array.isArray(group.submitterName) ? group.submitterName : [group.submitterName]);
|
|
1313
|
-
if (!validSubmitterNames.has(this.submitterName)) {
|
|
1334
|
+
if (!validSubmitterNames.has(this.submitterName) && !validSubmitterNames.has("*")) {
|
|
1314
1335
|
continue;
|
|
1315
1336
|
}
|
|
1316
1337
|
}
|
|
@@ -8,6 +8,8 @@ export declare class EvaluateCommentPhrase extends UserEvaluatorBase {
|
|
|
8
8
|
banContentThreshold: number;
|
|
9
9
|
validateVariables(): ValidationIssue[];
|
|
10
10
|
gatherRegexes(): EvaluatorRegex[];
|
|
11
|
+
private compiledRegexes;
|
|
12
|
+
private getCompiledRegexes;
|
|
11
13
|
private eligibleComment;
|
|
12
14
|
preEvaluateComment(event: CommentCreate): boolean;
|
|
13
15
|
preEvaluatePost(_: Post): boolean;
|
|
@@ -20,11 +20,11 @@ class EvaluateCommentPhrase extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
20
20
|
regex = new RegExp(regexVal);
|
|
21
21
|
}
|
|
22
22
|
catch {
|
|
23
|
-
results.push({ severity: "error", message: `Invalid regex in
|
|
23
|
+
results.push({ severity: "error", message: `Invalid regex in comment phrase: ${regexVal}` });
|
|
24
24
|
continue;
|
|
25
25
|
}
|
|
26
26
|
if (regex.test("")) {
|
|
27
|
-
results.push({ severity: "error", message: `
|
|
27
|
+
results.push({ severity: "error", message: `Comment phrase regex is too greedy: ${regexVal}` });
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
return results;
|
|
@@ -37,14 +37,16 @@ class EvaluateCommentPhrase extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
37
37
|
regex: phrase,
|
|
38
38
|
})));
|
|
39
39
|
}
|
|
40
|
+
getCompiledRegexes() {
|
|
41
|
+
this.compiledRegexes ?? (this.compiledRegexes = this.gatherRegexes().map(r => new RegExp(r.regex)));
|
|
42
|
+
return this.compiledRegexes;
|
|
43
|
+
}
|
|
40
44
|
eligibleComment(comment) {
|
|
41
|
-
const phrases = this.getVariable("phrases", []);
|
|
42
45
|
const maxCommentAgeInDays = this.getVariable("maxcommentageindays", 30);
|
|
43
|
-
if (
|
|
46
|
+
if (comment.createdAt <= (0, date_fns_1.subDays)(new Date(), maxCommentAgeInDays)) {
|
|
44
47
|
return false;
|
|
45
48
|
}
|
|
46
|
-
return
|
|
47
|
-
&& phrases.some(phrase => new RegExp(phrase).test(comment.body));
|
|
49
|
+
return this.getCompiledRegexes().some(regex => regex.test(comment.body));
|
|
48
50
|
}
|
|
49
51
|
preEvaluateComment(event) {
|
|
50
52
|
if (!event.comment) {
|
|
@@ -73,8 +75,7 @@ class EvaluateCommentPhrase extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
73
75
|
return false;
|
|
74
76
|
}
|
|
75
77
|
const matchingComment = matchingComments[0];
|
|
76
|
-
const
|
|
77
|
-
const matchedPhrase = phrases.find(phrase => new RegExp(phrase).test(matchingComment.body));
|
|
78
|
+
const matchedPhrase = this.getCompiledRegexes().find(regex => regex.test(matchingComment.body))?.source;
|
|
78
79
|
if (!matchedPhrase) {
|
|
79
80
|
// Impossible to reach this point.
|
|
80
81
|
return false;
|
|
@@ -10,6 +10,8 @@ export declare class EvaluatePostTitle extends UserEvaluatorBase {
|
|
|
10
10
|
gatherRegexes(): EvaluatorRegex[];
|
|
11
11
|
preEvaluateComment(_: CommentCreate): boolean;
|
|
12
12
|
private getTitles;
|
|
13
|
+
private titleRegexes;
|
|
14
|
+
private getTitleRegexes;
|
|
13
15
|
preEvaluatePost(post: Post): boolean;
|
|
14
16
|
preEvaluateUser(user: UserExtended): boolean;
|
|
15
17
|
evaluate(_: UserExtended): boolean;
|
|
@@ -46,15 +46,17 @@ class EvaluatePostTitle extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
46
46
|
return false;
|
|
47
47
|
}
|
|
48
48
|
getTitles() {
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
return this.getVariable("bantext", []);
|
|
50
|
+
}
|
|
51
|
+
getTitleRegexes() {
|
|
52
|
+
this.titleRegexes ?? (this.titleRegexes = this.getTitles().map(title => new RegExp(title, "u")));
|
|
53
|
+
return this.titleRegexes;
|
|
51
54
|
}
|
|
52
55
|
preEvaluatePost(post) {
|
|
53
56
|
if (post.crosspostParentId) {
|
|
54
57
|
return false;
|
|
55
58
|
}
|
|
56
|
-
|
|
57
|
-
return bannableTitles.some(title => new RegExp(title, "u").test(post.title));
|
|
59
|
+
return this.getTitleRegexes().some(title => title.test(post.title));
|
|
58
60
|
}
|
|
59
61
|
preEvaluateUser(user) {
|
|
60
62
|
const maxCommentKarma = this.getVariable("maxCommentKarma", 2000);
|
|
@@ -70,18 +72,32 @@ class EvaluatePostTitle extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
70
72
|
if (userPosts.length === 0) {
|
|
71
73
|
return false;
|
|
72
74
|
}
|
|
73
|
-
const bannableTitles = this.gatherRegexes().map(title => ({ pattern: title.regex, regex: new RegExp(title.regex, title.flags) }));
|
|
74
75
|
const nonMatchingTitles = new Set();
|
|
76
|
+
const regexes = this.getTitleRegexes();
|
|
75
77
|
for (const title of userPosts.map(post => post.title)) {
|
|
76
78
|
if (nonMatchingTitles.has(title)) {
|
|
77
79
|
continue;
|
|
78
80
|
}
|
|
79
|
-
|
|
81
|
+
let matchedBanRegex;
|
|
82
|
+
if (this.verboseLogging) {
|
|
83
|
+
matchedBanRegex = regexes.find((regex) => {
|
|
84
|
+
const start = Date.now();
|
|
85
|
+
const result = regex.test(title);
|
|
86
|
+
const end = Date.now();
|
|
87
|
+
if (end - start > this.regexWarnThreshold) {
|
|
88
|
+
console.warn(`Evaluation: Regex took ${end - start}ms: ${regex.source}`);
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
matchedBanRegex = regexes.find(regex => regex.test(title));
|
|
95
|
+
}
|
|
80
96
|
if (!matchedBanRegex) {
|
|
81
97
|
nonMatchingTitles.add(title);
|
|
82
98
|
continue;
|
|
83
99
|
}
|
|
84
|
-
this.addHitReason(`Post title "${title}" matched bannable regex: ${(0, markdown_escape_1.default)(matchedBanRegex.
|
|
100
|
+
this.addHitReason(`Post title "${title}" matched bannable regex: ${(0, markdown_escape_1.default)(matchedBanRegex.source)}`);
|
|
85
101
|
this.canAutoBan = true;
|
|
86
102
|
return true;
|
|
87
103
|
}
|
|
@@ -8,6 +8,8 @@ export declare class EvaluatePostTitleDefinedHandles extends UserEvaluatorBase {
|
|
|
8
8
|
banContentThreshold: number;
|
|
9
9
|
validateVariables(): ValidationIssue[];
|
|
10
10
|
gatherRegexes(): EvaluatorRegex[];
|
|
11
|
+
private compiledRegexes;
|
|
12
|
+
private getCompiledRegexes;
|
|
11
13
|
preEvaluateComment(_: CommentCreate): boolean;
|
|
12
14
|
preEvaluatePost(post: Post): boolean;
|
|
13
15
|
preEvaluateUser(user: UserExtended): boolean;
|
|
@@ -60,6 +60,10 @@ class EvaluatePostTitleDefinedHandles extends UserEvaluatorBase_js_1.UserEvaluat
|
|
|
60
60
|
flags: "u",
|
|
61
61
|
})));
|
|
62
62
|
}
|
|
63
|
+
getCompiledRegexes() {
|
|
64
|
+
this.compiledRegexes ?? (this.compiledRegexes = this.gatherRegexes().map(r => new RegExp(r.regex, r.flags)));
|
|
65
|
+
return this.compiledRegexes;
|
|
66
|
+
}
|
|
63
67
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
64
68
|
preEvaluateComment(_) {
|
|
65
69
|
return false;
|
|
@@ -68,8 +72,7 @@ class EvaluatePostTitleDefinedHandles extends UserEvaluatorBase_js_1.UserEvaluat
|
|
|
68
72
|
if (post.crosspostParentId) {
|
|
69
73
|
return false;
|
|
70
74
|
}
|
|
71
|
-
|
|
72
|
-
return problematicTitles.some(title => new RegExp(title, "u").test(post.title));
|
|
75
|
+
return this.getCompiledRegexes().some(regex => regex.test(post.title));
|
|
73
76
|
}
|
|
74
77
|
preEvaluateUser(user) {
|
|
75
78
|
const maxCommentKarma = this.getVariable("maxCommentKarma", 2000);
|
|
@@ -85,7 +88,7 @@ class EvaluatePostTitleDefinedHandles extends UserEvaluatorBase_js_1.UserEvaluat
|
|
|
85
88
|
if (userPosts.length === 0) {
|
|
86
89
|
return false;
|
|
87
90
|
}
|
|
88
|
-
const regexes = this.
|
|
91
|
+
const regexes = this.getCompiledRegexes();
|
|
89
92
|
if (regexes.length === 0) {
|
|
90
93
|
return false;
|
|
91
94
|
}
|
|
@@ -94,12 +97,12 @@ class EvaluatePostTitleDefinedHandles extends UserEvaluatorBase_js_1.UserEvaluat
|
|
|
94
97
|
if (nonMatchingTitles.has(title)) {
|
|
95
98
|
continue;
|
|
96
99
|
}
|
|
97
|
-
const matchedRegex = regexes.find(r => r.
|
|
100
|
+
const matchedRegex = regexes.find(r => r.test(title));
|
|
98
101
|
if (!matchedRegex) {
|
|
99
102
|
nonMatchingTitles.add(title);
|
|
100
103
|
continue;
|
|
101
104
|
}
|
|
102
|
-
this.addHitReason(`Post title "${title}" matched bannable regex: ${(0, markdown_escape_1.default)(matchedRegex.
|
|
105
|
+
this.addHitReason(`Post title "${title}" matched bannable regex: ${(0, markdown_escape_1.default)(matchedRegex.source)}`);
|
|
103
106
|
this.canAutoBan = true;
|
|
104
107
|
return true;
|
|
105
108
|
}
|
|
@@ -9,6 +9,8 @@ export declare class EvaluatePostTitleMulti extends UserEvaluatorBase {
|
|
|
9
9
|
validateVariables(): ValidationIssue[];
|
|
10
10
|
getVariableOverrides(): Record<string, unknown>;
|
|
11
11
|
gatherRegexes(): EvaluatorRegex[];
|
|
12
|
+
private compiledRegexes;
|
|
13
|
+
private getCompiledRegexes;
|
|
12
14
|
preEvaluateComment(_: CommentCreate): boolean;
|
|
13
15
|
preEvaluatePost(post: Post): boolean;
|
|
14
16
|
preEvaluateUser(user: UserExtended): boolean;
|
|
@@ -52,6 +52,10 @@ class EvaluatePostTitleMulti extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
52
52
|
flags: "u",
|
|
53
53
|
}));
|
|
54
54
|
}
|
|
55
|
+
getCompiledRegexes() {
|
|
56
|
+
this.compiledRegexes ?? (this.compiledRegexes = this.gatherRegexes().map(r => new RegExp(r.regex, r.flags)));
|
|
57
|
+
return this.compiledRegexes;
|
|
58
|
+
}
|
|
55
59
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
56
60
|
preEvaluateComment(_) {
|
|
57
61
|
return false;
|
|
@@ -60,8 +64,8 @@ class EvaluatePostTitleMulti extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
60
64
|
if (post.crosspostParentId) {
|
|
61
65
|
return false;
|
|
62
66
|
}
|
|
63
|
-
const regexes = this.
|
|
64
|
-
return regexes.some(
|
|
67
|
+
const regexes = this.getCompiledRegexes();
|
|
68
|
+
return regexes.some(regex => regex.test(post.title));
|
|
65
69
|
}
|
|
66
70
|
preEvaluateUser(user) {
|
|
67
71
|
return user.nsfw;
|
|
@@ -74,14 +78,14 @@ class EvaluatePostTitleMulti extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
74
78
|
return false;
|
|
75
79
|
}
|
|
76
80
|
const distinctTitles = (0, lodash_1.uniq)(userPosts.map(post => post.title));
|
|
77
|
-
const regexes = this.
|
|
78
|
-
const matchedRegexes = regexes.filter(
|
|
81
|
+
const regexes = this.getCompiledRegexes();
|
|
82
|
+
const matchedRegexes = regexes.filter(regex => distinctTitles.some(postTitle => regex.test(postTitle)));
|
|
79
83
|
const matchesNeeded = this.getVariable("matchesNeeded", 4);
|
|
80
84
|
if (matchedRegexes.length < matchesNeeded) {
|
|
81
85
|
return false;
|
|
82
86
|
}
|
|
83
87
|
const regexesInOutput = this.getVariable("regexesInOutput", 5);
|
|
84
|
-
this.addHitReason(`User has ${matchedRegexes.length} bad post titles: ${matchedRegexes.slice(0, regexesInOutput).map(r => `\`${r.
|
|
88
|
+
this.addHitReason(`User has ${matchedRegexes.length} bad post titles: ${matchedRegexes.slice(0, regexesInOutput).map(r => `\`${r.source}\``).join(", ")}`);
|
|
85
89
|
return true;
|
|
86
90
|
}
|
|
87
91
|
}
|
|
@@ -8,7 +8,6 @@ export declare class EvaluateSocialLinks extends UserEvaluatorBase {
|
|
|
8
8
|
banContentThreshold: number;
|
|
9
9
|
validateVariables(): ValidationIssue[];
|
|
10
10
|
getVariableOverrides(): Record<string, unknown>;
|
|
11
|
-
private getDomains;
|
|
12
11
|
preEvaluateComment(_: CommentCreate): boolean;
|
|
13
12
|
preEvaluatePost(post: Post): boolean;
|
|
14
13
|
preEvaluateUser(user: UserExtended): boolean;
|
|
@@ -36,25 +36,6 @@ class EvaluateSocialLinks extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
36
36
|
return {};
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
getDomains() {
|
|
40
|
-
const domains = new Set(this.getGenericVariable("redditdomains", []));
|
|
41
|
-
domains.add("redgifs.com");
|
|
42
|
-
domains.add("instagram.com");
|
|
43
|
-
domains.add("i.redd.it");
|
|
44
|
-
const badLinks = this.getVariable("badlinks", []);
|
|
45
|
-
for (const link of badLinks) {
|
|
46
|
-
try {
|
|
47
|
-
const domain = (0, evaluatorHelpers_js_1.domainFromUrl)(link);
|
|
48
|
-
if (domain) {
|
|
49
|
-
domains.add(domain);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
53
|
-
//
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return Array.from(domains);
|
|
57
|
-
}
|
|
58
39
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
59
40
|
preEvaluateComment(_) {
|
|
60
41
|
if (this.socialLinks) {
|
|
@@ -73,7 +73,7 @@ class EvaluateTextInNsfwImages extends EvaluateBotGroupAdvanced_1.EvaluateBotGro
|
|
|
73
73
|
if (!this.openAiKey) {
|
|
74
74
|
return;
|
|
75
75
|
}
|
|
76
|
-
const resultCacheKey = `imageText:${url}`;
|
|
76
|
+
const resultCacheKey = `bbe:imageText:${url}`;
|
|
77
77
|
const redis = this.context.subredditName === constants_1.MAIN_APP_NAME ? this.context.redis.global : this.context.redis;
|
|
78
78
|
const cachedResult = await redis.get(resultCacheKey);
|
|
79
79
|
if (cachedResult) {
|
|
@@ -8,7 +8,9 @@ export declare class EvaluateWorldTraveller extends UserEvaluatorBase {
|
|
|
8
8
|
canAutoBan: boolean;
|
|
9
9
|
banContentThreshold: number;
|
|
10
10
|
validateVariables(): ValidationIssue[];
|
|
11
|
+
private subGroups;
|
|
11
12
|
private getWTSubGroups;
|
|
13
|
+
private subList;
|
|
12
14
|
private getSubList;
|
|
13
15
|
private isInEligibleSubreddit;
|
|
14
16
|
preEvaluateComment(_: CommentCreate): boolean;
|
|
@@ -37,17 +37,18 @@ class EvaluateWorldTraveller extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
37
37
|
return results;
|
|
38
38
|
}
|
|
39
39
|
getWTSubGroups() {
|
|
40
|
-
|
|
41
|
-
return subGroups
|
|
40
|
+
this.subGroups ?? (this.subGroups = this.getVariable("subgroups", []).map(group => ({ group, subs: new Set(group.split(",").map(s => s.trim())) })));
|
|
41
|
+
return this.subGroups;
|
|
42
42
|
}
|
|
43
43
|
getSubList() {
|
|
44
|
-
|
|
44
|
+
this.subList ?? (this.subList = new Set(this.getWTSubGroups().map(group => Array.from(group.subs)).flat()));
|
|
45
|
+
return this.subList;
|
|
45
46
|
}
|
|
46
47
|
isInEligibleSubreddit() {
|
|
47
48
|
if (!this.context.subredditName) {
|
|
48
49
|
return false;
|
|
49
50
|
}
|
|
50
|
-
return this.context.subredditName.startsWith(constants_js_1.CONTROL_SUBREDDIT) || this.getSubList().
|
|
51
|
+
return this.context.subredditName.startsWith(constants_js_1.CONTROL_SUBREDDIT) || this.getSubList().has(this.context.subredditName);
|
|
51
52
|
}
|
|
52
53
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
53
54
|
preEvaluateComment(_) {
|
|
@@ -57,7 +58,7 @@ class EvaluateWorldTraveller extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
57
58
|
if (!post.nsfw) {
|
|
58
59
|
return false;
|
|
59
60
|
}
|
|
60
|
-
return this.getSubList().
|
|
61
|
+
return this.getSubList().has(post.subredditName);
|
|
61
62
|
}
|
|
62
63
|
preEvaluateUser(user) {
|
|
63
64
|
return user.nsfw && this.isInEligibleSubreddit();
|
|
@@ -67,10 +68,10 @@ class EvaluateWorldTraveller extends UserEvaluatorBase_js_1.UserEvaluatorBase {
|
|
|
67
68
|
const nsfwOnly = this.getVariable("nsfwonly", false);
|
|
68
69
|
const relevantHistory = this.getPosts({ since: (0, date_fns_1.subMonths)(new Date(), 1) })
|
|
69
70
|
.filter(post => nsfwOnly ? post.nsfw : true)
|
|
70
|
-
.filter(post => this.getSubList().
|
|
71
|
+
.filter(post => this.getSubList().has(post.subredditName));
|
|
71
72
|
const distinctSubreddits = (0, lodash_1.uniq)(relevantHistory.map(item => item.subredditName));
|
|
72
73
|
const distinctSubGroups = (0, lodash_1.uniq)(this.getWTSubGroups()
|
|
73
|
-
.filter(group => distinctSubreddits.some(sub => group.subs.
|
|
74
|
+
.filter(group => distinctSubreddits.some(sub => group.subs.has(sub)))
|
|
74
75
|
.map(group => group.group));
|
|
75
76
|
const requiredSubCount = this.getVariable("distinctgroups", 5);
|
|
76
77
|
return distinctSubGroups.length >= requiredSubCount;
|
|
@@ -38,6 +38,8 @@ export declare abstract class UserEvaluatorBase {
|
|
|
38
38
|
private userPosts;
|
|
39
39
|
private userComments;
|
|
40
40
|
protected ignoredSubs: Set<string>;
|
|
41
|
+
protected verboseLogging: boolean;
|
|
42
|
+
protected regexWarnThreshold: number;
|
|
41
43
|
constructor(context: TriggerContext, history: (Post | Comment)[], socialLinks: UserSocialLink[] | undefined, variables: Record<string, unknown>);
|
|
42
44
|
setHistory(history: (Post | Comment)[]): void;
|
|
43
45
|
setSocialLinks(socialLinks: UserSocialLink[]): void;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.UserEvaluatorBase = void 0;
|
|
4
4
|
const tid_js_1 = require("@devvit/public-api/types/tid.js");
|
|
5
5
|
const evaluatorHelpers_js_1 = require("./evaluatorHelpers.js");
|
|
6
|
+
const constants_js_1 = require("../constants.js");
|
|
6
7
|
class UserEvaluatorBase {
|
|
7
8
|
constructor(context, history, socialLinks, variables) {
|
|
8
9
|
this.variables = {};
|
|
@@ -13,6 +14,8 @@ class UserEvaluatorBase {
|
|
|
13
14
|
this.context = context;
|
|
14
15
|
this.socialLinks = socialLinks;
|
|
15
16
|
this.variables = variables;
|
|
17
|
+
this.verboseLogging = context.appSlug !== constants_js_1.MAIN_APP_NAME;
|
|
18
|
+
this.regexWarnThreshold = this.getVariable("regexWarnThreshold", 100);
|
|
16
19
|
this.ignoredSubs = new Set(this.getGenericVariable("ignoredsubs", []));
|
|
17
20
|
this.history = history;
|
|
18
21
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fsvreddit/bot-bouncer-evaluation",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.42",
|
|
4
4
|
"description": "Evaluation code for Bot Bouncer, a Dev Platform app designed to hunt bots on Reddit",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -32,19 +32,19 @@
|
|
|
32
32
|
"zod": "^4.4.3"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@fsvreddit/eslint-config": "^0.1.
|
|
35
|
+
"@fsvreddit/eslint-config": "^0.1.1",
|
|
36
36
|
"@types/lodash": "^4.17.17",
|
|
37
37
|
"@types/markdown-escape": "^1.1.3",
|
|
38
38
|
"eslint": "^10.0.2",
|
|
39
39
|
"typescript": "^5.8.3",
|
|
40
|
-
"vitest": "^
|
|
40
|
+
"vitest": "^5.0.0"
|
|
41
41
|
},
|
|
42
42
|
"keywords": [
|
|
43
43
|
"reddit",
|
|
44
44
|
"devvit"
|
|
45
45
|
],
|
|
46
46
|
"peerDependencies": {
|
|
47
|
-
"@devvit/protos": "^0.14.
|
|
48
|
-
"@devvit/public-api": "^0.14.
|
|
47
|
+
"@devvit/protos": "^0.14.3",
|
|
48
|
+
"@devvit/public-api": "^0.14.3"
|
|
49
49
|
}
|
|
50
50
|
}
|