@joliegg/moderation 0.6.0 → 0.8.0
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/actions.d.ts +28 -0
- package/dist/actions.js +48 -0
- package/dist/client.d.ts +19 -0
- package/dist/client.js +97 -0
- package/dist/index.d.ts +3 -41
- package/dist/index.js +20 -213
- package/dist/providers/aws.d.ts +11 -0
- package/dist/providers/aws.js +58 -0
- package/dist/providers/google.d.ts +21 -0
- package/dist/providers/google.js +61 -0
- package/dist/providers/webrisk.d.ts +9 -0
- package/dist/providers/webrisk.js +33 -0
- package/dist/raid/age.d.ts +6 -0
- package/dist/raid/age.js +19 -0
- package/dist/raid/detector.d.ts +56 -0
- package/dist/raid/detector.js +88 -0
- package/dist/raid/index.d.ts +2 -0
- package/dist/raid/index.js +18 -0
- package/dist/spam/cache.d.ts +99 -0
- package/dist/spam/cache.js +210 -0
- package/dist/spam/index.d.ts +1 -0
- package/dist/spam/index.js +17 -0
- package/dist/text/index.d.ts +2 -0
- package/dist/text/index.js +18 -0
- package/dist/text/mentions.d.ts +31 -0
- package/dist/text/mentions.js +55 -0
- package/dist/text/normalize.d.ts +15 -0
- package/dist/text/normalize.js +45 -0
- package/dist/types/config.d.ts +13 -0
- package/dist/types/config.js +2 -0
- package/dist/types/index.d.ts +3 -10
- package/dist/types/index.js +15 -0
- package/package.json +54 -13
- package/src/actions.ts +50 -0
- package/src/client.ts +121 -0
- package/src/index.ts +3 -277
- package/src/providers/aws.ts +58 -0
- package/src/providers/google.ts +63 -0
- package/src/providers/webrisk.ts +30 -0
- package/src/raid/age.ts +19 -0
- package/src/raid/detector.ts +122 -0
- package/src/raid/index.ts +2 -0
- package/src/spam/cache.ts +342 -0
- package/src/spam/index.ts +1 -0
- package/src/text/index.ts +2 -0
- package/src/text/mentions.ts +91 -0
- package/src/text/normalize.ts +43 -0
- package/src/types/config.ts +14 -0
- package/src/types/index.ts +5 -11
- /package/dist/{url-blacklist.json → data/url-blacklist.json} +0 -0
- /package/dist/{url-shorteners.json → data/url-shorteners.json} +0 -0
- /package/src/{url-blacklist.json → data/url-blacklist.json} +0 -0
- /package/src/{url-shorteners.json → data/url-shorteners.json} +0 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export interface MentionConfig {
|
|
2
|
+
/** Maximum number of distinct user mentions per message. */
|
|
3
|
+
maxUserMentions: number;
|
|
4
|
+
/** Maximum number of distinct role mentions per message. */
|
|
5
|
+
maxRoleMentions: number;
|
|
6
|
+
/** Maximum number of total mentions (user + role) per message. */
|
|
7
|
+
maxTotalMentions: number;
|
|
8
|
+
/** Whether to treat `@everyone` as spam for the sender. */
|
|
9
|
+
blockEveryone: boolean;
|
|
10
|
+
/** Whether to treat `@here` as spam for the sender. */
|
|
11
|
+
blockHere: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface MentionCounts {
|
|
15
|
+
userMentions: number;
|
|
16
|
+
roleMentions: number;
|
|
17
|
+
hasEveryone: boolean;
|
|
18
|
+
hasHere: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type MentionSpamReason =
|
|
22
|
+
| 'mention_everyone'
|
|
23
|
+
| 'mention_here'
|
|
24
|
+
| 'mention_users'
|
|
25
|
+
| 'mention_roles'
|
|
26
|
+
| 'mention_total';
|
|
27
|
+
|
|
28
|
+
export interface MentionSpamResult {
|
|
29
|
+
isSpam: boolean;
|
|
30
|
+
reason: MentionSpamReason | null;
|
|
31
|
+
details: string | null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const DEFAULT_MENTION_CONFIG: MentionConfig = {
|
|
35
|
+
maxUserMentions: 5,
|
|
36
|
+
maxRoleMentions: 3,
|
|
37
|
+
maxTotalMentions: 8,
|
|
38
|
+
blockEveryone: true,
|
|
39
|
+
blockHere: true,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Mention-spam check.
|
|
44
|
+
*
|
|
45
|
+
* `@everyone` detection takes priority over other reasons.
|
|
46
|
+
*/
|
|
47
|
+
export function checkMentionSpam(counts: MentionCounts, config: MentionConfig): MentionSpamResult {
|
|
48
|
+
if (config.blockEveryone && counts.hasEveryone) {
|
|
49
|
+
return {
|
|
50
|
+
isSpam: true,
|
|
51
|
+
reason: 'mention_everyone',
|
|
52
|
+
details: '@everyone mentioned without permission',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (config.blockHere && counts.hasHere) {
|
|
57
|
+
return {
|
|
58
|
+
isSpam: true,
|
|
59
|
+
reason: 'mention_here',
|
|
60
|
+
details: '@here mentioned without permission',
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (counts.userMentions > config.maxUserMentions) {
|
|
65
|
+
return {
|
|
66
|
+
isSpam: true,
|
|
67
|
+
reason: 'mention_users',
|
|
68
|
+
details: `${counts.userMentions} user mentions (limit: ${config.maxUserMentions})`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (counts.roleMentions > config.maxRoleMentions) {
|
|
73
|
+
return {
|
|
74
|
+
isSpam: true,
|
|
75
|
+
reason: 'mention_roles',
|
|
76
|
+
details: `${counts.roleMentions} role mentions (limit: ${config.maxRoleMentions})`,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const total = counts.userMentions + counts.roleMentions;
|
|
81
|
+
|
|
82
|
+
if (total > config.maxTotalMentions) {
|
|
83
|
+
return {
|
|
84
|
+
isSpam: true,
|
|
85
|
+
reason: 'mention_total',
|
|
86
|
+
details: `${total} total mentions (limit: ${config.maxTotalMentions})`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return { isSpam: false, reason: null, details: null };
|
|
91
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invisible / zero-width Unicode code points that users sometimes insert
|
|
3
|
+
* between letters to bypass substring-based filters. NFKC normalization
|
|
4
|
+
* does NOT collapse these on its own, so we strip them explicitly before
|
|
5
|
+
* normalizing.
|
|
6
|
+
*
|
|
7
|
+
* - U+200B Zero-Width Space
|
|
8
|
+
* - U+200C Zero-Width Non-Joiner
|
|
9
|
+
* - U+200D Zero-Width Joiner
|
|
10
|
+
* - U+200E Left-to-Right Mark
|
|
11
|
+
* - U+200F Right-to-Left Mark
|
|
12
|
+
* - U+2060 Word Joiner
|
|
13
|
+
* - U+FEFF Zero-Width No-Break Space (BOM)
|
|
14
|
+
*/
|
|
15
|
+
// Matching individual zero-width code points by design (we are stripping
|
|
16
|
+
// them, not joining anything). ESLint's no-misleading-character-class
|
|
17
|
+
// flags this since \u200d is the Zero-Width Joiner; the warning does not
|
|
18
|
+
// apply here because every code point in the class is a literal target.
|
|
19
|
+
// eslint-disable-next-line no-misleading-character-class
|
|
20
|
+
const ZERO_WIDTH = /[\u200b\u200c\u200d\u200e\u200f\u2060\ufeff]/gu;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Canonicalizes user-submitted text for content matching:
|
|
24
|
+
*
|
|
25
|
+
* 1. trim surrounding whitespace
|
|
26
|
+
* 2. lowercase
|
|
27
|
+
* 3. strip zero-width / invisible characters
|
|
28
|
+
* 4. NFKC normalize (collapses bold, italic, fullwidth, circled,
|
|
29
|
+
* small-caps, and other compatibility variants to ASCII)
|
|
30
|
+
* 5. collapse internal whitespace runs to single spaces
|
|
31
|
+
*
|
|
32
|
+
* Useful for spam hashing, ban-list matching, and any other comparison
|
|
33
|
+
* where users should not be able to defeat a match by visually similar
|
|
34
|
+
* but technically distinct input.
|
|
35
|
+
*/
|
|
36
|
+
export function normalizeText(input: string): string {
|
|
37
|
+
return input
|
|
38
|
+
.trim()
|
|
39
|
+
.toLowerCase()
|
|
40
|
+
.replace(ZERO_WIDTH, '')
|
|
41
|
+
.normalize('NFKC')
|
|
42
|
+
.replace(/\s+/g, ' ');
|
|
43
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RekognitionClientConfig } from '@aws-sdk/client-rekognition';
|
|
2
|
+
|
|
3
|
+
export interface ModerationConfiguration {
|
|
4
|
+
aws?: RekognitionClientConfig;
|
|
5
|
+
google?: {
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
keyFile?: string;
|
|
8
|
+
};
|
|
9
|
+
openai?: {
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
};
|
|
12
|
+
banList?: string[];
|
|
13
|
+
urlBlackList?: string[];
|
|
14
|
+
}
|
package/src/types/index.ts
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
export * from './config';
|
|
2
2
|
|
|
3
|
-
export
|
|
4
|
-
aws?: RekognitionClientConfig;
|
|
5
|
-
google?: {
|
|
6
|
-
apiKey?: string;
|
|
7
|
-
keyFile?: string;
|
|
8
|
-
};
|
|
9
|
-
banList?: string[];
|
|
10
|
-
urlBlackList?: string[];
|
|
11
|
-
}
|
|
3
|
+
export type Severity = 'low' | 'medium' | 'high' | 'critical';
|
|
12
4
|
|
|
13
5
|
export interface ModerationCategory {
|
|
14
6
|
category: string;
|
|
15
7
|
confidence: number;
|
|
8
|
+
severity?: Severity;
|
|
16
9
|
}
|
|
10
|
+
|
|
17
11
|
export interface ModerationResult {
|
|
18
12
|
source: string;
|
|
19
13
|
moderation: ModerationCategory[];
|
|
@@ -29,4 +23,4 @@ export interface ThreatsResponse {
|
|
|
29
23
|
threatTypes: string[];
|
|
30
24
|
expireTime: string;
|
|
31
25
|
};
|
|
32
|
-
}
|
|
26
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|