@amatiscorp/disguard 1.2.0 → 1.4.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/README.md +356 -27
- package/dist/AntiSpam.d.ts +12 -1
- package/dist/AntiSpam.d.ts.map +1 -1
- package/dist/AntiSpam.js +145 -9
- package/dist/AntiSpam.js.map +1 -1
- package/dist/defaults.d.ts.map +1 -1
- package/dist/defaults.js +89 -1
- package/dist/defaults.js.map +1 -1
- package/dist/detectors/accounts.d.ts.map +1 -1
- package/dist/detectors/accounts.js +27 -0
- package/dist/detectors/accounts.js.map +1 -1
- package/dist/detectors/attach.d.ts +3 -0
- package/dist/detectors/attach.d.ts.map +1 -0
- package/dist/detectors/attach.js +31 -0
- package/dist/detectors/attach.js.map +1 -0
- package/dist/detectors/duplicates.js +1 -1
- package/dist/detectors/duplicates.js.map +1 -1
- package/dist/detectors/echo.d.ts +3 -0
- package/dist/detectors/echo.d.ts.map +1 -0
- package/dist/detectors/echo.js +37 -0
- package/dist/detectors/echo.js.map +1 -0
- package/dist/detectors/files.d.ts.map +1 -1
- package/dist/detectors/files.js +10 -0
- package/dist/detectors/files.js.map +1 -1
- package/dist/detectors/ghost.d.ts +4 -0
- package/dist/detectors/ghost.d.ts.map +1 -0
- package/dist/detectors/ghost.js +36 -0
- package/dist/detectors/ghost.js.map +1 -0
- package/dist/detectors/hop.d.ts +3 -0
- package/dist/detectors/hop.d.ts.map +1 -0
- package/dist/detectors/hop.js +30 -0
- package/dist/detectors/hop.js.map +1 -0
- package/dist/detectors/invisible.d.ts +3 -0
- package/dist/detectors/invisible.d.ts.map +1 -0
- package/dist/detectors/invisible.js +25 -0
- package/dist/detectors/invisible.js.map +1 -0
- package/dist/detectors/links.d.ts.map +1 -1
- package/dist/detectors/links.js +11 -0
- package/dist/detectors/links.js.map +1 -1
- package/dist/detectors/mentions.d.ts.map +1 -1
- package/dist/detectors/mentions.js +19 -1
- package/dist/detectors/mentions.js.map +1 -1
- package/dist/detectors/punctuation.d.ts +3 -0
- package/dist/detectors/punctuation.d.ts.map +1 -0
- package/dist/detectors/punctuation.js +26 -0
- package/dist/detectors/punctuation.js.map +1 -0
- package/dist/detectors/secrets.d.ts +3 -0
- package/dist/detectors/secrets.d.ts.map +1 -0
- package/dist/detectors/secrets.js +59 -0
- package/dist/detectors/secrets.js.map +1 -0
- package/dist/detectors/spoilers.d.ts +3 -0
- package/dist/detectors/spoilers.d.ts.map +1 -0
- package/dist/detectors/spoilers.js +25 -0
- package/dist/detectors/spoilers.js.map +1 -0
- package/dist/detectors/words.d.ts +3 -0
- package/dist/detectors/words.d.ts.map +1 -0
- package/dist/detectors/words.js +56 -0
- package/dist/detectors/words.js.map +1 -0
- package/dist/enforcement.d.ts.map +1 -1
- package/dist/enforcement.js +71 -6
- package/dist/enforcement.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +112 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/normalize.d.ts +1 -0
- package/dist/utils/normalize.d.ts.map +1 -1
- package/dist/utils/normalize.js +4 -0
- package/dist/utils/normalize.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
# Disguard
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<div align="center">
|
|
4
4
|
|
|
5
|
-
Configurable antispam for
|
|
5
|
+
**Configurable antispam for discord.js v14**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Flood · phishing · leaked secrets · channel hop · ghost pings · TypeScript
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
[](https://www.npmjs.com/package/@amatiscorp/disguard)
|
|
10
|
+
[](https://opensource.org/licenses/MIT)
|
|
11
|
+
[](https://www.typescriptlang.org/)
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
[Install](#install) · [Quick start](#quick-start) · [API](#api) · [Español](#español)
|
|
14
|
+
|
|
15
|
+
</div>
|
|
12
16
|
|
|
13
17
|
---
|
|
14
18
|
|
|
19
|
+
npm: [`@amatiscorp/disguard`](https://www.npmjs.com/package/@amatiscorp/disguard)
|
|
20
|
+
|
|
21
|
+
Configurable antispam for [discord.js](https://discord.js.org) v14 bots.
|
|
22
|
+
|
|
23
|
+
It is **not** a bot. You plug it into your existing `Client` and decide every threshold, allowlist, and punishment.
|
|
24
|
+
|
|
25
|
+
Detects flood, leaked tokens/webhooks, channel hopping, blocked words, phishing, duplicate images, mention spam, ghost pings, and more.
|
|
26
|
+
|
|
15
27
|
**Languages**
|
|
16
28
|
|
|
17
29
|
- [English](#english)
|
|
@@ -21,6 +33,97 @@ Detects flood, repeated text, phishing / unwanted links, duplicate images, menti
|
|
|
21
33
|
|
|
22
34
|
# English
|
|
23
35
|
|
|
36
|
+
## What's new in 1.4.0
|
|
37
|
+
|
|
38
|
+
Secret scanning, cross-channel copy-paste, invisible unicode, attachment floods, and cleaner logs. Kick/ban stay **off**.
|
|
39
|
+
|
|
40
|
+
| Option | Default | What it does |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| `secrets` | **on** | Flags Discord **bot tokens** and **webhook URLs** pasted in chat (also embeds). The incident does **not** store the secret. |
|
|
43
|
+
| `echo` | **on**, 3 channels / 12s | Same text pasted across several channels (raid copypasta). Distinct from `hop` (any messages). |
|
|
44
|
+
| `invisible` | **on**, 8 | Zero-width / bidi characters used to dodge filters. |
|
|
45
|
+
| `attach` | **on**, 8 files / 10s | Too many attachments across a short window, not just dangerous extensions. |
|
|
46
|
+
| `duplicates.minLength` | `8` | Short stuff like `ok` / `lol` is no longer duplicate-spam. |
|
|
47
|
+
| `mentions.maxInWindow` | `0` (off) | Cap mentions across several messages, not only one. |
|
|
48
|
+
| `accounts.onlyWithLinks` | `false` (`strict`: true) | New accounts are flagged only if the message has a URL. |
|
|
49
|
+
| `punishment.purgeCount` | `0` | After a hit, bulk-delete N of that user's recent messages in the channel. |
|
|
50
|
+
| `punishment.logWebhookUrl` | `null` | Log embeds to a Discord webhook (no extra log channel needed). |
|
|
51
|
+
| `ignorePinned` | `false` | Skip pinned messages. |
|
|
52
|
+
| `ignoreOlderThanMs` | `0` | Skip old messages (useful on reconnect replay). |
|
|
53
|
+
| `setEnabled(false)` | — | Turn the whole filter off without `stop()`. |
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
const antispam = new AntiSpam(client, {
|
|
57
|
+
preset: "balanced",
|
|
58
|
+
secrets: { enabled: true, botTokens: true, webhooks: true, extraPatterns: ["ghp_[A-Za-z0-9]{20,}"] },
|
|
59
|
+
echo: { maxChannels: 3, windowMs: 12_000, minLength: 12 },
|
|
60
|
+
invisible: { maxInvisible: 8 },
|
|
61
|
+
attach: { maxAttachments: 8, windowMs: 10_000 },
|
|
62
|
+
duplicates: { minLength: 8 },
|
|
63
|
+
accounts: { enabled: true, minAgeDays: 2, onlyWithLinks: true },
|
|
64
|
+
ignorePinned: true,
|
|
65
|
+
punishment: {
|
|
66
|
+
purgeCount: 5,
|
|
67
|
+
logWebhookUrl: process.env.DISGUARD_LOG_WEBHOOK || null,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
antispam.setEnabled(false); // raid party / event
|
|
72
|
+
antispam.setEnabled(true);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`secrets` is meant to **delete leaks**, not to harvest credentials. Reasons only say “token/webhook”, never the value.
|
|
76
|
+
|
|
77
|
+
## What's new in 1.3.0
|
|
78
|
+
|
|
79
|
+
| Option | Default | What it does |
|
|
80
|
+
| --- | --- | --- |
|
|
81
|
+
| `words` | **off**, empty list | Block a word list and/or regex. `ignoreCase` and `matchWholeWord` are both `true` by default. |
|
|
82
|
+
| `hop` | **on**, 5 channels / 8s | Same user posting across too many unique channels in a window (raid / hop). |
|
|
83
|
+
| `punctuation` | **on**, 10 | `aaaaaa` / `!!!!!!` runs longer than `maxRepeated`. |
|
|
84
|
+
| `spoilers` | **on**, 8 pairs | Too many `\|\|spoiler\|\|` pairs in one message. |
|
|
85
|
+
| `ghostPing` | **off** (`strict`: on) | Punish deleting a message that mentioned people (`messageDelete`). |
|
|
86
|
+
| `checkDeletes` | `true` | Listen for `messageDelete`. Set `false` if you do not want ghost-ping checks. |
|
|
87
|
+
| `ignored.prefixes` | `[]` | Skip messages that start with `!`, `/`, `.`, etc. |
|
|
88
|
+
| `ignoreThreads` | `false` | Skip thread messages. |
|
|
89
|
+
| `ignoreSystem` | `true` | Skip Discord system messages. |
|
|
90
|
+
| `roleOverrides` / `setRoleConfig` | `{}` | Per-role config overlay (before channel overrides). |
|
|
91
|
+
| `links.blockOauth` | `true` | Flag non-allowlisted URLs whose path looks like `/oauth`, `/authorize`, `/login`. Official `discord.com` stays allowed. |
|
|
92
|
+
| `files.maxBytes` | `0` | Max attachment size in bytes. `0` = unlimited. |
|
|
93
|
+
| `accounts.minGuildAgeDays` | `0` | Flag members who joined the guild too recently. `0` = off. |
|
|
94
|
+
| `punishment.addRoleIds` / `removeRoleIds` | `[]` | Add/remove roles on punish (mute role). Needs **Manage Roles**. |
|
|
95
|
+
| `punishment.minStrikesForRoles` | `1` | Minimum strikes before those role actions run. |
|
|
96
|
+
| `onCooldown` | — | Callback when extra spam is deleted quietly during the punishment cooldown. |
|
|
97
|
+
| `pause()` / `resume()` | — | Freeze enforcement without removing listeners. |
|
|
98
|
+
|
|
99
|
+
```js
|
|
100
|
+
const antispam = new AntiSpam(client, {
|
|
101
|
+
preset: "balanced",
|
|
102
|
+
locale: "es",
|
|
103
|
+
ignored: { prefixes: ["!", "/", "."], roles: ["STAFF_ROLE_ID"] },
|
|
104
|
+
words: { enabled: true, list: ["raid-now"], regex: ["n[i1]tro\\s+free"] },
|
|
105
|
+
hop: { maxChannels: 4, windowMs: 6_000 },
|
|
106
|
+
ghostPing: { enabled: true, minMentions: 1, maxAgeMs: 15_000 },
|
|
107
|
+
links: { blockOauth: true },
|
|
108
|
+
files: { maxBytes: 8 * 1024 * 1024 },
|
|
109
|
+
roleOverrides: {
|
|
110
|
+
"VIP_ROLE_ID": { flood: { maxMessages: 10 } },
|
|
111
|
+
},
|
|
112
|
+
punishment: {
|
|
113
|
+
addRoleIds: ["MUTE_ROLE_ID"],
|
|
114
|
+
minStrikesForRoles: 2,
|
|
115
|
+
},
|
|
116
|
+
onCooldown(message) {
|
|
117
|
+
console.log("quiet delete", message.id);
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
antispam.setRoleConfig("VIP_ROLE_ID", { emojis: { maxEmojis: 40 } });
|
|
122
|
+
antispam.pause(); // raid over? antispam.resume();
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Ghost pings need the message in cache (or `Partials.Message`) so `messageDelete` still has mentions. Kick/ban stay **off**. Role add/remove is opt-in via empty arrays.
|
|
126
|
+
|
|
24
127
|
## What's new in 1.2.0
|
|
25
128
|
|
|
26
129
|
More knobs, per-channel rules, and bilingual user-facing text.
|
|
@@ -105,6 +208,8 @@ console.log(antispam.getStats());
|
|
|
105
208
|
|
|
106
209
|
## Table of contents
|
|
107
210
|
|
|
211
|
+
- [What's new in 1.4.0](#whats-new-in-140)
|
|
212
|
+
- [What's new in 1.3.0](#whats-new-in-130)
|
|
108
213
|
- [What's new in 1.2.0](#whats-new-in-120)
|
|
109
214
|
- [What's new in 1.1.0](#whats-new-in-110)
|
|
110
215
|
- [Features](#features)
|
|
@@ -138,17 +243,27 @@ console.log(antispam.getStats());
|
|
|
138
243
|
| **file** | Dangerous attachments (`.exe`, `.bat`, `.dll`, `.msi`, …) |
|
|
139
244
|
| **zalgo** | Obfuscated / zalgo text (stacked combining marks) |
|
|
140
245
|
| **newline** | Message walls made of empty lines |
|
|
141
|
-
| **account** | Brand-new Discord accounts / default avatar (off by default) |
|
|
246
|
+
| **account** | Brand-new Discord accounts / default avatar / new guild members (off by default) |
|
|
142
247
|
| **length** | Over-long messages (off by default) |
|
|
248
|
+
| **word** | Custom blocked words and regex (off until you fill `list` / `regex`) |
|
|
249
|
+
| **hop** | Same user jumping across too many channels |
|
|
250
|
+
| **punctuation** | Long runs of the same character (`!!!!`, `aaaa`) |
|
|
251
|
+
| **spoiler** | Spoiler-tag walls |
|
|
252
|
+
| **ghost** | Deleted messages that mentioned users (off by default) |
|
|
253
|
+
| **secret** | Accidental Discord bot tokens / webhook URLs in chat |
|
|
254
|
+
| **echo** | Same text pasted in several channels |
|
|
255
|
+
| **invisible** | Zero-width / bidi obfuscation |
|
|
256
|
+
| **attach** | Attachment floods over a sliding window |
|
|
143
257
|
|
|
144
258
|
Also included:
|
|
145
259
|
|
|
146
260
|
- Three presets: `lenient`, `balanced`, `strict`
|
|
147
|
-
- Ignore lists for users, roles, channels, categories, and
|
|
261
|
+
- Ignore lists for users, roles, channels, categories, guilds, and command prefixes
|
|
262
|
+
- Per-guild, per-channel, and per-role overlays
|
|
148
263
|
- Strike system with decay
|
|
149
|
-
- Optional delete / warn / timeout / kick / ban (kick and ban are **off** by default)
|
|
264
|
+
- Optional delete / warn / timeout / kick / ban / addRole / removeRole (kick and ban are **off** by default)
|
|
150
265
|
- `dryRun` to tune rules without punishing anyone
|
|
151
|
-
- Edit scanning (links and
|
|
266
|
+
- Edit scanning (links, mentions, and words)
|
|
152
267
|
- Zero extra runtime dependencies (peer: `discord.js`)
|
|
153
268
|
- In-memory store only — no database required
|
|
154
269
|
- Full TypeScript types
|
|
@@ -263,6 +378,7 @@ npm run dev
|
|
|
263
378
|
| Warn in the channel | **Send Messages** |
|
|
264
379
|
| Log embeds | **Embed Links** |
|
|
265
380
|
| Kick / ban (opt-in) | **Kick Members** / **Ban Members** |
|
|
381
|
+
| Mute / add / remove roles (opt-in) | **Manage Roles** |
|
|
266
382
|
|
|
267
383
|
The bot will not sanction the guild owner or anyone above it in the role hierarchy. Those actions are skipped and reported in `onAction`.
|
|
268
384
|
|
|
@@ -270,11 +386,12 @@ Enable **Message Content Intent** in the [Discord Developer Portal](https://disc
|
|
|
270
386
|
|
|
271
387
|
## How it works
|
|
272
388
|
|
|
273
|
-
1. Ignores bots, webhooks, the owner, administrators, and anything in your ignore lists.
|
|
389
|
+
1. Ignores bots, webhooks, system messages, the owner, administrators, command prefixes, and anything in your ignore lists.
|
|
274
390
|
2. Keeps a short **in-memory** history per user and guild (no database).
|
|
275
|
-
3. Runs detectors in this order: files → flood → duplicates → links → images → mentions → zalgo → newlines → caps → emojis. The first match wins.
|
|
391
|
+
3. Runs detectors in this order: files → secrets → words → flood → hop → echo → duplicates → attachments → links → images → mentions → zalgo → newlines → punctuation → spoilers → invisible → accounts → length → caps → emojis. The first match wins.
|
|
276
392
|
4. Adds one strike (with optional decay) and applies the configured punishment.
|
|
277
|
-
5. Message edits
|
|
393
|
+
5. Message edits re-check **links**, **mentions**, **words**, **secrets**, and **invisible**.
|
|
394
|
+
6. Deletes can trigger **ghost** pings if `ghostPing.enabled` is true.
|
|
278
395
|
|
|
279
396
|
Call `antispam.stop()` on shutdown, hot reload, or plugin unload.
|
|
280
397
|
|
|
@@ -304,6 +421,8 @@ new AntiSpam(client, {
|
|
|
304
421
|
| Mentions | 10 | 6 | 3 |
|
|
305
422
|
| Block invites | no | no | yes |
|
|
306
423
|
| Block shorteners | no | yes | yes |
|
|
424
|
+
| Channel hop | off | 5 / 8s | 3 / 6s |
|
|
425
|
+
| Ghost pings | off | off | on |
|
|
307
426
|
| Auto timeout | off | 60s from 2 strikes | 5 min from 1 strike |
|
|
308
427
|
|
|
309
428
|
## Full configuration
|
|
@@ -320,13 +439,17 @@ Every option is optional. Missing fields fall back to the preset (or `balanced`
|
|
|
320
439
|
| `ignoreWebhooks` | `boolean` | `true` | Skip webhooks. |
|
|
321
440
|
| `ignoreOwner` | `boolean` | `true` | Skip the guild owner. |
|
|
322
441
|
| `ignoreAdministrators` | `boolean` | `true` | Skip members with Administrator. |
|
|
323
|
-
| `checkEdits` | `boolean` | `true` | Re-scan edits for links and
|
|
442
|
+
| `checkEdits` | `boolean` | `true` | Re-scan edits for links, mentions, and words. |
|
|
443
|
+
| `checkDeletes` | `boolean` | `true` | Listen for `messageDelete` (ghost pings). |
|
|
444
|
+
| `ignoreThreads` | `boolean` | `false` | Skip messages in threads. |
|
|
445
|
+
| `ignoreSystem` | `boolean` | `true` | Skip Discord system messages. |
|
|
324
446
|
| `cleanupIntervalMs` | `number` | `60000` | How often the memory store is pruned. |
|
|
325
447
|
| `locale` | `"en"` \| `"es"` | `"en"` | Language for warnings and log embeds. |
|
|
326
448
|
| `ignorePermissions` | `string[]` | `[]` | Permission names that bypass checks. |
|
|
327
449
|
| `disabledDetectors` | `DetectorType[]` | `[]` | Detectors to skip. |
|
|
328
450
|
| `detectorOrder` | `DetectorType[]` | `[]` | Custom order. Empty = default. |
|
|
329
451
|
| `channelOverrides` | `object` | `{}` | Per-channel patches keyed by channel id. |
|
|
452
|
+
| `roleOverrides` | `object` | `{}` | Per-role patches keyed by role id. |
|
|
330
453
|
|
|
331
454
|
### Ignore lists
|
|
332
455
|
|
|
@@ -337,10 +460,11 @@ ignored: {
|
|
|
337
460
|
channels: ["789"],
|
|
338
461
|
categories: ["101"],
|
|
339
462
|
guilds: ["202"],
|
|
463
|
+
prefixes: ["!", "/", "."],
|
|
340
464
|
}
|
|
341
465
|
```
|
|
342
466
|
|
|
343
|
-
IDs are snowflakes as strings. A staff role in `ignored.roles` bypasses every detector.
|
|
467
|
+
IDs are snowflakes as strings. A staff role in `ignored.roles` bypasses every detector. `prefixes` skip command messages (`!help` is ignored if `"!"` is listed).
|
|
344
468
|
|
|
345
469
|
### Flood
|
|
346
470
|
|
|
@@ -387,6 +511,9 @@ links: {
|
|
|
387
511
|
suspiciousTlds: [], // e.g. ["tk", "gq"]
|
|
388
512
|
customPatterns: [], // regex against the whole message
|
|
389
513
|
extraPhishingKeywords: ["fake giveaway"],
|
|
514
|
+
maxLinks: 0,
|
|
515
|
+
scanEmbeds: true,
|
|
516
|
+
blockOauth: true,
|
|
390
517
|
severity: "high",
|
|
391
518
|
}
|
|
392
519
|
```
|
|
@@ -402,6 +529,7 @@ Built-in checks (each can be turned off):
|
|
|
402
529
|
- Scam phrases plus any link (`free nitro`, `steam gift`, `verifica tu cuenta`, …)
|
|
403
530
|
- Discord invite links if `blockInvites` is `true`
|
|
404
531
|
- Markdown-masked links: `[click](https://evil.test)`
|
|
532
|
+
- Login / OAuth-looking paths on non-allowlisted hosts if `blockOauth` is `true`
|
|
405
533
|
|
|
406
534
|
```js
|
|
407
535
|
// Block foreign server invites
|
|
@@ -474,6 +602,7 @@ accounts: {
|
|
|
474
602
|
enabled: false, // turn on to flag new users
|
|
475
603
|
minAgeDays: 3,
|
|
476
604
|
blockDefaultAvatar: false,
|
|
605
|
+
minGuildAgeDays: 0, // 0 = off; e.g. 1 = joined this guild today
|
|
477
606
|
severity: "medium",
|
|
478
607
|
}
|
|
479
608
|
|
|
@@ -490,6 +619,7 @@ length: {
|
|
|
490
619
|
files: {
|
|
491
620
|
enabled: true,
|
|
492
621
|
blockedExtensions: ["exe", "bat", "cmd", "com", "scr", "dll", "msi", "vbs", "ps1", "jar", "apk"],
|
|
622
|
+
maxBytes: 0, // 0 = unlimited
|
|
493
623
|
severity: "critical",
|
|
494
624
|
}
|
|
495
625
|
|
|
@@ -506,6 +636,57 @@ newlines: {
|
|
|
506
636
|
}
|
|
507
637
|
```
|
|
508
638
|
|
|
639
|
+
### Words, channel hop, punctuation, spoilers
|
|
640
|
+
|
|
641
|
+
```js
|
|
642
|
+
words: {
|
|
643
|
+
enabled: false, // stays off until you add a list or regex
|
|
644
|
+
list: ["raid-now"],
|
|
645
|
+
regex: ["n[i1]tro\\s+free"],
|
|
646
|
+
ignoreCase: true,
|
|
647
|
+
matchWholeWord: true,
|
|
648
|
+
severity: "high",
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
hop: {
|
|
652
|
+
enabled: true,
|
|
653
|
+
maxChannels: 5, // 5th unique channel in the window triggers
|
|
654
|
+
windowMs: 8_000,
|
|
655
|
+
severity: "high",
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
punctuation: {
|
|
659
|
+
enabled: true,
|
|
660
|
+
maxRepeated: 10, // 11+ of the same character in a row
|
|
661
|
+
severity: "low",
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
spoilers: {
|
|
665
|
+
enabled: true,
|
|
666
|
+
maxSpoilers: 8,
|
|
667
|
+
severity: "low",
|
|
668
|
+
}
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
`lenient` turns hop and punctuation off. `strict` tightens hop to 3 channels / 6s.
|
|
672
|
+
|
|
673
|
+
### Ghost pings
|
|
674
|
+
|
|
675
|
+
Off in `balanced` / `lenient`. On in `strict`. Needs `checkDeletes: true` (default) and the deleted message in cache (`Partials.Message` in your Client).
|
|
676
|
+
|
|
677
|
+
```js
|
|
678
|
+
ghostPing: {
|
|
679
|
+
enabled: false,
|
|
680
|
+
minMentions: 1,
|
|
681
|
+
maxAgeMs: 15_000, // 0 = any age
|
|
682
|
+
severity: "high",
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
checkDeletes: true
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
Disable with `ghostPing: { enabled: false }` or `disabledDetectors: ["ghost"]`.
|
|
689
|
+
|
|
509
690
|
### Punishment
|
|
510
691
|
|
|
511
692
|
Kick and ban stay **disabled** on purpose. Turn them on only if you really want that.
|
|
@@ -525,6 +706,9 @@ punishment: {
|
|
|
525
706
|
cooldownMs: 8_000, // no second timeout/warn during this window
|
|
526
707
|
deleteDuringCooldown: true, // still delete extra spam quietly
|
|
527
708
|
warnAsEmbed: false,
|
|
709
|
+
addRoleIds: [], // e.g. ["MUTE_ROLE_ID"] — needs Manage Roles
|
|
710
|
+
removeRoleIds: [],
|
|
711
|
+
minStrikesForRoles: 1,
|
|
528
712
|
}
|
|
529
713
|
|
|
530
714
|
// timeout.scale: "none" | "linear" (base * strikes) | "exponential" (base * 2^n)
|
|
@@ -534,7 +718,7 @@ punishment: {
|
|
|
534
718
|
|
|
535
719
|
`warnMessage` placeholders: `{user}` `{reason}` `{type}` `{strikes}`.
|
|
536
720
|
|
|
537
|
-
With `escalate: true`, Disguard applies **one** hard action (timeout, or kick, or ban — whichever threshold you hit). Delete and warn can still run together.
|
|
721
|
+
With `escalate: true`, Disguard applies **one** hard action (timeout, or kick, or ban — whichever threshold you hit). Delete and warn can still run together. `addRole` / `removeRole` run if those ID lists are non-empty and strikes ≥ `minStrikesForRoles`.
|
|
538
722
|
|
|
539
723
|
If the bot lacks a permission, or the target is higher in the hierarchy, that action is skipped and listed in `result.skipped`.
|
|
540
724
|
|
|
@@ -552,6 +736,9 @@ new AntiSpam(client, {
|
|
|
552
736
|
onError(error, context) {
|
|
553
737
|
console.error("[disguard]", context, error);
|
|
554
738
|
},
|
|
739
|
+
onCooldown(message) {
|
|
740
|
+
// Extra spam during punishment.cooldownMs (already deleted if deleteDuringCooldown).
|
|
741
|
+
},
|
|
555
742
|
});
|
|
556
743
|
```
|
|
557
744
|
|
|
@@ -559,7 +746,10 @@ new AntiSpam(client, {
|
|
|
559
746
|
|
|
560
747
|
```ts
|
|
561
748
|
{
|
|
562
|
-
type: "flood" | "duplicate" | "link" | "image" | "mention" | "caps" | "emoji"
|
|
749
|
+
type: "flood" | "duplicate" | "link" | "image" | "mention" | "caps" | "emoji"
|
|
750
|
+
| "file" | "zalgo" | "newline" | "account" | "length"
|
|
751
|
+
| "word" | "hop" | "punctuation" | "spoiler" | "ghost"
|
|
752
|
+
| "secret" | "echo" | "invisible" | "attach",
|
|
563
753
|
severity: "low" | "medium" | "high" | "critical",
|
|
564
754
|
userId: string,
|
|
565
755
|
guildId: string,
|
|
@@ -567,7 +757,7 @@ new AntiSpam(client, {
|
|
|
567
757
|
messageId: string,
|
|
568
758
|
reason: string,
|
|
569
759
|
details: Record<string, unknown>,
|
|
570
|
-
recommendedActions: Array<"delete" | "warn" | "timeout" | "kick" | "ban">,
|
|
760
|
+
recommendedActions: Array<"delete" | "warn" | "timeout" | "kick" | "ban" | "addRole" | "removeRole" | "purge">,
|
|
571
761
|
timestamp: number,
|
|
572
762
|
}
|
|
573
763
|
```
|
|
@@ -594,6 +784,11 @@ const antispam = new AntiSpam(client, options);
|
|
|
594
784
|
|
|
595
785
|
antispam.start();
|
|
596
786
|
antispam.stop();
|
|
787
|
+
antispam.pause();
|
|
788
|
+
antispam.resume();
|
|
789
|
+
antispam.isPaused();
|
|
790
|
+
antispam.setEnabled(false);
|
|
791
|
+
antispam.isEnabled();
|
|
597
792
|
|
|
598
793
|
const config = antispam.getConfig();
|
|
599
794
|
antispam.setConfig({ flood: { maxMessages: 8 } }); // deep merge, other keys stay
|
|
@@ -608,6 +803,8 @@ antispam.clearGuildConfig(guildId);
|
|
|
608
803
|
antispam.setChannelConfig(guildId, channelId, { images: { maxRepeats: 8 } });
|
|
609
804
|
antispam.getChannelConfig(guildId, channelId);
|
|
610
805
|
antispam.clearChannelConfig(guildId, channelId);
|
|
806
|
+
antispam.setRoleConfig(roleId, { flood: { maxMessages: 12 } });
|
|
807
|
+
antispam.clearRoleConfig(roleId);
|
|
611
808
|
|
|
612
809
|
antispam.use(customDetector);
|
|
613
810
|
antispam.getStats();
|
|
@@ -692,6 +889,18 @@ antispam.setConfig(resolveConfig("strict", { ignored: antispam.getConfig().ignor
|
|
|
692
889
|
images: { hashMode: "content", maxDownloadBytes: 1_000_000 }
|
|
693
890
|
```
|
|
694
891
|
|
|
892
|
+
**Mute role instead of timeout**
|
|
893
|
+
|
|
894
|
+
```js
|
|
895
|
+
punishment: {
|
|
896
|
+
timeout: { enabled: false, durationMs: 60_000, minStrikes: 99 },
|
|
897
|
+
addRoleIds: ["MUTE_ROLE_ID"],
|
|
898
|
+
minStrikesForRoles: 1,
|
|
899
|
+
}
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
The bot role must sit **above** the mute role. Needs **Manage Roles**.
|
|
903
|
+
|
|
695
904
|
**Reset a user after a false positive**
|
|
696
905
|
|
|
697
906
|
```js
|
|
@@ -746,9 +955,18 @@ Wait a few seconds between categories so flood does not eat the next test.
|
|
|
746
955
|
| File | Upload a dummy `.exe` or `.bat` |
|
|
747
956
|
| Zalgo | Text with many stacked combining marks |
|
|
748
957
|
| Newlines | A message with more than 15 line breaks |
|
|
958
|
+
| Channel hop | Same user posts in 5 different channels within 8 seconds |
|
|
959
|
+
| Punctuation | `aaaaaaaaaaa` or `!!!!!!!!!!!` |
|
|
960
|
+
| Spoilers | More than 8 `\|\|spoiler\|\|` pairs |
|
|
961
|
+
| Blocked word | Enable `words` first, then send a listed word |
|
|
962
|
+
| Ghost ping | Mention someone and delete the message within 15s (`ghostPing.enabled: true`) |
|
|
963
|
+
| Secret | Paste a dummy webhook URL `https://discord.com/api/webhooks/123/abc` |
|
|
964
|
+
| Echo | Same long sentence in 3 channels within 12s |
|
|
965
|
+
| Invisible | A message padded with many zero-width spaces |
|
|
966
|
+
| Attachments | 8+ files in 10 seconds |
|
|
749
967
|
| Edit | Send `hello`, then edit it to `Free Nitro https://bit.ly/test` |
|
|
750
968
|
|
|
751
|
-
Watch the terminal: `[detect] flood|duplicate|link|image|mention|caps|emoji`.
|
|
969
|
+
Watch the terminal: `[detect] flood|duplicate|link|image|mention|caps|emoji|file|zalgo|newline|word|hop|punctuation|spoiler|ghost|secret|echo|invisible|attach`.
|
|
752
970
|
|
|
753
971
|
The second strike applies a 1 minute timeout with the default example config. Strikes decay after 15 minutes, or call `resetUser`.
|
|
754
972
|
|
|
@@ -789,6 +1007,73 @@ MIT
|
|
|
789
1007
|
|
|
790
1008
|
# Español
|
|
791
1009
|
|
|
1010
|
+
## Novedades de 1.4.0
|
|
1011
|
+
|
|
1012
|
+
Escaneo de secretos, copypasta entre canales, unicode invisible, flood de adjuntos y logs por webhook. Kick/ban siguen **apagados**.
|
|
1013
|
+
|
|
1014
|
+
| Opción | Default | Qué hace |
|
|
1015
|
+
| --- | --- | --- |
|
|
1016
|
+
| `secrets` | **on** | Caza **tokens de bot** y **webhooks** pegados en el chat. El incidente **no** guarda el secreto. |
|
|
1017
|
+
| `echo` | **on**, 3 canales / 12s | El mismo texto en varios canales (raid). No es lo mismo que `hop`. |
|
|
1018
|
+
| `invisible` | **on**, 8 | Caracteres de ancho cero / bidi para saltarse filtros. |
|
|
1019
|
+
| `attach` | **on**, 8 / 10s | Demasiados adjuntos en una ventana, no solo `.exe`. |
|
|
1020
|
+
| `duplicates.minLength` | `8` | `ok` / `lol` ya no cuentan como duplicado. |
|
|
1021
|
+
| `mentions.maxInWindow` | `0` (off) | Tope de menciones entre varios mensajes. |
|
|
1022
|
+
| `accounts.onlyWithLinks` | `false` (`strict`: true) | Cuentas nuevas solo si el mensaje trae URL. |
|
|
1023
|
+
| `punishment.purgeCount` | `0` | Tras un hit, borra N mensajes recientes de ese user en el canal. |
|
|
1024
|
+
| `punishment.logWebhookUrl` | `null` | Logs a un webhook de Discord. |
|
|
1025
|
+
| `ignorePinned` | `false` | Ignora pineados. |
|
|
1026
|
+
| `ignoreOlderThanMs` | `0` | Ignora mensajes viejos (replay al reconectar). |
|
|
1027
|
+
| `setEnabled(false)` | — | Apaga el filtro sin `stop()`. |
|
|
1028
|
+
|
|
1029
|
+
```js
|
|
1030
|
+
new AntiSpam(client, {
|
|
1031
|
+
secrets: { enabled: true, extraPatterns: ["ghp_[A-Za-z0-9]{20,}"] },
|
|
1032
|
+
echo: { maxChannels: 3 },
|
|
1033
|
+
accounts: { enabled: true, onlyWithLinks: true },
|
|
1034
|
+
punishment: { purgeCount: 5, logWebhookUrl: process.env.DISGUARD_LOG_WEBHOOK || null },
|
|
1035
|
+
});
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
## Novedades de 1.3.0
|
|
1039
|
+
|
|
1040
|
+
Más detectores, overlays por rol, mute por rol y más ignores. Todo es opcional.
|
|
1041
|
+
|
|
1042
|
+
| Opción | Default | Qué hace |
|
|
1043
|
+
| --- | --- | --- |
|
|
1044
|
+
| `words` | **apagado**, lista vacía | Palabras y/o regex bloqueados. `ignoreCase` y `matchWholeWord` en `true`. |
|
|
1045
|
+
| `hop` | **on**, 5 canales / 8s | El mismo usuario escribe en demasiados canales (raid / hop). |
|
|
1046
|
+
| `punctuation` | **on**, 10 | Rachas de `aaaaaa` / `!!!!!!` más largas que `maxRepeated`. |
|
|
1047
|
+
| `spoilers` | **on**, 8 pares | Demasiados `\|\|spoiler\|\|` en un mensaje. |
|
|
1048
|
+
| `ghostPing` | **off** (`strict`: on) | Castiga borrar un mensaje que mencionaba gente. |
|
|
1049
|
+
| `checkDeletes` | `true` | Escucha `messageDelete`. |
|
|
1050
|
+
| `ignored.prefixes` | `[]` | Ignora mensajes que empiezan por `!`, `/`, `.`. |
|
|
1051
|
+
| `ignoreThreads` | `false` | Ignora hilos. |
|
|
1052
|
+
| `ignoreSystem` | `true` | Ignora mensajes de sistema. |
|
|
1053
|
+
| `roleOverrides` / `setRoleConfig` | `{}` | Config por rol (antes de la de canal). |
|
|
1054
|
+
| `links.blockOauth` | `true` | URLs de login/OAuth fuera de la allowList. `discord.com` sigue permitido. |
|
|
1055
|
+
| `files.maxBytes` | `0` | Tamaño máximo de adjunto. `0` = sin límite. |
|
|
1056
|
+
| `accounts.minGuildAgeDays` | `0` | Miembros demasiado nuevos en **este** servidor. `0` = off. |
|
|
1057
|
+
| `punishment.addRoleIds` / `removeRoleIds` | `[]` | Añadir/quitar roles al castigar (mute). Hace falta **Manage Roles**. |
|
|
1058
|
+
| `onCooldown` | — | Callback cuando el cooldown borra spam extra en silencio. |
|
|
1059
|
+
| `pause()` / `resume()` | — | Congela el antispam sin quitar listeners. |
|
|
1060
|
+
|
|
1061
|
+
```js
|
|
1062
|
+
const antispam = new AntiSpam(client, {
|
|
1063
|
+
locale: "es",
|
|
1064
|
+
ignored: { prefixes: ["!", "/", "."], roles: ["ID_STAFF"] },
|
|
1065
|
+
words: { enabled: true, list: ["raid-now"] },
|
|
1066
|
+
hop: { maxChannels: 4, windowMs: 6_000 },
|
|
1067
|
+
ghostPing: { enabled: true, maxAgeMs: 15_000 },
|
|
1068
|
+
punishment: { addRoleIds: ["ID_MUTE"], minStrikesForRoles: 2 },
|
|
1069
|
+
});
|
|
1070
|
+
|
|
1071
|
+
antispam.setRoleConfig("ID_VIP", { flood: { maxMessages: 10 } });
|
|
1072
|
+
antispam.pause();
|
|
1073
|
+
```
|
|
1074
|
+
|
|
1075
|
+
Kick y ban siguen **apagados**. Ghost ping necesita el mensaje en caché (`Partials.Message`).
|
|
1076
|
+
|
|
792
1077
|
## Novedades de 1.2.0
|
|
793
1078
|
|
|
794
1079
|
Más opciones, reglas por canal y textos al usuario en inglés o español.
|
|
@@ -839,6 +1124,8 @@ new AntiSpam(client, {
|
|
|
839
1124
|
|
|
840
1125
|
## Tabla de contenidos
|
|
841
1126
|
|
|
1127
|
+
- [Novedades de 1.4.0](#novedades-de-140)
|
|
1128
|
+
- [Novedades de 1.3.0](#novedades-de-130)
|
|
842
1129
|
- [Novedades de 1.2.0](#novedades-de-120)
|
|
843
1130
|
- [Novedades de 1.1.0](#novedades-de-110)
|
|
844
1131
|
- [Qué es](#qué-es)
|
|
@@ -862,7 +1149,7 @@ new AntiSpam(client, {
|
|
|
862
1149
|
|
|
863
1150
|
**Disguard** es una librería antispam para bots de discord.js v14. No es un bot: la enchufas a tu `Client` y tú decides umbrales, listas y castigos.
|
|
864
1151
|
|
|
865
|
-
Detecta flood,
|
|
1152
|
+
Detecta flood, salto de canales, palabras bloqueadas, phishing / enlaces no deseados (también en embeds), imágenes repetidas, spam de menciones, ghost pings, mayúsculas, emojis, archivos peligrosos, zalgo y paredes de líneas.
|
|
866
1153
|
|
|
867
1154
|
## Requisitos
|
|
868
1155
|
|
|
@@ -948,6 +1235,7 @@ npm run dev
|
|
|
948
1235
|
| Avisar en el canal | **Send Messages** |
|
|
949
1236
|
| Embed de logs | **Embed Links** |
|
|
950
1237
|
| Kick / ban (opt-in) | **Kick Members** / **Ban Members** |
|
|
1238
|
+
| Mute / add / remove roles (opt-in) | **Manage Roles** |
|
|
951
1239
|
|
|
952
1240
|
No puede sancionar al dueño del servidor ni a quien esté por encima del bot en la jerarquía.
|
|
953
1241
|
|
|
@@ -955,11 +1243,12 @@ Activa **Message Content Intent** en el [Portal de Discord](https://discord.com/
|
|
|
955
1243
|
|
|
956
1244
|
## Cómo funciona
|
|
957
1245
|
|
|
958
|
-
1. Ignora bots, webhooks, el dueño, administradores y tus listas de ignore.
|
|
1246
|
+
1. Ignora bots, webhooks, mensajes de sistema, el dueño, administradores, prefijos de comando y tus listas de ignore.
|
|
959
1247
|
2. Guarda en **memoria** un historial corto por usuario y servidor. Sin base de datos.
|
|
960
|
-
3. Pasa el mensaje por: flood → duplicados → enlaces → imágenes → menciones → caps → emojis. El primero que dispare gana.
|
|
1248
|
+
3. Pasa el mensaje por: archivos → secretos → palabras → flood → hop → echo → duplicados → adjuntos → enlaces → imágenes → menciones → zalgo → líneas → puntuación → spoilers → invisibles → cuentas → longitud → caps → emojis. El primero que dispare gana.
|
|
961
1249
|
4. Suma un strike (con caducidad) y aplica el castigo configurado.
|
|
962
|
-
5. Las ediciones
|
|
1250
|
+
5. Las ediciones revisan **enlaces**, **menciones** y **palabras**.
|
|
1251
|
+
6. Los borrados pueden disparar **ghost** ping si `ghostPing.enabled` es true.
|
|
963
1252
|
|
|
964
1253
|
Llama `antispam.stop()` al apagar el proceso.
|
|
965
1254
|
|
|
@@ -992,8 +1281,12 @@ Todo es opcional. Lo que no pongas usa el preset.
|
|
|
992
1281
|
| `ignoreWebhooks` | `boolean` | `true` | Ignora webhooks. |
|
|
993
1282
|
| `ignoreOwner` | `boolean` | `true` | Ignora al dueño. |
|
|
994
1283
|
| `ignoreAdministrators` | `boolean` | `true` | Ignora quien tenga Administrator. |
|
|
995
|
-
| `checkEdits` | `boolean` | `true` | Revisa ediciones (enlaces y
|
|
1284
|
+
| `checkEdits` | `boolean` | `true` | Revisa ediciones (enlaces, menciones y palabras). |
|
|
1285
|
+
| `checkDeletes` | `boolean` | `true` | Escucha `messageDelete` (ghost pings). |
|
|
1286
|
+
| `ignoreThreads` | `boolean` | `false` | Ignora hilos. |
|
|
1287
|
+
| `ignoreSystem` | `boolean` | `true` | Ignora mensajes de sistema. |
|
|
996
1288
|
| `cleanupIntervalMs` | `number` | `60000` | Limpieza de memoria. |
|
|
1289
|
+
| `roleOverrides` | `object` | `{}` | Parches por rol. |
|
|
997
1290
|
|
|
998
1291
|
### Listas de ignore
|
|
999
1292
|
|
|
@@ -1004,6 +1297,7 @@ ignored: {
|
|
|
1004
1297
|
channels: ["id"],
|
|
1005
1298
|
categories: ["id"],
|
|
1006
1299
|
guilds: ["id"],
|
|
1300
|
+
prefixes: ["!", "/", "."],
|
|
1007
1301
|
}
|
|
1008
1302
|
```
|
|
1009
1303
|
|
|
@@ -1048,13 +1342,16 @@ links: {
|
|
|
1048
1342
|
suspiciousTlds: [],
|
|
1049
1343
|
customPatterns: ["steamcommunity\\.ru"],
|
|
1050
1344
|
extraPhishingKeywords: ["sorteo falso"],
|
|
1345
|
+
maxLinks: 0,
|
|
1346
|
+
scanEmbeds: true,
|
|
1347
|
+
blockOauth: true,
|
|
1051
1348
|
severity: "high",
|
|
1052
1349
|
}
|
|
1053
1350
|
```
|
|
1054
1351
|
|
|
1055
1352
|
La `allowList` gana a las heurísticas. `discord.com` y `youtube.com` ya vienen permitidos.
|
|
1056
1353
|
|
|
1057
|
-
Heurísticas incluidas (todas se pueden apagar): acortadores, IPs, punycode, clones de marcas, palabras de estafa + enlace, invitaciones si `blockInvites` es `true`,
|
|
1354
|
+
Heurísticas incluidas (todas se pueden apagar): acortadores, IPs, punycode, clones de marcas, palabras de estafa + enlace, invitaciones si `blockInvites` es `true`, enlaces enmascarados `[texto](url)`, y rutas de login/OAuth si `blockOauth` es `true`.
|
|
1058
1355
|
|
|
1059
1356
|
### Imágenes
|
|
1060
1357
|
|
|
@@ -1086,11 +1383,23 @@ emojis: { enabled: true, maxEmojis: 12, maxStickers: 3, severity: "low" },
|
|
|
1086
1383
|
### Archivos, zalgo, saltos de línea
|
|
1087
1384
|
|
|
1088
1385
|
```js
|
|
1089
|
-
files: { enabled: true, blockedExtensions: ["exe", "bat", "cmd", "dll", "msi"], severity: "critical" },
|
|
1386
|
+
files: { enabled: true, blockedExtensions: ["exe", "bat", "cmd", "dll", "msi"], maxBytes: 0, severity: "critical" },
|
|
1090
1387
|
zalgo: { enabled: true, maxCombining: 20, severity: "medium" },
|
|
1091
1388
|
newlines: { enabled: true, maxNewlines: 15, severity: "low" },
|
|
1092
1389
|
```
|
|
1093
1390
|
|
|
1391
|
+
### Palabras, hop, puntuación, spoilers, ghost ping
|
|
1392
|
+
|
|
1393
|
+
```js
|
|
1394
|
+
words: { enabled: false, list: ["raid-now"], regex: [], ignoreCase: true, matchWholeWord: true, severity: "high" },
|
|
1395
|
+
hop: { enabled: true, maxChannels: 5, windowMs: 8_000, severity: "high" },
|
|
1396
|
+
punctuation: { enabled: true, maxRepeated: 10, severity: "low" },
|
|
1397
|
+
spoilers: { enabled: true, maxSpoilers: 8, severity: "low" },
|
|
1398
|
+
ghostPing: { enabled: false, minMentions: 1, maxAgeMs: 15_000, severity: "high" },
|
|
1399
|
+
```
|
|
1400
|
+
|
|
1401
|
+
`lenient` apaga hop y puntuación. `strict` enciende ghost ping y aprieta hop a 3 canales / 6s.
|
|
1402
|
+
|
|
1094
1403
|
### Castigos
|
|
1095
1404
|
|
|
1096
1405
|
Kick y ban van **apagados**. Actívalos solo si lo tienes claro.
|
|
@@ -1109,12 +1418,15 @@ punishment: {
|
|
|
1109
1418
|
strikeDecayMs: 15 * 60_000,
|
|
1110
1419
|
cooldownMs: 8_000,
|
|
1111
1420
|
deleteDuringCooldown: true,
|
|
1421
|
+
addRoleIds: [],
|
|
1422
|
+
removeRoleIds: [],
|
|
1423
|
+
minStrikesForRoles: 1,
|
|
1112
1424
|
}
|
|
1113
1425
|
```
|
|
1114
1426
|
|
|
1115
1427
|
Placeholders: `{user}` `{reason}` `{type}` `{strikes}`.
|
|
1116
1428
|
|
|
1117
|
-
Con `escalate: true` se aplica **un** castigo fuerte (timeout, kick o ban). Aviso y borrado se pueden sumar.
|
|
1429
|
+
Con `escalate: true` se aplica **un** castigo fuerte (timeout, kick o ban). Aviso y borrado se pueden sumar. `addRole` / `removeRole` corren si las listas no están vacías.
|
|
1118
1430
|
|
|
1119
1431
|
## Callbacks
|
|
1120
1432
|
|
|
@@ -1126,6 +1438,7 @@ new AntiSpam(client, {
|
|
|
1126
1438
|
onError(error, context) {
|
|
1127
1439
|
console.error(context, error);
|
|
1128
1440
|
},
|
|
1441
|
+
onCooldown(message) {},
|
|
1129
1442
|
});
|
|
1130
1443
|
```
|
|
1131
1444
|
|
|
@@ -1138,11 +1451,16 @@ const antispam = new AntiSpam(client, options);
|
|
|
1138
1451
|
|
|
1139
1452
|
antispam.start();
|
|
1140
1453
|
antispam.stop();
|
|
1454
|
+
antispam.pause();
|
|
1455
|
+
antispam.resume();
|
|
1456
|
+
antispam.setEnabled(false);
|
|
1141
1457
|
antispam.getConfig();
|
|
1142
1458
|
antispam.setConfig({ flood: { maxMessages: 8 } });
|
|
1143
1459
|
antispam.getStrikes(guildId, userId);
|
|
1144
1460
|
antispam.resetUser(guildId, userId);
|
|
1145
1461
|
antispam.setGuildConfig(guildId, { flood: { maxMessages: 3 } });
|
|
1462
|
+
antispam.setChannelConfig(guildId, channelId, { flood: { maxMessages: 12 } });
|
|
1463
|
+
antispam.setRoleConfig(roleId, { emojis: { maxEmojis: 40 } });
|
|
1146
1464
|
antispam.getStats();
|
|
1147
1465
|
|
|
1148
1466
|
const incident = await antispam.analyze(message);
|
|
@@ -1174,6 +1492,8 @@ new AntiSpam(client, {
|
|
|
1174
1492
|
|
|
1175
1493
|
**Quitar strikes:** `antispam.resetUser(guildId, userId)`.
|
|
1176
1494
|
|
|
1495
|
+
**Mute por rol:** `punishment: { addRoleIds: ["ID_MUTE"], timeout: { enabled: false, durationMs: 0, minStrikes: 99 } }`. El rol del bot debe estar por encima del mute.
|
|
1496
|
+
|
|
1177
1497
|
**Cambiar a strict en caliente**
|
|
1178
1498
|
|
|
1179
1499
|
```js
|
|
@@ -1211,9 +1531,18 @@ Espera unos segundos entre categorías.
|
|
|
1211
1531
|
| Archivo | Sube un `.exe` o `.bat` (aunque sea de mentira) |
|
|
1212
1532
|
| Zalgo | Texto con muchos diacríticos apilados |
|
|
1213
1533
|
| Líneas | Un mensaje con más de 15 enters |
|
|
1534
|
+
| Hop | El mismo usuario en 5 canales distintos en 8s |
|
|
1535
|
+
| Puntuación | `aaaaaaaaaaa` o `!!!!!!!!!!!` |
|
|
1536
|
+
| Spoilers | Más de 8 pares `\|\|spoiler\|\|` |
|
|
1537
|
+
| Palabra | Activa `words` y manda una de la lista |
|
|
1538
|
+
| Ghost ping | Menciona a alguien y borra el mensaje en menos de 15s (`ghostPing.enabled: true`) |
|
|
1539
|
+
| Secreto | Pega un webhook de mentira `https://discord.com/api/webhooks/123/abc` |
|
|
1540
|
+
| Echo | La misma frase larga en 3 canales en 12s |
|
|
1541
|
+
| Invisible | Un mensaje con muchos espacios de ancho cero |
|
|
1542
|
+
| Adjuntos | 8+ archivos en 10 segundos |
|
|
1214
1543
|
| Edición | Manda `hola` y edítalo a `Free Nitro https://bit.ly/test` |
|
|
1215
1544
|
|
|
1216
|
-
En la terminal: `[detect] flood|duplicate|link|image|mention|caps|emoji|file|zalgo|newline`.
|
|
1545
|
+
En la terminal: `[detect] flood|duplicate|link|image|mention|caps|emoji|file|zalgo|newline|word|hop|punctuation|spoiler|ghost|secret|echo|invisible|attach`.
|
|
1217
1546
|
|
|
1218
1547
|
Al segundo strike el ejemplo mete timeout de 1 minuto. Los strikes caducan a los 15 minutos, o usa `resetUser`.
|
|
1219
1548
|
|