@gfargo/doorman 3.14.0 → 3.14.2
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/bin/run.js +47 -47
- package/dist/bin/run.mjs +47 -47
- package/package.json +1 -1
- package/skills/doorman/SKILL.md +27 -3
- package/skills/doorman/references/cloudflare.md +105 -53
- package/skills/doorman/references/fastly.md +1 -1
- package/skills/doorman/references/gcp.md +184 -0
- package/skills/doorman/references/rules.md +87 -73
- package/skills/doorman/references/templates.md +15 -4
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Complete reference for creating and configuring Doorman firewall rules.
|
|
4
4
|
|
|
5
|
+
> **Format note:** this reference covers the **legacy (Vercel-only) rule format** — no `provider`/`providers` field in the config. If your config has `provider`/`providers` set (required for Cloudflare/Fastly), rules use a different shape entirely (`conditions`/`enabled`/flat `action: {type}` instead of `conditionGroup`/`active`/`action: {mitigate}`) — see [cloudflare.md](cloudflare.md)/[fastly.md](fastly.md) for the correct format and field/operator/action support per provider, and `SKILL.md`'s "Rule Shape" section for a side-by-side comparison.
|
|
6
|
+
|
|
5
7
|
## Rule Structure
|
|
6
8
|
|
|
7
9
|
Every rule in the `rules` array has this shape:
|
|
@@ -13,8 +15,16 @@ Every rule in the `rules` array has this shape:
|
|
|
13
15
|
"description": "What this rule does and why",
|
|
14
16
|
"active": true,
|
|
15
17
|
"conditionGroup": [
|
|
16
|
-
{
|
|
17
|
-
|
|
18
|
+
{
|
|
19
|
+
"conditions": [
|
|
20
|
+
/* AND — all must match */
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"conditions": [
|
|
25
|
+
/* OR — this group is an alternative */
|
|
26
|
+
]
|
|
27
|
+
}
|
|
18
28
|
],
|
|
19
29
|
"action": { "mitigate": { "action": "deny" } }
|
|
20
30
|
}
|
|
@@ -22,14 +32,14 @@ Every rule in the `rules` array has this shape:
|
|
|
22
32
|
|
|
23
33
|
### Fields
|
|
24
34
|
|
|
25
|
-
| Field
|
|
26
|
-
|
|
27
|
-
| `id`
|
|
28
|
-
| `name`
|
|
29
|
-
| `description`
|
|
30
|
-
| `active`
|
|
31
|
-
| `conditionGroup` | array
|
|
32
|
-
| `action`
|
|
35
|
+
| Field | Type | Required | Description |
|
|
36
|
+
| ---------------- | ------- | -------- | ------------------------------------------------------------------------------------- |
|
|
37
|
+
| `id` | string | No | Unique identifier. Convention: `rule_` prefix, snake_case. Auto-generated if omitted. |
|
|
38
|
+
| `name` | string | Yes | Display name shown in tables and logs. |
|
|
39
|
+
| `description` | string | No | Explains the rule's purpose. Improves health score. |
|
|
40
|
+
| `active` | boolean | Yes | `true` to enforce, `false` to disable without deleting. |
|
|
41
|
+
| `conditionGroup` | array | Yes | Array of condition groups (see below). |
|
|
42
|
+
| `action` | object | Yes | What to do when conditions match (see below). |
|
|
33
43
|
|
|
34
44
|
## Condition Groups
|
|
35
45
|
|
|
@@ -41,6 +51,7 @@ Every rule in the `rules` array has this shape:
|
|
|
41
51
|
```
|
|
42
52
|
|
|
43
53
|
**Logic**:
|
|
54
|
+
|
|
44
55
|
- Conditions **within** a group: AND (all must match)
|
|
45
56
|
- **Between** groups: OR (any group matching triggers the rule)
|
|
46
57
|
|
|
@@ -52,35 +63,36 @@ Each condition has:
|
|
|
52
63
|
{ "type": "field_type", "op": "operator", "value": "match_value", "key": "header_name", "neg": false }
|
|
53
64
|
```
|
|
54
65
|
|
|
55
|
-
| Field
|
|
56
|
-
|
|
57
|
-
| `type`
|
|
58
|
-
| `op`
|
|
59
|
-
| `value` | string/number/array | Yes
|
|
60
|
-
| `key`
|
|
61
|
-
| `neg`
|
|
66
|
+
| Field | Type | Required | Description |
|
|
67
|
+
| ------- | ------------------- | -------- | ------------------------------------------------------------- |
|
|
68
|
+
| `type` | string | Yes | What to match against (see types below). |
|
|
69
|
+
| `op` | string | Yes | How to compare (see operators below). |
|
|
70
|
+
| `value` | string/number/array | Yes | Value to match. Arrays for `inc` operator. |
|
|
71
|
+
| `key` | string | No | Required for `header`, `query`, `cookie` types. |
|
|
72
|
+
| `neg` | boolean | No | `true` to negate the condition (NOT logic). Default: `false`. |
|
|
62
73
|
|
|
63
74
|
### Condition Types
|
|
64
75
|
|
|
65
|
-
| Type
|
|
66
|
-
|
|
67
|
-
| `path`
|
|
68
|
-
| `method`
|
|
69
|
-
| `host`
|
|
70
|
-
| `user_agent`
|
|
71
|
-
| `ip_address`
|
|
72
|
-
| `header`
|
|
73
|
-
| `query`
|
|
74
|
-
| `cookie`
|
|
75
|
-
| `geo_country`
|
|
76
|
-
| `geo_city`
|
|
77
|
-
| `geo_continent`
|
|
78
|
-
| `geo_country_region` | Region/state code
|
|
79
|
-
| `geo_as_number`
|
|
80
|
-
| `scheme`
|
|
81
|
-
| `protocol`
|
|
76
|
+
| Type | Description | Example Value |
|
|
77
|
+
| -------------------- | -------------------------------- | ----------------------- |
|
|
78
|
+
| `path` | URL path | `"/api/users"` |
|
|
79
|
+
| `method` | HTTP method | `"POST"` |
|
|
80
|
+
| `host` | Hostname | `"example.com"` |
|
|
81
|
+
| `user_agent` | User-Agent header | `"Googlebot"` |
|
|
82
|
+
| `ip_address` | Client IP | `"192.168.1.1"` |
|
|
83
|
+
| `header` | HTTP header (requires `key`) | `"application/json"` |
|
|
84
|
+
| `query` | Query parameter (requires `key`) | `"true"` |
|
|
85
|
+
| `cookie` | Cookie value (requires `key`) | `"session_abc"` |
|
|
86
|
+
| `geo_country` | Country code (ISO 3166-1) | `"US"` or `["US","CA"]` |
|
|
87
|
+
| `geo_city` | City name | `"New York"` |
|
|
88
|
+
| `geo_continent` | Continent code | `"NA"` |
|
|
89
|
+
| `geo_country_region` | Region/state code | `"CA"` |
|
|
90
|
+
| `geo_as_number` | ASN number | `13335` |
|
|
91
|
+
| `scheme` | URL scheme | `"https"` |
|
|
92
|
+
| `protocol` | HTTP protocol version | `"HTTP/2"` |
|
|
82
93
|
|
|
83
94
|
**Vercel-only types** (not available on Cloudflare):
|
|
95
|
+
|
|
84
96
|
- `environment` — deployment environment (`"production"`, `"preview"`)
|
|
85
97
|
- `ja3_digest` — TLS fingerprint
|
|
86
98
|
- `ja4_digest` — TLS fingerprint v4
|
|
@@ -89,16 +101,16 @@ Each condition has:
|
|
|
89
101
|
|
|
90
102
|
### Operators
|
|
91
103
|
|
|
92
|
-
| Operator | Name
|
|
93
|
-
|
|
94
|
-
| `eq`
|
|
95
|
-
| `pre`
|
|
96
|
-
| `suf`
|
|
97
|
-
| `sub`
|
|
98
|
-
| `inc`
|
|
99
|
-
| `re`
|
|
100
|
-
| `ex`
|
|
101
|
-
| `nex`
|
|
104
|
+
| Operator | Name | Description | Value Type |
|
|
105
|
+
| -------- | ---------- | --------------------------- | ---------------------- |
|
|
106
|
+
| `eq` | Equals | Exact match | string/number |
|
|
107
|
+
| `pre` | Prefix | Starts with | string |
|
|
108
|
+
| `suf` | Suffix | Ends with | string |
|
|
109
|
+
| `sub` | Substring | Contains | string |
|
|
110
|
+
| `inc` | Includes | Is any of (array match) | string[] |
|
|
111
|
+
| `re` | Regex | Regular expression match | string (regex pattern) |
|
|
112
|
+
| `ex` | Exists | Field/header exists | `true` |
|
|
113
|
+
| `nex` | Not Exists | Field/header does not exist | `true` |
|
|
102
114
|
|
|
103
115
|
### Using `key` for Header/Query/Cookie
|
|
104
116
|
|
|
@@ -154,13 +166,13 @@ Duration formats: `"30s"`, `"5m"`, `"1h"`, `"1d"`, `"permanent"`
|
|
|
154
166
|
}
|
|
155
167
|
```
|
|
156
168
|
|
|
157
|
-
| Field
|
|
158
|
-
|
|
159
|
-
| `requests`
|
|
160
|
-
| `window`
|
|
161
|
-
| `characteristics`
|
|
162
|
-
| `mitigationTimeout`
|
|
163
|
-
| `countingExpression` | string
|
|
169
|
+
| Field | Type | Required | Description |
|
|
170
|
+
| -------------------- | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
171
|
+
| `requests` | number | Yes | Max requests allowed in window. |
|
|
172
|
+
| `window` | string | Yes | Time window: `"10s"`, `"1m"`, `"5m"`, `"1h"` |
|
|
173
|
+
| `characteristics` | string[] | No | What to rate limit by. Default: `["ip.src"]`. Options: `"ip.src"`, `"http.request.uri.path"`, `"http.request.headers[\"user-agent\"]"` |
|
|
174
|
+
| `mitigationTimeout` | number | No | How long (seconds) to block after limit exceeded. Default: 3600. |
|
|
175
|
+
| `countingExpression` | string | No | Cloudflare-specific: expression for what counts toward the limit. |
|
|
164
176
|
|
|
165
177
|
### Redirect
|
|
166
178
|
|
|
@@ -175,10 +187,10 @@ Duration formats: `"30s"`, `"5m"`, `"1h"`, `"1d"`, `"permanent"`
|
|
|
175
187
|
}
|
|
176
188
|
```
|
|
177
189
|
|
|
178
|
-
| Field
|
|
179
|
-
|
|
180
|
-
| `location`
|
|
181
|
-
| `permanent` | boolean | `true` for 301, `false` for 302.
|
|
190
|
+
| Field | Type | Description |
|
|
191
|
+
| ----------- | ------- | ----------------------------------------- |
|
|
192
|
+
| `location` | string | Redirect URL (absolute or relative path). |
|
|
193
|
+
| `permanent` | boolean | `true` for 301, `false` for 302. |
|
|
182
194
|
|
|
183
195
|
### Log Only
|
|
184
196
|
|
|
@@ -210,13 +222,13 @@ IP rules go in the `ips` array, separate from `rules`:
|
|
|
210
222
|
}
|
|
211
223
|
```
|
|
212
224
|
|
|
213
|
-
| Field
|
|
214
|
-
|
|
215
|
-
| `id`
|
|
216
|
-
| `ip`
|
|
217
|
-
| `hostname` | string | No
|
|
218
|
-
| `action`
|
|
219
|
-
| `notes`
|
|
225
|
+
| Field | Type | Required | Description |
|
|
226
|
+
| ---------- | ------ | -------- | --------------------------------------------------- |
|
|
227
|
+
| `id` | string | No | Unique identifier. |
|
|
228
|
+
| `ip` | string | Yes | IP address or CIDR range. Use `/32` for single IPs. |
|
|
229
|
+
| `hostname` | string | No | Associated hostname (documentation only). |
|
|
230
|
+
| `action` | string | Yes | `"deny"` (only supported value currently). |
|
|
231
|
+
| `notes` | string | No | Why this IP was blocked. |
|
|
220
232
|
|
|
221
233
|
### CIDR Notation
|
|
222
234
|
|
|
@@ -262,10 +274,12 @@ IP rules go in the `ips` array, separate from `rules`:
|
|
|
262
274
|
"name": "Rate Limit POST to API",
|
|
263
275
|
"active": true,
|
|
264
276
|
"conditionGroup": [
|
|
265
|
-
{
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
277
|
+
{
|
|
278
|
+
"conditions": [
|
|
279
|
+
{ "type": "path", "op": "pre", "value": "/api/" },
|
|
280
|
+
{ "type": "method", "op": "eq", "value": "POST" }
|
|
281
|
+
]
|
|
282
|
+
}
|
|
269
283
|
],
|
|
270
284
|
"action": {
|
|
271
285
|
"mitigate": {
|
|
@@ -284,10 +298,12 @@ IP rules go in the `ips` array, separate from `rules`:
|
|
|
284
298
|
"name": "Block Missing API Key",
|
|
285
299
|
"active": true,
|
|
286
300
|
"conditionGroup": [
|
|
287
|
-
{
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
301
|
+
{
|
|
302
|
+
"conditions": [
|
|
303
|
+
{ "type": "path", "op": "pre", "value": "/api/" },
|
|
304
|
+
{ "type": "header", "op": "nex", "value": true, "key": "X-API-Key" }
|
|
305
|
+
]
|
|
306
|
+
}
|
|
291
307
|
],
|
|
292
308
|
"action": { "mitigate": { "action": "deny" } }
|
|
293
309
|
}
|
|
@@ -327,9 +343,7 @@ IP rules go in the `ips` array, separate from `rules`:
|
|
|
327
343
|
{
|
|
328
344
|
"name": "Redirect Legacy API",
|
|
329
345
|
"active": true,
|
|
330
|
-
"conditionGroup": [
|
|
331
|
-
{ "conditions": [{ "type": "path", "op": "pre", "value": "/v1/api/" }] }
|
|
332
|
-
],
|
|
346
|
+
"conditionGroup": [{ "conditions": [{ "type": "path", "op": "pre", "value": "/v1/api/" }] }],
|
|
333
347
|
"action": {
|
|
334
348
|
"mitigate": {
|
|
335
349
|
"action": "redirect",
|
|
@@ -27,6 +27,7 @@ doorman template ai-bots
|
|
|
27
27
|
Detected bots include: GPTBot, ChatGPT-User, ClaudeBot, Claude-Web, Bytespider, CCBot, Google-Extended, GoogleOther, Amazonbot, Applebot-Extended, Meta-ExternalAgent, PerplexityBot, OAI-SearchBot, Diffbot, anthropic-ai, cohere-ai, and many more.
|
|
28
28
|
|
|
29
29
|
**Rule added:**
|
|
30
|
+
|
|
30
31
|
```json
|
|
31
32
|
{
|
|
32
33
|
"id": "rule_detect_ai_bots",
|
|
@@ -58,6 +59,7 @@ doorman template bad-bots
|
|
|
58
59
|
Includes: scrapers (HTTrack, WebCopier, SiteRipper), vulnerability scanners (Nikto, Nmap, Acunetix, SQLmap, WPScan, Nuclei), SEO crawlers (AhrefsBot, SemrushBot, MJ12bot, DotBot), and spam/attack tools (Zeus, Havij, Dirbuster).
|
|
59
60
|
|
|
60
61
|
**Rule added:**
|
|
62
|
+
|
|
61
63
|
```json
|
|
62
64
|
{
|
|
63
65
|
"id": "rule_detect_bad_bots",
|
|
@@ -87,6 +89,7 @@ doorman template block-ofac-sanctioned-countries
|
|
|
87
89
|
Countries blocked: Syria (SY), Iran (IR), Russia (RU), Cuba (CU), North Korea (KP).
|
|
88
90
|
|
|
89
91
|
**Rule added:**
|
|
92
|
+
|
|
90
93
|
```json
|
|
91
94
|
{
|
|
92
95
|
"id": "rule_block_traffic_from_ofac_sanctioned_countries",
|
|
@@ -117,18 +120,28 @@ doorman template wordpress
|
|
|
117
120
|
Paths blocked: `/wp-admin`, `/wp-login.php`, `/xmlrpc.php`, `/wp-content`, `/wp-includes`, `/wp-signup.php`, `/wp-activate.php`, `/register.php`, `/wp-register.php`
|
|
118
121
|
|
|
119
122
|
**Rule added:**
|
|
123
|
+
|
|
120
124
|
```json
|
|
121
125
|
{
|
|
122
126
|
"name": "Deny WordPress URLs",
|
|
123
127
|
"active": true,
|
|
124
128
|
"conditionGroup": [
|
|
125
|
-
{
|
|
129
|
+
{
|
|
130
|
+
"conditions": [
|
|
131
|
+
{
|
|
132
|
+
"type": "path",
|
|
133
|
+
"op": "re",
|
|
134
|
+
"value": "/(wp-admin|wp-login\\.php|xmlrpc\\.php|wp-content|wp-includes|wp-signup\\.php|wp-activate\\.php|register\\.php|wp-register\\.php)"
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
}
|
|
126
138
|
],
|
|
127
139
|
"action": { "mitigate": { "action": "deny" } }
|
|
128
140
|
}
|
|
129
141
|
```
|
|
130
142
|
|
|
131
143
|
**Note**: Uses regex — for Cloudflare non-Enterprise, split into multiple `pre` (prefix) conditions:
|
|
144
|
+
|
|
132
145
|
```json
|
|
133
146
|
"conditionGroup": [
|
|
134
147
|
{ "conditions": [{ "type": "path", "op": "pre", "value": "/wp-admin" }] },
|
|
@@ -157,9 +170,7 @@ export const myTemplate: Template = {
|
|
|
157
170
|
name: 'My Rule',
|
|
158
171
|
description: 'What it does',
|
|
159
172
|
active: true,
|
|
160
|
-
conditionGroup: [
|
|
161
|
-
{ conditions: [{ type: 'path', op: 'pre', value: '/protected' }] }
|
|
162
|
-
],
|
|
173
|
+
conditionGroup: [{ conditions: [{ type: 'path', op: 'pre', value: '/protected' }] }],
|
|
163
174
|
action: { mitigate: { action: 'deny' } },
|
|
164
175
|
},
|
|
165
176
|
],
|