@osqd/bothandlerjs 0.6.0 → 0.7.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.
Files changed (84) hide show
  1. package/CHANGELOG.md +227 -1
  2. package/README.md +18 -10
  3. package/dist/adapters/fastify.d.ts +10 -0
  4. package/dist/adapters/index.cjs +38 -13
  5. package/dist/adapters/index.cjs.map +1 -1
  6. package/dist/adapters/index.js +38 -13
  7. package/dist/adapters/index.js.map +1 -1
  8. package/dist/challenge/index.d.ts +40 -0
  9. package/dist/cli.cjs +1783 -83
  10. package/dist/cli.cjs.map +1 -1
  11. package/dist/cli.js +1783 -83
  12. package/dist/cli.js.map +1 -1
  13. package/dist/config.d.ts +55 -0
  14. package/dist/core.d.ts +33 -21
  15. package/dist/corpus/index.cjs +282 -8
  16. package/dist/corpus/index.cjs.map +1 -1
  17. package/dist/corpus/index.js +282 -8
  18. package/dist/corpus/index.js.map +1 -1
  19. package/dist/corpus/schema.d.ts +25 -0
  20. package/dist/dashboard/client/actions.d.ts +1 -1
  21. package/dist/dashboard/client/app.d.ts +9 -2
  22. package/dist/dashboard/client/boot.d.ts +32 -3
  23. package/dist/dashboard/client/query.d.ts +72 -12
  24. package/dist/dashboard/client/registry.d.ts +25 -0
  25. package/dist/dashboard/client/saved.d.ts +29 -0
  26. package/dist/dashboard/client/store.d.ts +16 -2
  27. package/dist/dashboard/client/types.d.ts +2 -0
  28. package/dist/dashboard/client.generated.d.ts +1 -1
  29. package/dist/dashboard/types.d.ts +15 -0
  30. package/dist/detectors/blended-identity.d.ts +34 -0
  31. package/dist/detectors/challenge-integrity.d.ts +26 -0
  32. package/dist/detectors/challenge-reaction.d.ts +39 -0
  33. package/dist/detectors/clearance.d.ts +1 -23
  34. package/dist/detectors/index.d.ts +16 -1
  35. package/dist/detectors/marker.d.ts +106 -0
  36. package/dist/detectors/probe-signature.d.ts +27 -0
  37. package/dist/detectors/site-baseline.d.ts +135 -0
  38. package/dist/detectors/target-integrity.d.ts +16 -0
  39. package/dist/detectors/trap.d.ts +10 -3
  40. package/dist/detectors/types.d.ts +17 -0
  41. package/dist/element/index.cjs +726 -79
  42. package/dist/element/index.cjs.map +1 -1
  43. package/dist/element/index.js +726 -79
  44. package/dist/element/index.js.map +1 -1
  45. package/dist/index.cjs +1657 -125
  46. package/dist/index.cjs.map +1 -1
  47. package/dist/index.d.ts +4 -0
  48. package/dist/index.js +1643 -125
  49. package/dist/index.js.map +1 -1
  50. package/dist/internal/async.d.ts +0 -3
  51. package/dist/internal/ip.d.ts +18 -0
  52. package/dist/internal/text.d.ts +28 -0
  53. package/dist/metrics.d.ts +18 -0
  54. package/dist/probe/index.d.ts +153 -0
  55. package/dist/probe/marker.d.ts +119 -0
  56. package/dist/site/index.d.ts +122 -0
  57. package/dist/state.d.ts +130 -0
  58. package/dist/stores/redis.d.ts +24 -1
  59. package/dist/types.d.ts +70 -0
  60. package/docs/course/05-detectors.md +6 -5
  61. package/docs/course/06-identity.md +1 -1
  62. package/docs/course/16-proving-it.md +15 -9
  63. package/docs/course/index.md +1 -1
  64. package/docs/design/decisions.md +1 -1
  65. package/docs/detection/correlation.md +284 -0
  66. package/docs/detection/detectors.md +139 -3
  67. package/docs/detection/index.md +2 -1
  68. package/docs/detection/shadow-mode.md +147 -0
  69. package/docs/detection/signatures.md +1 -1
  70. package/docs/index.md +3 -2
  71. package/docs/integration/client-ip.md +16 -0
  72. package/docs/operations/dashboard.md +40 -1
  73. package/docs/operations/filters.md +143 -0
  74. package/docs/operations/index.md +1 -0
  75. package/docs/operations/metrics.md +18 -0
  76. package/docs/policy/presets.md +1 -1
  77. package/docs/start/choosing-a-policy.md +1 -1
  78. package/docs/start/first-integration.md +1 -1
  79. package/docs/start/installation.md +2 -2
  80. package/docs/testing/cli.md +7 -1
  81. package/docs/testing/corpus.md +12 -8
  82. package/docs/testing/index.md +1 -1
  83. package/docs/testing/try-it.md +1 -1
  84. package/package.json +4 -1
@@ -81,7 +81,7 @@ npx @osqd/bothandlerjs check --preset protect-content --audience human
81
81
  npx @osqd/bothandlerjs replay /var/log/nginx/access.log --preset protect-content
82
82
  ```
83
83
 
84
- The first is [526 shapes of real traffic](../testing/corpus.md); the second is *yours*. Both
84
+ The first is [548 shapes of real traffic](../testing/corpus.md); the second is *yours*. Both
85
85
  print every request the policy would have refused, with the evidence.
86
86
 
87
87
  For your own configuration rather than a preset:
@@ -61,7 +61,7 @@ npx @osqd/bothandlerjs check --preset protect-content
61
61
  npx @osqd/bothandlerjs replay /var/log/nginx/access.log --preset protect-content
62
62
  ```
63
63
 
64
- The first runs your policy against [526 shapes of real traffic](../testing/corpus.md); the
64
+ The first runs your policy against [548 shapes of real traffic](../testing/corpus.md); the
65
65
  second runs it against yours. Read the list of would-be-denied requests. If any of them is a
66
66
  person, the policy is wrong — and you found out from a log file.
67
67
 
@@ -16,7 +16,7 @@ The library imports nothing but `node:` builtins, and CI fails if that ever stop
16
16
  true. Nothing here can hand your project a transitive advisory, an install script, or a
17
17
  version conflict with something you already run.
18
18
 
19
- Redis, if you use it, is your client passed in: `RedisStore` describes the five commands it
19
+ Redis, if you use it, is your client passed in: `RedisStore` describes the four commands it
20
20
  needs structurally and imports neither `ioredis` nor `node-redis`.
21
21
 
22
22
  ```ts
@@ -31,7 +31,7 @@ new BotHandler({ store: new RedisStore(redis) });
31
31
  | `@osqd/bothandlerjs` | the engine, detectors, presets, robots, stores, notifiers, challenge, dashboard |
32
32
  | `@osqd/bothandlerjs/adapters` | [Express, Fastify, Koa, Fetch](../integration/adapters.md) |
33
33
  | `@osqd/bothandlerjs/client` | the browser-side [client signals](../detection/client-signals.md) script |
34
- | `@osqd/bothandlerjs/corpus` | [`runCorpus`](../testing/corpus.md) and all 526 cases |
34
+ | `@osqd/bothandlerjs/corpus` | [`runCorpus`](../testing/corpus.md) and all 548 cases |
35
35
  | `@osqd/bothandlerjs/cli` | the [command line](../testing/cli.md) |
36
36
 
37
37
  ## Runtimes
@@ -43,7 +43,7 @@ npx @osqd/bothandlerjs check --preset protect-content
43
43
  ```
44
44
 
45
45
  ```
46
- protect-content against 522 shapes of real traffic
46
+ protect-content against 548 shapes of real traffic
47
47
 
48
48
  human 181 cases 3 tag, 175 allow, 3 challenge
49
49
  benign-bot 144 cases 6 allow, 86 tag, 48 block, 2 challenge, 2 rate-limit
@@ -112,6 +112,12 @@ Lists what a configuration actually installs, with each detector's cost and stag
112
112
  for the question "is `identity-rotation` on?", which has caused more confusion than any
113
113
  other single setting.
114
114
 
115
+ A preset selects *rules*, so it does not change this list — the flag is there because the
116
+ command builds a real handler, not because the answer moves. What does change it is
117
+ `challenge`, `probe` and `site`, each of which installs the detectors that read it. The
118
+ command says so on stderr, so redirecting the list somewhere stays clean. An unknown preset
119
+ is refused rather than quietly answered for the default configuration.
120
+
115
121
  ## Related
116
122
 
117
123
  - [The corpus](corpus.md) · [Log replay](replay.md)
@@ -1,6 +1,6 @@
1
1
  # The traffic corpus
2
2
 
3
- 526 cases, 739 requests, 6,002 header lines, 55 categories of real web traffic — and a
3
+ 548 cases, 1,235 requests, 12,802 header lines, 58 categories of real web traffic — and a
4
4
  harness that runs them against *your* configuration.
5
5
 
6
6
  ← [Documentation](../index.md) · [Testing](index.md)
@@ -21,12 +21,16 @@ npm run corpus -- --audience human --verbose
21
21
  ```
22
22
 
23
23
  ```
24
- monitor-only 526/526 cases pass · 0 false positives
25
- protect-content 526/526 cases pass · 0 false positives
26
- protect-data 525/526 cases pass · 0 false positives
27
- protect-auth 511/526 cases pass · 0 false positives
24
+ monitor-only 539/539 cases pass · 0 false positives
25
+ protect-content 539/539 cases pass · 0 false positives
26
+ protect-data 538/539 cases pass · 0 false positives
27
+ protect-auth 524/539 cases pass · 0 false positives
28
28
  ```
29
29
 
30
+ 539 rather than 548 because nine cases name a source this configuration does not provide —
31
+ a marker probe or a site baseline — and a verdict about a marker from a handler that issues
32
+ none is a verdict about nothing. Those are *skipped*, and named, rather than failed.
33
+
30
34
  The two strict presets do not pass everything, and **the gap is the documentation rather
31
35
  than a defect**: [`protect-auth`](../policy/presets.md#protect-auth) blocks proven
32
36
  automation, and the fifteen cases it fails are your payment webhook, your own server-side
@@ -38,11 +42,11 @@ corpus keeps the receipts.
38
42
 
39
43
  | Audience | Cases | Examples |
40
44
  | -------- | ----: | -------- |
41
- | **human** | 182 | 30 browser profiles across Chromium, Gecko and WebKit · desktop, mobile, tablet, console, television · 40 in-app WebViews (Instagram, TikTok, WeChat, KakaoTalk, LINE, VK, banking and airline apps) · Electron desktop apps · Tor, `resistFingerprinting`, Sec-GPC · Lynx, w3m, screen readers · IE11, Android 4.4, a car's infotainment screen · corporate proxies, carrier transcoders, CGNAT, iCloud Private Relay · an author signing in at `/wp-login.php` and a developer searching a docs site for SQL syntax |
45
+ | **human** | 186 | 30 browser profiles across Chromium, Gecko and WebKit · desktop, mobile, tablet, console, television · 40 in-app WebViews (Instagram, TikTok, WeChat, KakaoTalk, LINE, VK, banking and airline apps) · Electron desktop apps · Tor, `resistFingerprinting`, Sec-GPC · Lynx, w3m, screen readers · IE11, Android 4.4, a car's infotainment screen · corporate proxies, carrier transcoders, CGNAT, iCloud Private Relay · an author signing in at `/wp-login.php` and a developer searching a docs site for SQL syntax |
42
46
  | **benign-bot** | 144 | Googlebot and Bingbot verified by DNS · 30 regional crawlers (Naver, Seznam, Coc Coc, Sogou, 360, Shenma, Qwant, Mojeek) · Google's and Microsoft's specialist fleets · 12 link unfurlers · monitoring · feed and podcast clients · academic and archival crawlers · ad verification · email link scanners |
43
47
  | **declared-bot** | 32 | The AI fleet split by job — training, search, fetch-for-a-user — plus an agentic browser |
44
- | **unwanted-bot** | 106 | SEO and market-intelligence crawlers · **50 HTTP clients in their real header orders**, across Python, Node, JVM, Go, Rust, PHP, Ruby, .NET, Perl · headless runtimes · fabricated User-Agents from a randomiser (Chrome on an iPhone, Windows and macOS at once, Firefox on WebKit) |
45
- | **hostile** | 29 | Forged Googlebot four ways · scanners · credential stuffing · traps · protocol abuse and request-smuggling framing · forwarding-header injection · wordlist probes for `/.env`, `/.git`, JNDI and TRACE |
48
+ | **unwanted-bot** | 116 | SEO and market-intelligence crawlers · **50 HTTP clients in their real header orders**, across Python, Node, JVM, Go, Rust, PHP, Ruby, .NET, Perl · headless runtimes · fabricated User-Agents from a randomiser (Chrome on an iPhone, Windows and macOS at once, Firefox on WebKit) |
49
+ | **hostile** | 37 | Forged Googlebot four ways · scanners · credential stuffing · traps · protocol abuse and request-smuggling framing · forwarding-header injection · wordlist probes for `/.env`, `/.git`, JNDI and TRACE · traversals spelled in percent-encoding and encoded twice over · open-proxy probing |
46
50
  | **infrastructure** | 33 | CDN origin pulls (Cloudflare, Fastly, Akamai, CloudFront) · API gateways and service meshes · k8s and ELB probes · webhooks · browser prefetch |
47
51
 
48
52
  Every request is built the way the client actually builds it — the Client Hints block, the
@@ -13,7 +13,7 @@ that cheap.
13
13
  | Page | Answers |
14
14
  | ---- | ------- |
15
15
  | [The CLI](cli.md) | "what is this one request?", "what does this policy do?" |
16
- | [The corpus](corpus.md) | "who would this configuration hurt?" — 526 shapes of real traffic |
16
+ | [The corpus](corpus.md) | "who would this configuration hurt?" — 548 shapes of real traffic |
17
17
  | [Log replay](replay.md) | "what would this have done to yesterday?" |
18
18
  | [Try it](try-it.md) | "what does it look like running?" — the demo, the simulator, three dashboards |
19
19
 
@@ -77,7 +77,7 @@ detectors read. Run one scenario at a time with `npm run simulate:curl`,
77
77
  ### Replaying the whole corpus over the wire
78
78
 
79
79
  ```bash
80
- npm run simulate:corpus # all 526 cases
80
+ npm run simulate:corpus # all 548 cases
81
81
  npm run simulate:corpus:human # only the people
82
82
  npm run simulate -- --corpus --tag known-cost # only the awkward ones
83
83
  npm run simulate -- --corpus --case browse-chrome-windows --verbose
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osqd/bothandlerjs",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -80,11 +80,14 @@
80
80
  ],
81
81
  "scripts": {
82
82
  "build": "tsup && tsc --emitDeclarationOnly && tsc -p tsconfig.element.json",
83
+ "check:package": "npm run build && tsx scripts/check-package.ts",
83
84
  "build:watch": "tsup --watch",
84
85
  "test": "vitest run",
85
86
  "test:watch": "vitest",
86
87
  "test:coverage": "vitest run --coverage",
87
88
  "test:browser": "vitest run --config vitest.browser.config.ts",
89
+ "test:browser:firefox": "BROWSER_ENGINE=firefox npm run test:browser",
90
+ "test:browser:webkit": "BROWSER_ENGINE=webkit npm run test:browser",
88
91
  "lint": "biome check .",
89
92
  "docs:check": "node scripts/check-links.mjs",
90
93
  "format": "biome check --write .",