@fsvreddit/bot-bouncer-evaluation 0.7.41 → 0.7.43

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.
Files changed (27) hide show
  1. package/dist/allEvaluators.d.ts +2 -2
  2. package/dist/userEvaluation/EvaluateBadDisplayname.js +1 -5
  3. package/dist/userEvaluation/EvaluateBadDisplaynameDefinedHandles.d.ts +2 -0
  4. package/dist/userEvaluation/EvaluateBadDisplaynameDefinedHandles.js +6 -3
  5. package/dist/userEvaluation/EvaluateBadUsername.d.ts +2 -0
  6. package/dist/userEvaluation/EvaluateBadUsername.js +6 -3
  7. package/dist/userEvaluation/EvaluateBioText.d.ts +3 -1
  8. package/dist/userEvaluation/EvaluateBioText.js +16 -19
  9. package/dist/userEvaluation/EvaluateBioTextDefinedHandles.d.ts +2 -0
  10. package/dist/userEvaluation/EvaluateBioTextDefinedHandles.js +11 -13
  11. package/dist/userEvaluation/EvaluateBotGroupAdvanced.d.ts +2 -1
  12. package/dist/userEvaluation/EvaluateBotGroupAdvanced.js +11 -6
  13. package/dist/userEvaluation/EvaluateCommentPhrase.d.ts +2 -0
  14. package/dist/userEvaluation/EvaluateCommentPhrase.js +9 -8
  15. package/dist/userEvaluation/EvaluatePostTitle.d.ts +2 -0
  16. package/dist/userEvaluation/EvaluatePostTitle.js +9 -7
  17. package/dist/userEvaluation/EvaluatePostTitleDefinedHandles.d.ts +2 -0
  18. package/dist/userEvaluation/EvaluatePostTitleDefinedHandles.js +8 -5
  19. package/dist/userEvaluation/EvaluatePostTitleMulti.d.ts +2 -0
  20. package/dist/userEvaluation/EvaluatePostTitleMulti.js +9 -5
  21. package/dist/userEvaluation/EvaluateSocialLinks.d.ts +0 -1
  22. package/dist/userEvaluation/EvaluateSocialLinks.js +0 -19
  23. package/dist/userEvaluation/EvaluateWorldTraveller.d.ts +2 -0
  24. package/dist/userEvaluation/EvaluateWorldTraveller.js +8 -7
  25. package/dist/userEvaluation/UserEvaluatorBase.d.ts +2 -0
  26. package/dist/userEvaluation/UserEvaluatorBase.js +3 -0
  27. package/package.json +4 -4
@@ -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 EvaluateBotGroupAdvanced | typeof EvaluateWarmupBot | typeof EvaluateLinkReuse)[];
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
- if (this.badDisplayNameRegexes === undefined) {
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 regexes = this.gatherRegexes().map(r => r.regex);
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 regexes = this.getVariable("regexes", []);
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
- if (this.bioText === undefined) {
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,35 @@ 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
- const bannableBioText = this.getBioText();
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 bannableBioText.some(bioText => user.userDescription && new RegExp(bioText, "u").test(user.userDescription));
79
+ return this.getCompiledRegexes().some(regex => user.userDescription && regex.test(user.userDescription));
79
80
  }
80
81
  evaluate(user) {
81
- const bannableBioText = this.getBioText();
82
- if (bannableBioText.length === 0) {
83
- return false;
84
- }
85
- const bannableBioTextFound = bannableBioText.find(bio => user.userDescription && new RegExp(bio, "u").test(user.userDescription));
86
- if (bannableBioTextFound) {
82
+ const matchedRegex = this.getCompiledRegexes().find(regex => user.userDescription && regex.test(user.userDescription));
83
+ if (matchedRegex) {
87
84
  this.canAutoBan = true;
88
- this.addHitReason(`Bio text matched regex: ${(0, markdown_escape_1.default)(bannableBioTextFound)}`);
85
+ this.addHitReason(`Bio text matched regex: ${(0, markdown_escape_1.default)(matchedRegex.source)}`);
89
86
  }
90
87
  else {
91
88
  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
- const problematicBioText = this.gatherRegexes().map(r => r.regex);
27
- return problematicBioText.some(bioText => event.author?.description && new RegExp(bioText, "u").test(event.author.description));
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 regexes.some(bioText => user.userDescription && new RegExp(bioText, "u").test(user.userDescription));
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 regexes = this.gatherRegexes().map(r => r.regex);
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(bio => `\`${bio}\``).join(", ")}`);
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,19 @@ 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
- return regexes.some(regex => new RegExp(regex, "u").test(input));
482
+ return regexes.some(regex => this.getCompiledRegex(regex).test(input));
475
483
  }
476
484
  getBotGroups() {
477
485
  const groups = this.getAllVariables("group");
@@ -746,9 +754,6 @@ class EvaluateBotGroupAdvanced extends UserEvaluatorBase_js_1.UserEvaluatorBase
746
754
  continue;
747
755
  }
748
756
  if (!group.criteria) {
749
- if (this.verboseLogging) {
750
- console.log(`Pre-evaluation: Comment ${comment.comment.id} for ${comment.author.name} matches bot group with no criteria ${group.name}`);
751
- }
752
757
  return true;
753
758
  }
754
759
  ;
@@ -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 biotext: ${regexVal}` });
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: `Bio Text regex is too greedy: ${regexVal}` });
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 (phrases.length === 0) {
46
+ if (comment.createdAt <= (0, date_fns_1.subDays)(new Date(), maxCommentAgeInDays)) {
44
47
  return false;
45
48
  }
46
- return comment.createdAt > (0, date_fns_1.subDays)(new Date(), maxCommentAgeInDays)
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 phrases = this.getVariable("phrases", []);
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
- const prefixesToIgnore = this.getVariable("ignoredRegexPrefixes", []);
50
- return this.getVariable("bantext", []).filter(title => !prefixesToIgnore.some(prefix => title.startsWith(prefix)));
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
- const bannableTitles = this.getTitles();
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,18 @@ 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
- const matchedBanRegex = bannableTitles.find(bannable => bannable.regex.test(title));
81
+ const matchedBanRegex = regexes.find(regex => regex.test(title));
80
82
  if (!matchedBanRegex) {
81
83
  nonMatchingTitles.add(title);
82
84
  continue;
83
85
  }
84
- this.addHitReason(`Post title "${title}" matched bannable regex: ${(0, markdown_escape_1.default)(matchedBanRegex.pattern)}`);
86
+ this.addHitReason(`Post title "${title}" matched bannable regex: ${(0, markdown_escape_1.default)(matchedBanRegex.source)}`);
85
87
  this.canAutoBan = true;
86
88
  return true;
87
89
  }
@@ -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
- const problematicTitles = this.gatherRegexes().map(r => r.regex);
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.gatherRegexes().map(r => ({ pattern: r.regex, regex: new RegExp(r.regex, r.flags) }));
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.regex.test(title));
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.pattern)}`);
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.gatherRegexes();
64
- return regexes.some(regexObj => new RegExp(regexObj.regex, regexObj.flags).test(post.title));
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.gatherRegexes();
78
- const matchedRegexes = regexes.filter(regexObj => distinctTitles.some(postTitle => new RegExp(regexObj.regex, regexObj.flags).test(postTitle)));
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.regex}\``).join(", ")}`);
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) {
@@ -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
- const subGroups = this.getVariable("subgroups", []);
41
- return subGroups.map(group => ({ group, subs: group.split(",").map(s => s.trim()) }));
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
- return this.getWTSubGroups().map(group => group.subs).flat();
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().includes(this.context.subredditName);
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().includes(post.subredditName);
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().includes(post.subredditName));
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.includes(sub)))
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.41",
3
+ "version": "0.7.43",
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": {
@@ -37,14 +37,14 @@
37
37
  "@types/markdown-escape": "^1.1.3",
38
38
  "eslint": "^10.0.2",
39
39
  "typescript": "^5.8.3",
40
- "vitest": "^4.0.15"
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.1",
48
- "@devvit/public-api": "^0.14.1"
47
+ "@devvit/protos": "^0.14.3",
48
+ "@devvit/public-api": "^0.14.3"
49
49
  }
50
50
  }