glassframe-protocol 1.2.1 → 2.1.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/CHANGELOG.md +184 -0
- package/GETTING_STARTED.md +23 -4
- package/README.md +55 -20
- package/dist/config.js +20 -1
- package/dist/src/GlassFrame.js +312 -42
- package/dist/src/commands/PrefixRouter.js +123 -48
- package/dist/src/core/Cache.js +10 -0
- package/dist/src/core/Layer.js +28 -23
- package/dist/src/core/PerformanceMonitor.js +16 -4
- package/dist/src/core/VersionInfo.js +1 -1
- package/dist/src/layers/AIModerationLayer.js +4 -4
- package/dist/src/layers/AntiNukeLayer.js +113 -16
- package/dist/src/layers/AntiRaidLayer.js +5 -7
- package/dist/src/layers/BasicSecurityLayer.js +39 -12
- package/dist/src/logging/SmartLogger.js +33 -3
- package/dist/src/moderation/PunishmentEngine.js +19 -7
- package/dist/src/ui/ControlPanel.js +195 -1
- package/dist/src/utils/nlpEngine.js +2 -2
- package/docs/CACHE_ARCHITECTURE.md +9 -0
- package/docs/COMMANDS.md +37 -11
- package/docs/ENGINE.md +83 -0
- package/docs/PROTOCOL_LAYERS.md +62 -17
- package/docs/STATE.md +101 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,190 @@ lives in `src/core/VersionInfo.js` (`VersionInfo.info()` /
|
|
|
14
14
|
`VersionInfo.banner()`), so code can read the current version without
|
|
15
15
|
parsing this file.
|
|
16
16
|
|
|
17
|
+
## [2.1.0] - 2026-08-01
|
|
18
|
+
|
|
19
|
+
Additive - nothing from 2.0.0's API changes. New detections, a plugin
|
|
20
|
+
system, per-guild customization, and an owner-only cross-server dashboard.
|
|
21
|
+
|
|
22
|
+
### Added - security detections
|
|
23
|
+
|
|
24
|
+
- **Dangerous role grants to a member.** The existing permission-grant
|
|
25
|
+
watchdog only caught a role's own permissions changing (`RoleUpdate`).
|
|
26
|
+
It missed the other half: someone with `ManageRoles` handing an
|
|
27
|
+
already-dangerous role directly to a member (`MemberRoleUpdate`) without
|
|
28
|
+
ever touching the role's definition. Now watched, gated the same way -
|
|
29
|
+
only flagged when the executor isn't recognized trusted staff.
|
|
30
|
+
- **Channel permission-overwrite abuse.** A nuke doesn't have to delete
|
|
31
|
+
anything - locking @everyone out of a public channel, or opening a
|
|
32
|
+
private one up to @everyone, does equivalent damage through permission
|
|
33
|
+
overwrites. Only @everyone's own overwrite is watched; a role- or
|
|
34
|
+
member-specific overwrite change is routine administration and ignored.
|
|
35
|
+
- **A dedicated @everyone/@here guard** in Basic Security, weighted well
|
|
36
|
+
above regular mention spam (a single mass ping reaches every member at
|
|
37
|
+
once) and skipped for recognized trusted staff, so a real admin's
|
|
38
|
+
announcement isn't flagged.
|
|
39
|
+
- **Raid-recruitment language is now actually used.** `raidCallout` scoring
|
|
40
|
+
existed in the NLP engine already but was never wired into
|
|
41
|
+
`BasicSecurityLayer`'s real decision logic - fixed. Also added a specific
|
|
42
|
+
invite-link + raid-language combo check (the "join this server to raid
|
|
43
|
+
with us" pattern), and expanded the raid lexicon to catch common word
|
|
44
|
+
forms ("raiding", "raids") that the bare-verb-only version missed.
|
|
45
|
+
|
|
46
|
+
### Added - extensibility
|
|
47
|
+
|
|
48
|
+
- **`frame.registerLayer(name, layerInstance)`** - add a custom security
|
|
49
|
+
layer to the same shared pipeline the built-in four use. Must extend
|
|
50
|
+
`core/Layer`; gets per-guild enable/disable, state persistence, and
|
|
51
|
+
`!gf status`/`!gf metrics` visibility for free, since those now iterate
|
|
52
|
+
`frame.layers` dynamically instead of a fixed list. Does not get an
|
|
53
|
+
automatic button on the 5-button panel (that stays fixed at 5).
|
|
54
|
+
- **`frame.registerAction(name, handler)`** - add a punishment action
|
|
55
|
+
beyond ban/kick/timeout/quarantine, referenceable from
|
|
56
|
+
`config.punishment.ladder`. Runs through the same action queue as the
|
|
57
|
+
built-in ones.
|
|
58
|
+
- **Per-guild custom prefix** - `!gf prefix set <newPrefix>` /
|
|
59
|
+
`!gf prefix reset`. `config.prefix` always still works everywhere as a
|
|
60
|
+
fallback; an overlapping custom/default pair resolves by trying the
|
|
61
|
+
longer one first.
|
|
62
|
+
- **Per-layer log channel routing** - `getLogChannel(guild, layerName)` now
|
|
63
|
+
receives the reporting layer's name as an optional second argument, so
|
|
64
|
+
different layers can route to different channels. Fully backward
|
|
65
|
+
compatible - a `getLogChannel` that only takes one parameter keeps
|
|
66
|
+
working unchanged.
|
|
67
|
+
|
|
68
|
+
### Added - the owner-only engine dashboard
|
|
69
|
+
|
|
70
|
+
- **`!gf engine`** - a bot-wide, cross-server dashboard: layer adoption
|
|
71
|
+
across every server, the busiest servers by event volume, AI usage
|
|
72
|
+
(Groq key pool/cooldowns/call volume), queue and cache health, and a live
|
|
73
|
+
feed of the last several things logged anywhere. See `docs/ENGINE.md`.
|
|
74
|
+
Deliberately not listed in `!gf help` - a per-server admin shouldn't know
|
|
75
|
+
it exists, let alone see data about other servers.
|
|
76
|
+
- **Its own permission model**, separate from every other command:
|
|
77
|
+
`options.owners` (a list of Discord user IDs) is required regardless, and
|
|
78
|
+
an optional `config.engine.password` is a second factor on the initial
|
|
79
|
+
command only - page-navigation clicks re-check `isOwner()` but don't
|
|
80
|
+
re-prompt for the password. Wrong guesses count toward a lockout
|
|
81
|
+
(`config.engine.maxAttempts`, `config.engine.lockoutMs`), and the command
|
|
82
|
+
message is deleted immediately either way so the password doesn't sit
|
|
83
|
+
visible in channel history.
|
|
84
|
+
- **5 pages** (Overview, Servers, AI, Performance, Activity Log), navigated
|
|
85
|
+
with a row of tab buttons - this is a second interactive surface,
|
|
86
|
+
entirely separate from the 5-button panel and the metrics command's own
|
|
87
|
+
button.
|
|
88
|
+
- `frame.getEngineReport()` - the raw data behind the dashboard, if you
|
|
89
|
+
want it for your own tooling instead of the rendered message.
|
|
90
|
+
- `PerformanceMonitor.recordEvent(name, guildId)` now optionally tracks
|
|
91
|
+
per-guild activity (`topGuildsByActivity()`) alongside the existing
|
|
92
|
+
by-name counters.
|
|
93
|
+
- `SmartLogger` keeps a bounded in-memory ring buffer (`getRecentLogs()`,
|
|
94
|
+
last 30) of recent events across every guild, powering the Activity Log
|
|
95
|
+
page.
|
|
96
|
+
|
|
97
|
+
### Changed
|
|
98
|
+
|
|
99
|
+
- `!gf help` reorganized into sections (Getting started / Security tools /
|
|
100
|
+
Diagnostics / Customization) with a one-line explanation of what each
|
|
101
|
+
command actually does, instead of a flat list of syntax.
|
|
102
|
+
- `!gf status` now explains what each layer actually watches for, not just
|
|
103
|
+
whether it's on, and iterates every registered layer (including custom
|
|
104
|
+
ones) instead of a fixed four.
|
|
105
|
+
- `!gf metrics` and the global engine view now carry a short plain-language
|
|
106
|
+
explanation under every number - what it means, and whether it's
|
|
107
|
+
generally worth a closer look.
|
|
108
|
+
|
|
109
|
+
### Fixed
|
|
110
|
+
|
|
111
|
+
- `raidCallout` NLP scoring was computed but never checked anywhere.
|
|
112
|
+
- The default `raidCalloutThreshold` (0.5) was miscalibrated against how
|
|
113
|
+
the scoring function actually behaves - lowered to 0.3, validated against
|
|
114
|
+
both a real raid-recruitment example and known-innocuous messages with
|
|
115
|
+
margin on both sides.
|
|
116
|
+
|
|
117
|
+
## [2.0.0] - 2026-08-01
|
|
118
|
+
|
|
119
|
+
**Breaking.** Layer activation and the whitelist were accidentally global
|
|
120
|
+
across every server the bot is in - this release makes them per-guild, the
|
|
121
|
+
way they were always supposed to work, and adds real state persistence.
|
|
122
|
+
|
|
123
|
+
### Fixed (breaking)
|
|
124
|
+
|
|
125
|
+
- **Layer on/off state is now per-guild.** Previously, `Layer.enabled` was
|
|
126
|
+
one shared boolean - arming AntiRaid from one server's control panel
|
|
127
|
+
silently armed it for *every* server the bot serves. `getStatus(guildId)`
|
|
128
|
+
accepted a `guildId` but never actually used it. Both are now genuinely
|
|
129
|
+
per-guild: `Layer.enabledGuilds` is a `Set<guildId>`, and
|
|
130
|
+
`frame.enableLayer(name, guildId)` / `frame.disableLayer(name, guildId)`
|
|
131
|
+
now **require** a `guildId` argument. Calling either without one throws,
|
|
132
|
+
rather than silently doing the wrong thing.
|
|
133
|
+
- **The whitelist is now per-guild.** `frame.whitelist` was a single global
|
|
134
|
+
`Set<userId>` - whitelisting someone in one server exempted them
|
|
135
|
+
everywhere. It's now a `Map<guildId, Set<userId>>`; use the new
|
|
136
|
+
`frame.addToWhitelist(guildId, userId)`,
|
|
137
|
+
`frame.removeFromWhitelist(guildId, userId)`, and
|
|
138
|
+
`frame.isWhitelisted(guildId, userId)` instead of touching the Map
|
|
139
|
+
directly. The constructor's `whitelist: [...]` option still works exactly
|
|
140
|
+
as before from the outside - it now seeds that list into every guild
|
|
141
|
+
(present and future) the first time GlassFrame sees it, rather than
|
|
142
|
+
applying globally.
|
|
143
|
+
- **State now actually persists.** `stateStore` was constructed and then
|
|
144
|
+
never read from or written to anywhere. Every layer toggle and whitelist
|
|
145
|
+
change is now saved per-guild, and restored at startup (and automatically
|
|
146
|
+
for any new guild the bot joins) - see `docs/STATE.md`.
|
|
147
|
+
- Fixed a related bug in `BasicSecurityLayer`: its spam-rate buffer was
|
|
148
|
+
keyed by `userId` alone, so the same user active in two different
|
|
149
|
+
servers could incorrectly share one rate-limit window. Now keyed by
|
|
150
|
+
`guildId:userId`.
|
|
151
|
+
|
|
152
|
+
### Migrating from 1.x
|
|
153
|
+
|
|
154
|
+
**If you only use the built-in control panel and `!gf` commands, nothing in
|
|
155
|
+
your bot's code needs to change** - update the package and you're done; the
|
|
156
|
+
panel and commands already operate within a specific server, they just
|
|
157
|
+
didn't respect that internally before now.
|
|
158
|
+
|
|
159
|
+
**If your own code calls these directly, update the call sites:**
|
|
160
|
+
|
|
161
|
+
| 1.x | 2.0.0 |
|
|
162
|
+
|---|---|
|
|
163
|
+
| `frame.enableLayer(name)` | `frame.enableLayer(name, guildId)` |
|
|
164
|
+
| `frame.disableLayer(name)` | `frame.disableLayer(name, guildId)` |
|
|
165
|
+
| `frame.whitelist.add(userId)` | `frame.addToWhitelist(guildId, userId)` |
|
|
166
|
+
| `frame.whitelist.delete(userId)` | `frame.removeFromWhitelist(guildId, userId)` |
|
|
167
|
+
| `frame.whitelist.has(userId)` | `frame.isWhitelisted(guildId, userId)` |
|
|
168
|
+
| `layer.enabled` | `layer.isEnabled(guildId)` |
|
|
169
|
+
|
|
170
|
+
`options.autoStart` in the constructor is unchanged - still a plain array
|
|
171
|
+
of layer names - but now correctly applies per-guild (to every guild the
|
|
172
|
+
bot is already in, and automatically to any new one it joins) instead of
|
|
173
|
+
turning a layer on everywhere at once.
|
|
174
|
+
|
|
175
|
+
### Added
|
|
176
|
+
|
|
177
|
+
- `frame.ready` - a Promise that resolves once every guild the bot was
|
|
178
|
+
already in at construction time has finished restoring its saved state.
|
|
179
|
+
State restoration is async (a real `stateStore` may hit disk/a database),
|
|
180
|
+
so this exists for anyone who wants an explicit guarantee rather than
|
|
181
|
+
relying on the fact that, in practice, it resolves faster than any
|
|
182
|
+
Discord event could arrive.
|
|
183
|
+
- `frame.getGuildMetrics(guildId)` - one server's layer status, whitelist
|
|
184
|
+
size, open-case count, and flagged-member count.
|
|
185
|
+
- `!gf metrics` now shows **this server's** numbers by default instead of
|
|
186
|
+
bot-wide totals, with one button on the message to switch to the global
|
|
187
|
+
(all-servers) view and back. This is a second button, separate from the
|
|
188
|
+
5-button panel - the panel is still exactly 5 buttons; the metrics
|
|
189
|
+
command now has 1 of its own.
|
|
190
|
+
- `ProtocolCache.countByPrefix(prefix)` - powers the per-guild counts above
|
|
191
|
+
by counting non-expired `guildId:userId`-keyed entries for one guild.
|
|
192
|
+
- `docs/STATE.md` - the per-guild state and persistence model in full.
|
|
193
|
+
|
|
194
|
+
## [1.2.1] - 2026-07-31
|
|
195
|
+
|
|
196
|
+
### Added
|
|
197
|
+
|
|
198
|
+
- `homepage` and `discord` fields in `package.json` linking to the docs site
|
|
199
|
+
and the support server.
|
|
200
|
+
|
|
17
201
|
## [1.2.0] - 2026-07-31
|
|
18
202
|
|
|
19
203
|
Packaging and licensing changes to make this publishable to npm. No
|
package/GETTING_STARTED.md
CHANGED
|
@@ -79,9 +79,10 @@ toggle gets reported there through Components V2 messages.
|
|
|
79
79
|
|
|
80
80
|
Two ways, pick either or both:
|
|
81
81
|
|
|
82
|
-
- **Code**: list layer names in `autoStart` (see Step 2)
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
- **Code**: list layer names in `autoStart` (see Step 2) - applies to every
|
|
83
|
+
server by default - or call
|
|
84
|
+
`frame.enableLayer("antiNuke", guildId)` / `frame.disableLayer("antiNuke", guildId)`
|
|
85
|
+
for one specific server anywhere after construction.
|
|
85
86
|
- **In Discord**: an admin (Manage Server permission) sends `!gf panel` and
|
|
86
87
|
gets 5 buttons - Activate/Deactivate AntiRaid, AI Moderation, AntiNuke,
|
|
87
88
|
Basic Security, and Full Protocol (all four at once). This is the only
|
|
@@ -119,13 +120,31 @@ Nobody needs this guide again after setup. Server admins use:
|
|
|
119
120
|
| `!gf scan` | Checks current roles for name/permission mismatches |
|
|
120
121
|
| `!gf metrics` | Performance and cache health |
|
|
121
122
|
| `!gf phishing add/remove/list <domain>` | Manage the link blocklist |
|
|
122
|
-
| `!gf whitelist add/remove <userId>` | Exempt a user from punitive action |
|
|
123
|
+
| `!gf whitelist add/remove <userId>` | Exempt a user from punitive action in this server |
|
|
123
124
|
| `!gf help` | Lists all of the above |
|
|
124
125
|
|
|
126
|
+
## Step 6 (optional) - Your own bot-wide dashboard
|
|
127
|
+
|
|
128
|
+
If you run the bot yourself, `!gf engine` gives you a cross-server view
|
|
129
|
+
(busiest server, AI usage, a live activity feed) that regular server admins
|
|
130
|
+
can't see:
|
|
131
|
+
|
|
132
|
+
```js
|
|
133
|
+
const frame = new GlassFrame(client, {
|
|
134
|
+
getLogChannel: /* ... */,
|
|
135
|
+
owners: ["your-discord-user-id"]
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
See `docs/ENGINE.md` for the optional password/lockout system and what
|
|
140
|
+
each of its 5 pages shows.
|
|
141
|
+
|
|
125
142
|
## Going deeper
|
|
126
143
|
|
|
127
144
|
- `README.md` - full feature overview
|
|
128
145
|
- `docs/PROTOCOL_LAYERS.md` - how a signal becomes an action
|
|
146
|
+
- `docs/STATE.md` - per-server layer/whitelist state and persistence
|
|
147
|
+
- `docs/ENGINE.md` - the owner-only bot-wide dashboard
|
|
129
148
|
- `docs/CACHE_ARCHITECTURE.md` - every internal cache and its TTL
|
|
130
149
|
- `docs/PERFORMANCE.md` - the bounded-concurrency queues and `!gf metrics`
|
|
131
150
|
- `docs/COMMANDS.md` - full command/button reference
|
package/README.md
CHANGED
|
@@ -7,18 +7,23 @@ pipeline instead of each reacting on its own, so the same member never gets
|
|
|
7
7
|
hit by four different modules for one incident, and a single soft flag
|
|
8
8
|
never turns into an auto-ban.
|
|
9
9
|
|
|
10
|
+
Everything is per-server: one bot process can run GlassFrame across many
|
|
11
|
+
Discord servers, each with its own independent set of active layers and its
|
|
12
|
+
own whitelist, persisted across restarts. See `docs/STATE.md`.
|
|
13
|
+
|
|
10
14
|
No slash commands - prefix commands only. No legacy `EmbedBuilder` - every
|
|
11
15
|
log message renders through Discord's Components V2 system. No emoji
|
|
12
16
|
anywhere in code or output.
|
|
13
17
|
|
|
14
18
|
## Install
|
|
15
19
|
|
|
16
|
-
Copy the `glassframe-protocol` folder into your bot project, then:
|
|
17
|
-
|
|
18
20
|
```
|
|
19
|
-
npm install
|
|
21
|
+
npm install glassframe-protocol
|
|
20
22
|
```
|
|
21
23
|
|
|
24
|
+
Or copy the `glassframe-protocol` folder directly into your bot project and
|
|
25
|
+
`npm install` inside it - either works the same way.
|
|
26
|
+
|
|
22
27
|
Requires `discord.js` v14.16+ (Components V2 support and the
|
|
23
28
|
`guildAuditLogEntryCreate` event) and Node.js 18+ (global `fetch`, used only
|
|
24
29
|
by the optional AI layer).
|
|
@@ -56,8 +61,8 @@ client.once("ready", () => {
|
|
|
56
61
|
const frame = new GlassFrame(client, {
|
|
57
62
|
getLogChannel: async (guild) =>
|
|
58
63
|
guild.channels.cache.find((c) => c.name === "security-logs") ?? null,
|
|
59
|
-
whitelist: ["123456789012345678"],
|
|
60
|
-
autoStart: ["basicSecurity"], // layers
|
|
64
|
+
whitelist: ["123456789012345678"], // trusted everywhere, seeded into every guild on first run
|
|
65
|
+
autoStart: ["basicSecurity"], // starting layers for every guild - not a global on/off
|
|
61
66
|
config: {
|
|
62
67
|
antiRaid: { joinThreshold: 8 },
|
|
63
68
|
aiModeration: { apiKeys: [process.env.GROQ_KEY_1, process.env.GROQ_KEY_2].filter(Boolean) }
|
|
@@ -75,8 +80,10 @@ the 5-button control panel and arm layers from there instead of in code.
|
|
|
75
80
|
|
|
76
81
|
## The four layers
|
|
77
82
|
|
|
78
|
-
- **Basic Security** - spam rate, duplicate flood, mention spam,
|
|
79
|
-
|
|
83
|
+
- **Basic Security** - spam rate, duplicate flood, mention spam, a
|
|
84
|
+
dedicated trust-aware @everyone/@here guard, local NLP scam/phishing/
|
|
85
|
+
raid-recruitment scoring (including a specific invite-link +
|
|
86
|
+
raid-language combo check), and link checks via `PhishingDatabase` (a
|
|
80
87
|
server-editable blocklist plus raw-IP/punycode/brand-look-alike/shortener
|
|
81
88
|
heuristics - `!gf phishing add/remove/list`).
|
|
82
89
|
- **AntiRaid** - join-velocity lockdown with automatic verification-level
|
|
@@ -85,30 +92,36 @@ the 5-button control panel and arm layers from there instead of in code.
|
|
|
85
92
|
catches a raid trickling in too slowly to trip the rate counter.
|
|
86
93
|
- **AntiNuke** - audit-log burst detection across channels, roles, bans,
|
|
87
94
|
kicks, webhooks, emoji, and stickers per executor; a dangerous
|
|
88
|
-
permission-grant watchdog
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
(
|
|
92
|
-
|
|
93
|
-
|
|
95
|
+
permission-grant watchdog covering both a role's own permissions
|
|
96
|
+
changing *and* a member being quietly handed an already-dangerous role
|
|
97
|
+
(with optional auto-revert); a channel permission-overwrite watchdog
|
|
98
|
+
(catches @everyone getting locked out of, or let into, a channel without
|
|
99
|
+
anything being deleted); a server-identity watchdog (name/icon/vanity URL
|
|
100
|
+
changes); an invite-abuse watchdog (unrestricted invites from non-staff);
|
|
101
|
+
and webhook-flood containment (deletes an abusive webhook and traces it
|
|
102
|
+
back to its creator, since webhook messages carry no guild member for
|
|
103
|
+
other layers to see).
|
|
94
104
|
- **AI Moderation** (optional, off by default) - Groq-powered second opinion
|
|
95
105
|
for messages the local NLP scores as "gray zone": not clean, not clearly
|
|
96
106
|
over threshold. Supports a pool of API keys with automatic per-key
|
|
97
107
|
cooldown on rate limits. See `config.aiModeration` and
|
|
98
108
|
`docs/CACHE_ARCHITECTURE.md` for how verdicts get cached and keys rotated.
|
|
99
109
|
|
|
100
|
-
Every layer starts disabled. Nothing runs until you list it in
|
|
101
|
-
`autoStart`, call `frame.enableLayer(name)`, or arm it from the
|
|
102
|
-
panel.
|
|
110
|
+
Every layer starts disabled, per guild. Nothing runs until you list it in
|
|
111
|
+
`autoStart`, call `frame.enableLayer(name, guildId)`, or arm it from the
|
|
112
|
+
control panel. Add your own layer alongside these four with
|
|
113
|
+
`frame.registerLayer()` - see "Extending it" below.
|
|
103
114
|
|
|
104
115
|
## Performance under load
|
|
105
116
|
|
|
106
117
|
Every Discord mutation `PunishmentEngine` performs and every outbound Groq
|
|
107
118
|
request go through a bounded-concurrency queue (`frame.actionQueue` /
|
|
108
119
|
`frame.aiQueue`) instead of firing unbounded, so a burst can't trip a rate
|
|
109
|
-
limit by hammering it all at once.
|
|
110
|
-
|
|
111
|
-
|
|
120
|
+
limit by hammering it all at once. `!gf metrics` shows this server's numbers
|
|
121
|
+
by default (open cases, flagged members, active layers), with a button on
|
|
122
|
+
the message to switch to bot-wide totals across every server
|
|
123
|
+
(`frame.getMetrics()` / `frame.getGuildMetrics(guildId)`). Full write-up in
|
|
124
|
+
`docs/PERFORMANCE.md`.
|
|
112
125
|
|
|
113
126
|
## How punishment works
|
|
114
127
|
|
|
@@ -121,15 +134,37 @@ for human review, never auto-banned), and only if there isn't already an
|
|
|
121
134
|
open case for that member from a moment ago. Full write-up in
|
|
122
135
|
`docs/PROTOCOL_LAYERS.md`.
|
|
123
136
|
|
|
137
|
+
## Extending it
|
|
138
|
+
|
|
139
|
+
- **`frame.registerLayer(name, layerInstance)`** - add your own security
|
|
140
|
+
layer to the same pipeline the built-in four use (per-guild enable/state/
|
|
141
|
+
persistence come free from extending `core/Layer`). Doesn't get a button
|
|
142
|
+
on the panel automatically - the panel stays fixed at exactly 5.
|
|
143
|
+
- **`frame.registerAction(name, handler)`** - add a custom punishment
|
|
144
|
+
action beyond ban/kick/timeout/quarantine, referenceable from
|
|
145
|
+
`config.punishment.ladder`.
|
|
146
|
+
- **`!gf prefix set <newPrefix>`** - each server can run its own prefix;
|
|
147
|
+
`config.prefix` always still works everywhere as a fallback.
|
|
148
|
+
- **`getLogChannel(guild, layerName)`** - route different layers to
|
|
149
|
+
different channels, if you want; the second parameter is optional and
|
|
150
|
+
backward compatible.
|
|
151
|
+
- **`!gf engine`** - an owner-only, bot-wide dashboard (busiest server, AI
|
|
152
|
+
usage, live cross-server activity feed), gated separately from every
|
|
153
|
+
other command and not listed in `!gf help`. See `docs/ENGINE.md`.
|
|
154
|
+
|
|
124
155
|
## Docs
|
|
125
156
|
|
|
126
157
|
- `GETTING_STARTED.md` - adding GlassFrame to a bot you already have running.
|
|
127
158
|
- `docs/PROTOCOL_LAYERS.md` - full architecture: containment vs. punishment,
|
|
128
|
-
how a signal becomes an action,
|
|
159
|
+
how a signal becomes an action, `registerLayer`/`registerAction`.
|
|
160
|
+
- `docs/STATE.md` - per-guild layer/whitelist state and how persistence
|
|
161
|
+
across restarts works.
|
|
129
162
|
- `docs/CACHE_ARCHITECTURE.md` - every cache in the library, its key shape,
|
|
130
163
|
its TTL, and how to turn on cache-level debug logging.
|
|
131
164
|
- `docs/PERFORMANCE.md` - the bounded-concurrency queues and internal
|
|
132
165
|
metrics collector, and what `!gf metrics` shows.
|
|
166
|
+
- `docs/ENGINE.md` - the owner-only bot-wide dashboard: the password/lockout
|
|
167
|
+
system and what each of its 5 pages shows.
|
|
133
168
|
- `docs/COMMANDS.md` - the full prefix command reference and the control
|
|
134
169
|
panel's five buttons.
|
|
135
170
|
- `docs/PUBLISHING.md` - publishing this package to npm, and what actually
|
package/dist/config.js
CHANGED
|
@@ -44,7 +44,7 @@ module.exports = {
|
|
|
44
44
|
basicSecurity: {
|
|
45
45
|
spam: { windowMs: 6000, messageThreshold: 6, duplicateThreshold: 4 },
|
|
46
46
|
mentionSpam: { maxMentionsPerMessage: 8 },
|
|
47
|
-
nlp: { scamScoreThreshold: 0.62, phishingScoreThreshold: 0.55 },
|
|
47
|
+
nlp: { scamScoreThreshold: 0.62, phishingScoreThreshold: 0.55, raidCalloutThreshold: 0.3 },
|
|
48
48
|
// Seed domains for PhishingDatabase (src/security/PhishingDatabase.js).
|
|
49
49
|
// Empty by default - populate with what you actually see via
|
|
50
50
|
// `!gf phishing add <domain>` rather than shipping unverified blocklists.
|
|
@@ -83,6 +83,10 @@ module.exports = {
|
|
|
83
83
|
// A brand-new invite with no expiry and no use limit, created by anyone
|
|
84
84
|
// other than the owner, is worth a look the moment it's created.
|
|
85
85
|
watchInviteAbuse: true,
|
|
86
|
+
// Watches @everyone's channel permission overwrites specifically - a
|
|
87
|
+
// channel getting locked out for everyone, or a private channel getting
|
|
88
|
+
// opened to everyone, is a nuke technique that doesn't delete anything.
|
|
89
|
+
watchOverwriteAbuse: true,
|
|
86
90
|
// A webhook that starts pushing a burst of messages within minutes of
|
|
87
91
|
// being created is a classic "nuke via webhook" pattern - this catches
|
|
88
92
|
// it even though the messages themselves look like normal messageCreate
|
|
@@ -134,5 +138,20 @@ module.exports = {
|
|
|
134
138
|
// Default for GlassFrame's debug flag - logs every cache SET/HIT/MISS/EXPIRE to the console.
|
|
135
139
|
// See docs/CACHE_ARCHITECTURE.md. Overridden by the `debug` constructor option if provided.
|
|
136
140
|
debug: false
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
// The owner-only `!gf engine` dashboard - see docs/ENGINE.md. Being an
|
|
144
|
+
// owner (options.owners) is required no matter what; a password is an
|
|
145
|
+
// optional second factor on top of that for the initial command only -
|
|
146
|
+
// page-navigation button clicks are still gated by isOwner() but don't
|
|
147
|
+
// re-prompt for the password.
|
|
148
|
+
engine: {
|
|
149
|
+
// Set via an environment variable in your own bot, e.g.
|
|
150
|
+
// process.env.GLASSFRAME_ENGINE_PASSWORD - never hardcode a real
|
|
151
|
+
// password into a committed config.js. Leave null to skip the second
|
|
152
|
+
// factor and rely on the owners list alone.
|
|
153
|
+
password: null,
|
|
154
|
+
maxAttempts: 3,
|
|
155
|
+
lockoutMs: 1000 * 60 * 10
|
|
137
156
|
}
|
|
138
157
|
};
|