dbsc-toolkit 2.5.0 → 2.6.1
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 +61 -41
- package/dist/core/crypto/jwk.js +3 -1
- package/dist/core/crypto/jwk.js.map +1 -1
- package/dist/core/index.d.ts +4 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/protect-policy.d.ts +27 -0
- package/dist/core/protect-policy.d.ts.map +1 -0
- package/dist/core/protect-policy.js +8 -0
- package/dist/core/protect-policy.js.map +1 -0
- package/dist/core/protocol/cookies.d.ts +6 -0
- package/dist/core/protocol/cookies.d.ts.map +1 -0
- package/dist/core/protocol/cookies.js +33 -0
- package/dist/core/protocol/cookies.js.map +1 -0
- package/dist/core/types.d.ts +15 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/express/create-dbsc.d.ts +41 -0
- package/dist/express/create-dbsc.d.ts.map +1 -0
- package/dist/express/create-dbsc.js +88 -0
- package/dist/express/create-dbsc.js.map +1 -0
- package/dist/express/index.d.ts +9 -0
- package/dist/express/index.d.ts.map +1 -1
- package/dist/express/index.js +11 -1
- package/dist/express/index.js.map +1 -1
- package/dist/express/require-proof.d.ts +20 -0
- package/dist/express/require-proof.d.ts.map +1 -0
- package/dist/express/require-proof.js +56 -0
- package/dist/express/require-proof.js.map +1 -0
- package/dist/fastify/create-dbsc.d.ts +32 -0
- package/dist/fastify/create-dbsc.d.ts.map +1 -0
- package/dist/fastify/create-dbsc.js +70 -0
- package/dist/fastify/create-dbsc.js.map +1 -0
- package/dist/fastify/index.d.ts +9 -0
- package/dist/fastify/index.d.ts.map +1 -1
- package/dist/fastify/index.js +7 -0
- package/dist/fastify/index.js.map +1 -1
- package/dist/fastify/require-proof.d.ts +14 -0
- package/dist/fastify/require-proof.d.ts.map +1 -0
- package/dist/fastify/require-proof.js +50 -0
- package/dist/fastify/require-proof.js.map +1 -0
- package/dist/hono/create-dbsc.d.ts +34 -0
- package/dist/hono/create-dbsc.d.ts.map +1 -0
- package/dist/hono/create-dbsc.js +69 -0
- package/dist/hono/create-dbsc.js.map +1 -0
- package/dist/hono/index.d.ts +9 -0
- package/dist/hono/index.d.ts.map +1 -1
- package/dist/hono/index.js +7 -0
- package/dist/hono/index.js.map +1 -1
- package/dist/hono/require-proof.d.ts +13 -0
- package/dist/hono/require-proof.d.ts.map +1 -0
- package/dist/hono/require-proof.js +47 -0
- package/dist/hono/require-proof.js.map +1 -0
- package/dist/nextjs/create-dbsc.d.ts +44 -0
- package/dist/nextjs/create-dbsc.d.ts.map +1 -0
- package/dist/nextjs/create-dbsc.js +68 -0
- package/dist/nextjs/create-dbsc.js.map +1 -0
- package/dist/nextjs/index.d.ts +4 -0
- package/dist/nextjs/index.d.ts.map +1 -1
- package/dist/nextjs/index.js +2 -0
- package/dist/nextjs/index.js.map +1 -1
- package/dist/nextjs/require-proof.d.ts +28 -0
- package/dist/nextjs/require-proof.d.ts.map +1 -0
- package/dist/nextjs/require-proof.js +44 -0
- package/dist/nextjs/require-proof.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,36 +42,28 @@ npm install dbsc-toolkit
|
|
|
42
42
|
Pick the framework adapter and storage you actually use (each is an optional peer dependency):
|
|
43
43
|
|
|
44
44
|
```sh
|
|
45
|
-
npm install express
|
|
46
|
-
npm install express
|
|
45
|
+
npm install express ioredis # Express + Redis
|
|
46
|
+
npm install express pg # Express + Postgres
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
## Quick start
|
|
50
50
|
|
|
51
|
-
Copy-paste runnable.
|
|
51
|
+
Copy-paste runnable. `createDbsc()` takes your config once; `install()` mounts everything — the protocol routes, the bound-route JSON parser, the `/dbsc-client` SDK, and `trust proxy`. No `cookie-parser`, no manual static mount.
|
|
52
52
|
|
|
53
53
|
```ts
|
|
54
54
|
import express from "express";
|
|
55
|
-
import cookieParser from "cookie-parser";
|
|
56
55
|
import { randomUUID } from "node:crypto";
|
|
57
|
-
import {
|
|
56
|
+
import { createDbsc } from "dbsc-toolkit/express";
|
|
58
57
|
import { MemoryStorage } from "dbsc-toolkit/storage/memory";
|
|
59
58
|
|
|
60
59
|
const app = express();
|
|
60
|
+
app.use(express.json()); // for your own routes' JSON bodies
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
app.use(express.json()); // required: bound polyfill POSTs JSON
|
|
65
|
-
app.use(
|
|
66
|
-
"/dbsc-client", // serves the browser SDK for Firefox / Safari
|
|
67
|
-
express.static(new URL("../node_modules/dbsc-toolkit/dist/client/", import.meta.url).pathname),
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
const storage = new MemoryStorage(); // swap for RedisStorage / PostgresStorage in production
|
|
71
|
-
app.use(dbsc({ storage })); // mounts /dbsc/registration, /dbsc/refresh, /dbsc-bound/*
|
|
62
|
+
const dbsc = createDbsc({ storage: new MemoryStorage() }); // swap for Redis/Postgres in prod
|
|
63
|
+
dbsc.install(app); // mounts /dbsc/*, /dbsc-bound/*, the SDK, trust proxy
|
|
72
64
|
|
|
73
65
|
app.post("/login", async (req, res) => {
|
|
74
|
-
await
|
|
66
|
+
await dbsc.bind(res, randomUUID(), { userId: req.body.username });
|
|
75
67
|
res.json({ ok: true });
|
|
76
68
|
});
|
|
77
69
|
|
|
@@ -92,46 +84,67 @@ Without the script tag those browsers stay on `tier: "none"`. Native Chromium 14
|
|
|
92
84
|
|
|
93
85
|
### Common failure modes
|
|
94
86
|
|
|
95
|
-
- **`tier` always reads `"none"` on Chromium 145+?**
|
|
87
|
+
- **`tier` always reads `"none"` on Chromium 145+?** Running on plain HTTP (DBSC needs HTTPS), or `dbsc.install(app)` was never called. `install()` already sets `trust proxy` and parses cookies, so the old "middleware order" class of bug is gone.
|
|
96
88
|
- **Chrome loops registration?** Storage was wiped — switch off `MemoryStorage` to Redis or Postgres before deploying anywhere that ever restarts.
|
|
97
89
|
- **Tier flips back to `"none"` right after login?** The race between `/login` returning and the browser running `POST /dbsc/registration`. Poll `/me` for ~1 s after login or await the bound-SDK outcome promise. The demo wires both — see [examples/express/src/server.js](./examples/express/src/server.js).
|
|
98
|
-
- **Firefox / Safari still on `"none"`?** Forgot the `<script type="module">` tag above
|
|
90
|
+
- **Firefox / Safari still on `"none"`?** Forgot the `<script type="module">` tag above. `install()` serves the SDK at `/dbsc-client` for you; you still load it on the page.
|
|
99
91
|
|
|
100
92
|
Full walk-through: [docs/getting-started.md](./docs/getting-started.md).
|
|
101
93
|
|
|
102
94
|
## Adding to an existing app
|
|
103
95
|
|
|
104
|
-
You don't rewrite login, you don't migrate the session store. DBSC sits alongside your existing session cookie and binds to the same session id.
|
|
96
|
+
You don't rewrite login, you don't migrate the session store. DBSC sits alongside your existing session cookie and binds to the same session id. The whole integration for an Express app:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { createDbsc, requireProof } from "dbsc-toolkit/express";
|
|
100
|
+
import { RedisStorage } from "dbsc-toolkit/storage/redis";
|
|
101
|
+
import Redis from "ioredis";
|
|
102
|
+
|
|
103
|
+
// 1. configure the kit once — storage is the only required option
|
|
104
|
+
const dbsc = createDbsc({ storage: new RedisStorage(new Redis(process.env.REDIS_URL)) });
|
|
105
|
+
|
|
106
|
+
// 2. install once — mounts the protocol routes, trust proxy, the SDK
|
|
107
|
+
dbsc.install(app);
|
|
108
|
+
|
|
109
|
+
// 3. one line in your existing /login, after the password check
|
|
110
|
+
app.post("/login", async (req, res) => {
|
|
111
|
+
const user = await yourPasswordCheck(req.body); // unchanged
|
|
112
|
+
const sid = await issueYourOwnSession(user.id); // unchanged
|
|
113
|
+
await dbsc.bind(res, sid, { userId: user.id }); // <- the new line
|
|
114
|
+
res.json({ ok: true });
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// 4. guard sensitive routes — one call. POST routes deliver raw bytes.
|
|
118
|
+
app.post("/payment", express.raw({ type: "*/*" }), requireProof(), paymentHandler);
|
|
105
119
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
120
|
+
// 5. one line in /logout
|
|
121
|
+
app.post("/logout", async (req, res) => {
|
|
122
|
+
await res.locals.dbsc.revoke(); // <- the new line
|
|
123
|
+
await yourSessionStore.delete(req.cookies.sid); // unchanged
|
|
124
|
+
res.json({ ok: true });
|
|
125
|
+
});
|
|
126
|
+
```
|
|
112
127
|
|
|
113
|
-
|
|
128
|
+
`install()` handles `trust proxy`, cookie parsing, the bound-route JSON parser, and the `/dbsc-client` static mount — you don't wire those. You still need `express.json()` for your *own* routes' bodies. `sessionId` is whatever id your session store already issues; DBSC binds to it — no second id-space.
|
|
114
129
|
|
|
115
|
-
|
|
130
|
+
**No server-side session id** (NextAuth JWT mode, iron-session, Lucia stateless)? Call `dbsc.bind(res, { userId })` with no id — the kit derives a stable one and manages a per-device cookie so each browser of the same user binds independently. Per-system recipes: [docs/integration-recipes.md](./docs/integration-recipes.md).
|
|
116
131
|
|
|
117
|
-
|
|
132
|
+
**The full step-by-step** — every option and its default, the `autoBind` transparent-rollout variant, the per-route policy table, the migration timeline — is in [docs/integrating-existing-auth.md](./docs/integrating-existing-auth.md).
|
|
118
133
|
|
|
119
|
-
##
|
|
134
|
+
## Protect your routes
|
|
120
135
|
|
|
121
|
-
> **First time here?** [docs/usage.md](./docs/usage.md) walks the
|
|
136
|
+
> **First time here?** [docs/usage.md](./docs/usage.md) walks the setup and the guard in order, with concrete code. Five-minute read.
|
|
122
137
|
|
|
123
|
-
After
|
|
138
|
+
After `createDbsc().install()`, every request through the middleware has a `tier` field on the request context. The library does not auto-protect anything — you add **one guard, `requireProof()`**, to each route that matters.
|
|
124
139
|
|
|
125
|
-
| Your route does… | Use this guard | What it stops |
|
|
126
|
-
|
|
127
|
-
| Public / read-only (feed, search, public profile) | Nothing | n/a — no auth gate at all |
|
|
128
|
-
|
|
|
129
|
-
| Account takeover risk (password change, email change, admin actions) | `requireBoundProof({ storage })` | Stolen cookie cannot ride along even while the victim is online — Firefox / Safari now have the same guarantee Chrome gets from native DBSC | [docs/per-request-signing.md](./docs/per-request-signing.md) |
|
|
130
|
-
| Moves money or numeric input that matters (payment, transfer, refund, withdraw) | `requireBoundProof({ storage, signBody: true })` on the server + `wrapFetch({ signBody: true })` on the client | All of the above PLUS an active MITM cannot substitute the request body (amount, recipient, etc.) within the timestamp window | [docs/per-request-signing.md#body-signing-setup-v230](./docs/per-request-signing.md) |
|
|
140
|
+
| Your route does… | Use this guard | What it stops |
|
|
141
|
+
|---|---|---|
|
|
142
|
+
| Public / read-only (feed, search, public profile) | Nothing | n/a — no auth gate at all |
|
|
143
|
+
| Anything authenticated (post, comment, upvote, settings, payment, admin) | `requireProof()` (server) + `wrapFetch({ signBody: true })` (client, for Firefox/Safari) | A stolen cookie cannot be replayed from another device, cannot ride along during the freshness window, and an MITM cannot substitute a POST body |
|
|
131
144
|
|
|
132
|
-
|
|
145
|
+
There is deliberately **no tier-level argument**. A `dbsc`-only gate would lock out every Firefox/Safari user; a `bound`-only check (tier without a per-request proof) is not actually secure. `requireProof()` is the one honest answer — it requires a bound device + a per-request proof and works on every browser (Chromium passes through natively, Firefox/Safari supply the signed proof). It signs the request body, so a POST guarded route mounts `express.raw()` in front.
|
|
133
146
|
|
|
134
|
-
The full threat boundary
|
|
147
|
+
The full threat boundary, the per-framework wiring (Fastify / Hono / Next.js), and the migration timeline for an existing app are in [docs/integrating-existing-auth.md](./docs/integrating-existing-auth.md) and [docs/per-request-signing.md](./docs/per-request-signing.md).
|
|
135
148
|
|
|
136
149
|
## Subpath imports
|
|
137
150
|
|
|
@@ -149,13 +162,20 @@ Tree-shaking eliminates anything you don't import. Using Koa, Hapi, raw `http`,
|
|
|
149
162
|
|
|
150
163
|
## Protection tiers
|
|
151
164
|
|
|
165
|
+
`tier` is the **state** of a session — what kind of binding the browser achieved. It is *not* a knob you gate on directly:
|
|
166
|
+
|
|
152
167
|
| Tier | Mechanism | Protects against |
|
|
153
168
|
|------|-----------|------------------|
|
|
154
169
|
| `dbsc` | Native W3C DBSC, key in TPM / Secure Enclave / Android Keystore | Cookie theft (XSS, network, logs, paste-to-other-browser) **and** infostealer malware reading the browser profile |
|
|
155
170
|
| `bound` | Web Crypto polyfill, non-extractable ECDSA P-256 key in IndexedDB | Cookie theft. Does not defeat infostealer malware on the user's machine. |
|
|
156
|
-
| `none` |
|
|
171
|
+
| `none` | No active / fresh binding | Nothing the cookie itself doesn't already do |
|
|
172
|
+
|
|
173
|
+
**How to gate routes — the whole decision tree:**
|
|
174
|
+
|
|
175
|
+
- **Public / read-only route?** → no guard.
|
|
176
|
+
- **Anything authenticated?** → `requireProof()`. That's it.
|
|
157
177
|
|
|
158
|
-
|
|
178
|
+
There is no third option, and **never gate a route on `tier === "dbsc"`** — that locks out every Firefox and Safari user (they can only reach `tier: "bound"`), and `requireProof()` already gives those browsers the same per-request guarantee via a signed proof. `requireProof()` is the one guard; it works on every browser. Read `res.locals.dbsc.tier` only if you want to *display* binding state in the UI — not to build a gate. Full guidance in [docs/security/best-practices.md](./docs/security/best-practices.md).
|
|
159
179
|
|
|
160
180
|
## Going deeper
|
|
161
181
|
|
package/dist/core/crypto/jwk.js
CHANGED
|
@@ -30,7 +30,9 @@ export function detectAlgorithm(jwk) {
|
|
|
30
30
|
return "RS256";
|
|
31
31
|
throw new DbscVerificationError(ErrorCodes.UNKNOWN_ALGORITHM, `cannot determine algorithm for kty=${jwk.kty} crv=${jwk.crv}`);
|
|
32
32
|
}
|
|
33
|
+
/** Bit length of the bytes a base64url string decodes to. JWK `n` is unpadded. */
|
|
33
34
|
function base64urlBits(b64) {
|
|
34
|
-
|
|
35
|
+
const len = b64.replace(/=+$/, "").length;
|
|
36
|
+
return Math.floor((len * 3) / 4) * 8;
|
|
35
37
|
}
|
|
36
38
|
//# sourceMappingURL=jwk.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwk.js","sourceRoot":"","sources":["../../../src/core/crypto/jwk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAEjE,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC5C,MAAM,YAAY,GAAG,IAAI,CAAC;AAE1B,MAAM,UAAU,WAAW,CAAC,GAAe;IACzC,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,qBAAqB,CAC7B,UAAU,CAAC,WAAW,EACtB,sBAAsB,GAAG,CAAC,GAAG,EAAE,CAChC,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,qBAAqB,CAC7B,UAAU,CAAC,WAAW,EACtB,kCAAkC,CACnC,CAAC;QACJ,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,GAAG,CAAC,GAAG,KAAK,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,qBAAqB,CAC7B,UAAU,CAAC,WAAW,EACtB,yBAAyB,CAC1B,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAClC,IAAI,IAAI,GAAG,YAAY,EAAE,CAAC;YACxB,MAAM,IAAI,qBAAqB,CAC7B,UAAU,CAAC,WAAW,EACtB,sBAAsB,IAAI,kBAAkB,YAAY,EAAE,CAC3D,CAAC;QACJ,CAAC;QACD,OAAO;IACT,CAAC;IAED,MAAM,IAAI,qBAAqB,CAC7B,UAAU,CAAC,WAAW,EACtB,yBAAyB,GAAG,CAAC,GAAG,EAAE,CACnC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAe;IAC7C,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,GAAG,KAAK,OAAO;QAAE,OAAO,OAAO,CAAC;IAC5D,IAAI,GAAG,CAAC,GAAG,KAAK,KAAK;QAAE,OAAO,OAAO,CAAC;IACtC,MAAM,IAAI,qBAAqB,CAC7B,UAAU,CAAC,iBAAiB,EAC5B,sCAAsC,GAAG,CAAC,GAAG,QAAQ,GAAG,CAAC,GAAG,EAAE,CAC/D,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,GAAW;IAChC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"jwk.js","sourceRoot":"","sources":["../../../src/core/crypto/jwk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAEjE,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC5C,MAAM,YAAY,GAAG,IAAI,CAAC;AAE1B,MAAM,UAAU,WAAW,CAAC,GAAe;IACzC,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,qBAAqB,CAC7B,UAAU,CAAC,WAAW,EACtB,sBAAsB,GAAG,CAAC,GAAG,EAAE,CAChC,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,qBAAqB,CAC7B,UAAU,CAAC,WAAW,EACtB,kCAAkC,CACnC,CAAC;QACJ,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,GAAG,CAAC,GAAG,KAAK,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,qBAAqB,CAC7B,UAAU,CAAC,WAAW,EACtB,yBAAyB,CAC1B,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAClC,IAAI,IAAI,GAAG,YAAY,EAAE,CAAC;YACxB,MAAM,IAAI,qBAAqB,CAC7B,UAAU,CAAC,WAAW,EACtB,sBAAsB,IAAI,kBAAkB,YAAY,EAAE,CAC3D,CAAC;QACJ,CAAC;QACD,OAAO;IACT,CAAC;IAED,MAAM,IAAI,qBAAqB,CAC7B,UAAU,CAAC,WAAW,EACtB,yBAAyB,GAAG,CAAC,GAAG,EAAE,CACnC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAe;IAC7C,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,GAAG,KAAK,OAAO;QAAE,OAAO,OAAO,CAAC;IAC5D,IAAI,GAAG,CAAC,GAAG,KAAK,KAAK;QAAE,OAAO,OAAO,CAAC;IACtC,MAAM,IAAI,qBAAqB,CAC7B,UAAU,CAAC,iBAAiB,EAC5B,sCAAsC,GAAG,CAAC,GAAG,QAAQ,GAAG,CAAC,GAAG,EAAE,CAC/D,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,SAAS,aAAa,CAAC,GAAW;IAChC,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC;IAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;AACvC,CAAC"}
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { ProtectionTier, BoundKey, Session, Challenge, RegistrationProof, RefreshProof, StorageAdapter, RateLimiter, DbscOptions, AutoBindResult, AnyTelemetryEvent, TelemetryEvent, RegistrationEvent, RefreshEvent, VerificationFailureEvent, SessionStolenEvent, TierChangeEvent, } from "./types.js";
|
|
1
|
+
export type { ProtectionTier, BoundKey, Session, Challenge, RegistrationProof, RefreshProof, StorageAdapter, RateLimiter, DbscOptions, DbscKitExtras, AutoBindResult, AnyTelemetryEvent, TelemetryEvent, RegistrationEvent, RefreshEvent, VerificationFailureEvent, SessionStolenEvent, TierChangeEvent, } from "./types.js";
|
|
2
2
|
export { DbscProtocolError, DbscVerificationError, DbscStorageError, ErrorCodes } from "./errors.js";
|
|
3
3
|
export { validateJwk, detectAlgorithm } from "./crypto/jwk.js";
|
|
4
4
|
export { verifyDbscJws, parseRegistrationJws } from "./crypto/jws.js";
|
|
@@ -16,4 +16,7 @@ export { NoopRateLimiter } from "./ratelimit/interface.js";
|
|
|
16
16
|
export { emit } from "./telemetry/hooks.js";
|
|
17
17
|
export { deriveSessionId } from "./derive-session-id.js";
|
|
18
18
|
export type { DeriveSessionIdInput } from "./derive-session-id.js";
|
|
19
|
+
export { noBindingReason } from "./protect-policy.js";
|
|
20
|
+
export type { RequireProofOptions } from "./protect-policy.js";
|
|
21
|
+
export { parseCookieHeader } from "./protocol/cookies.js";
|
|
19
22
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/core/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,cAAc,EACd,QAAQ,EACR,OAAO,EACP,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,WAAW,EACX,WAAW,EACX,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,wBAAwB,EACxB,kBAAkB,EAClB,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAErG,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEtE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,yBAAyB,EACzB,oBAAoB,EACpB,yBAAyB,EACzB,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,0BAA0B,EAC1B,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC1F,YAAY,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAEhE,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,cAAc,EACd,QAAQ,EACR,OAAO,EACP,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,WAAW,EACX,WAAW,EACX,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,wBAAwB,EACxB,kBAAkB,EAClB,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAErG,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEtE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,yBAAyB,EACzB,oBAAoB,EACpB,yBAAyB,EACzB,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,0BAA0B,EAC1B,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC1F,YAAY,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAEhE,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/core/index.js
CHANGED
|
@@ -12,4 +12,6 @@ export { verifyBoundProof, parseProofHeader, BOUND_PROOF_HEADER } from "./bound/
|
|
|
12
12
|
export { NoopRateLimiter } from "./ratelimit/interface.js";
|
|
13
13
|
export { emit } from "./telemetry/hooks.js";
|
|
14
14
|
export { deriveSessionId } from "./derive-session-id.js";
|
|
15
|
+
export { noBindingReason } from "./protect-policy.js";
|
|
16
|
+
export { parseCookieHeader } from "./protocol/cookies.js";
|
|
15
17
|
//# sourceMappingURL=index.js.map
|
package/dist/core/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAErG,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEtE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,yBAAyB,EACzB,oBAAoB,EACpB,yBAAyB,EACzB,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,0BAA0B,EAC1B,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAG1F,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { StorageAdapter } from "./types.js";
|
|
2
|
+
import type { SkippedEntry } from "./protocol/headers.js";
|
|
3
|
+
/**
|
|
4
|
+
* Options for `requireProof()`. All optional — `requireProof()` with no
|
|
5
|
+
* arguments is the normal call. `requireProof()` always means: the request
|
|
6
|
+
* must come from a bound device and prove it per-request. It works on every
|
|
7
|
+
* browser — Chromium's hardware-backed `dbsc` tier passes through, the
|
|
8
|
+
* software `bound` tier (Firefox / Safari / older Chromium) supplies a signed,
|
|
9
|
+
* body-hashed proof.
|
|
10
|
+
*/
|
|
11
|
+
export interface RequireProofOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Let the hardware-backed `dbsc` tier through without a proof header.
|
|
14
|
+
* Default true — Chromium enforces the cookie↔key binding browser-side, and
|
|
15
|
+
* the native protocol does not sign request bodies. Set false to demand a
|
|
16
|
+
* signed proof from Chromium too (the client must then call
|
|
17
|
+
* `wrapFetch({ signBody: true })`).
|
|
18
|
+
*/
|
|
19
|
+
allowDbscWithoutProof?: boolean;
|
|
20
|
+
/** Accepted proof timestamp window, ms. */
|
|
21
|
+
timestampWindowMs?: number;
|
|
22
|
+
/** Storage override. Defaults to the storage the adapter middleware was given. */
|
|
23
|
+
storage?: StorageAdapter;
|
|
24
|
+
}
|
|
25
|
+
/** Human-readable reason for a `tier: "none"` rejection — quota-aware. */
|
|
26
|
+
export declare function noBindingReason(skipped?: SkippedEntry[]): string;
|
|
27
|
+
//# sourceMappingURL=protect-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protect-policy.d.ts","sourceRoot":"","sources":["../../src/core/protect-policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,2CAA2C;IAC3C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kFAAkF;IAClF,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,OAAO,GAAE,YAAY,EAAO,GAAG,MAAM,CAKpE"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Human-readable reason for a `tier: "none"` rejection — quota-aware. */
|
|
2
|
+
export function noBindingReason(skipped = []) {
|
|
3
|
+
if (skipped.some((s) => s.reason === "quota_exceeded")) {
|
|
4
|
+
return "Chrome declined native DBSC registration (quota_exceeded). Clear this origin's site data in chrome://settings, or open a fresh profile.";
|
|
5
|
+
}
|
|
6
|
+
return "no active device binding — the session is not bound, or the binding has gone stale";
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=protect-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protect-policy.js","sourceRoot":"","sources":["../../src/core/protect-policy.ts"],"names":[],"mappings":"AA0BA,0EAA0E;AAC1E,MAAM,UAAU,eAAe,CAAC,UAA0B,EAAE;IAC1D,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,gBAAgB,CAAC,EAAE,CAAC;QACvD,OAAO,yIAAyI,CAAC;IACnJ,CAAC;IACD,OAAO,oFAAoF,CAAC;AAC9F,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses a `Cookie` request header into a name→value map. Lets the adapter
|
|
3
|
+
* middlewares read DBSC cookies without depending on `cookie-parser`.
|
|
4
|
+
*/
|
|
5
|
+
export declare function parseCookieHeader(header?: string | null): Record<string, string>;
|
|
6
|
+
//# sourceMappingURL=cookies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../../src/core/protocol/cookies.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAsBhF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses a `Cookie` request header into a name→value map. Lets the adapter
|
|
3
|
+
* middlewares read DBSC cookies without depending on `cookie-parser`.
|
|
4
|
+
*/
|
|
5
|
+
export function parseCookieHeader(header) {
|
|
6
|
+
// Null-prototype map: a `__proto__` / `constructor` cookie name is then a
|
|
7
|
+
// plain own property, never a prototype-pollution vector.
|
|
8
|
+
const out = Object.create(null);
|
|
9
|
+
if (!header)
|
|
10
|
+
return out;
|
|
11
|
+
for (const part of header.split(";")) {
|
|
12
|
+
const eq = part.indexOf("=");
|
|
13
|
+
if (eq < 0)
|
|
14
|
+
continue;
|
|
15
|
+
const name = part.slice(0, eq).trim();
|
|
16
|
+
if (!name)
|
|
17
|
+
continue;
|
|
18
|
+
let value = part.slice(eq + 1).trim();
|
|
19
|
+
if (value.length >= 2 && value.startsWith('"') && value.endsWith('"')) {
|
|
20
|
+
value = value.slice(1, -1);
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
value = decodeURIComponent(value);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// keep the raw value if it is not valid percent-encoding
|
|
27
|
+
}
|
|
28
|
+
if (!(name in out))
|
|
29
|
+
out[name] = value;
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=cookies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookies.js","sourceRoot":"","sources":["../../../src/core/protocol/cookies.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAsB;IACtD,0EAA0E;IAC1E,0DAA0D;IAC1D,MAAM,GAAG,GAA2B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACxD,IAAI,CAAC,MAAM;QAAE,OAAO,GAAG,CAAC;IACxB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,EAAE,GAAG,CAAC;YAAE,SAAS;QACrB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACtE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QACD,IAAI,CAAC;YACH,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,yDAAyD;QAC3D,CAAC;QACD,IAAI,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACxC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -119,4 +119,19 @@ export interface AutoBindResult {
|
|
|
119
119
|
sessionId: string;
|
|
120
120
|
userId: string;
|
|
121
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Extra options accepted by every adapter's `createDbsc()` on top of that
|
|
124
|
+
* adapter's middleware options. The kit returned by `createDbsc()` carries
|
|
125
|
+
* these so `install()`, `bind()`, and `requireProof()` need no re-passing.
|
|
126
|
+
*/
|
|
127
|
+
export interface DbscKitExtras {
|
|
128
|
+
/** Use `__Host-` cookies + the Secure flag. Default true. */
|
|
129
|
+
secure?: boolean;
|
|
130
|
+
/** Mount path for the static client SDK. Default "/dbsc-client". `false` skips it. */
|
|
131
|
+
clientPath?: string | false;
|
|
132
|
+
/** Default session TTL (ms) for `bind()`. */
|
|
133
|
+
sessionTtl?: number;
|
|
134
|
+
/** Let `install()` set `trust proxy`. Default true. Set false to leave it alone. */
|
|
135
|
+
trustProxy?: boolean;
|
|
136
|
+
}
|
|
122
137
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/core/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type Express, type Response, type RequestHandler } from "express";
|
|
2
|
+
import { type RequireProofOptions } from "../core/index.js";
|
|
3
|
+
import { type DbscExpressOptions } from "./index.js";
|
|
4
|
+
export interface CreateDbscOptions extends DbscExpressOptions {
|
|
5
|
+
/** Mount path for the static client SDK. Default "/dbsc-client". `false` skips it. */
|
|
6
|
+
clientPath?: string | false;
|
|
7
|
+
/** Default session TTL (ms) for `bind()`. */
|
|
8
|
+
sessionTtl?: number;
|
|
9
|
+
/** Let `install()` set `trust proxy`. Default true. */
|
|
10
|
+
trustProxy?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface BindOptions {
|
|
13
|
+
userId: string;
|
|
14
|
+
/**
|
|
15
|
+
* Manual per-device value. Optional — when omitted on the no-sessionId
|
|
16
|
+
* (JWT) path, the kit manages a `__Host-dbsc-device` cookie itself so each
|
|
17
|
+
* browser binds independently. Pass this only to control device identity
|
|
18
|
+
* yourself.
|
|
19
|
+
*/
|
|
20
|
+
deviceHint?: string;
|
|
21
|
+
/** Namespace to scope derived ids. */
|
|
22
|
+
namespace?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface DbscKit {
|
|
25
|
+
/** Mount the whole DBSC surface on the app: middleware, bound-route JSON, client SDK. */
|
|
26
|
+
install(app: Express): Express;
|
|
27
|
+
/** The raw `dbsc()` middleware, for manual mounting. */
|
|
28
|
+
middleware(): RequestHandler;
|
|
29
|
+
/** Start a binding. Pass a sessionId, or omit it to derive one from `userId` (JWT apps). */
|
|
30
|
+
bind(res: Response, sessionId: string, opts: BindOptions): Promise<string>;
|
|
31
|
+
bind(res: Response, opts: BindOptions): Promise<string>;
|
|
32
|
+
/** The route guard — requires a bound device + a per-request proof. */
|
|
33
|
+
requireProof(opts?: RequireProofOptions): RequestHandler;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Builds a configured DBSC kit. Storage, `secure`, TTLs, rate limiter and
|
|
37
|
+
* telemetry are set once here; `install()`, `bind()` and `requireProof()` all
|
|
38
|
+
* read this config — nothing is re-passed.
|
|
39
|
+
*/
|
|
40
|
+
export declare function createDbsc(opts: CreateDbscOptions): DbscKit;
|
|
41
|
+
//# sourceMappingURL=create-dbsc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-dbsc.d.ts","sourceRoot":"","sources":["../../src/express/create-dbsc.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,KAAK,OAAO,EAAgB,KAAK,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAGlG,OAAO,EAAsC,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAChG,OAAO,EAAqB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA4BxE,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC5B,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,yFAAyF;IACzF,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC;IAC/B,wDAAwD;IACxD,UAAU,IAAI,cAAc,CAAC;IAC7B,4FAA4F;IAC5F,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3E,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxD,uEAAuE;IACvE,YAAY,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,cAAc,CAAC;CAC1D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAoD3D"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { randomBytes } from "node:crypto";
|
|
4
|
+
import { deriveSessionId, parseCookieHeader } from "../core/index.js";
|
|
5
|
+
import { dbsc, bindSession } from "./index.js";
|
|
6
|
+
import { requireProof } from "./require-proof.js";
|
|
7
|
+
const DEVICE_COOKIE_TTL_MS = 365 * 24 * 60 * 60 * 1000;
|
|
8
|
+
/**
|
|
9
|
+
* Returns a stable per-device value for the JWT `bind()` path: reads the
|
|
10
|
+
* `__Host-dbsc-device` cookie, or mints + sets one if absent. Two browsers of
|
|
11
|
+
* the same user thus derive distinct sessionIds and bind independently.
|
|
12
|
+
*/
|
|
13
|
+
function resolveDeviceHint(res, secure) {
|
|
14
|
+
const name = secure ? "__Host-dbsc-device" : "dbsc-device";
|
|
15
|
+
const req = res.req;
|
|
16
|
+
const existing = req?.cookies?.[name] ??
|
|
17
|
+
parseCookieHeader(req?.headers?.cookie)[name];
|
|
18
|
+
if (existing)
|
|
19
|
+
return existing;
|
|
20
|
+
const value = randomBytes(16).toString("hex");
|
|
21
|
+
res.cookie(name, value, {
|
|
22
|
+
httpOnly: true,
|
|
23
|
+
secure,
|
|
24
|
+
sameSite: "lax",
|
|
25
|
+
path: "/",
|
|
26
|
+
maxAge: DEVICE_COOKIE_TTL_MS,
|
|
27
|
+
});
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Builds a configured DBSC kit. Storage, `secure`, TTLs, rate limiter and
|
|
32
|
+
* telemetry are set once here; `install()`, `bind()` and `requireProof()` all
|
|
33
|
+
* read this config — nothing is re-passed.
|
|
34
|
+
*/
|
|
35
|
+
export function createDbsc(opts) {
|
|
36
|
+
const secure = opts.secure ?? true;
|
|
37
|
+
const clientPath = opts.clientPath ?? "/dbsc-client";
|
|
38
|
+
const registrationPath = opts.registrationPath ?? "/dbsc/registration";
|
|
39
|
+
const boundRegistrationPath = opts.boundRegistrationPath ?? "/dbsc-bound/registration";
|
|
40
|
+
const boundRefreshPath = opts.boundRefreshPath ?? "/dbsc-bound/refresh";
|
|
41
|
+
const middleware = dbsc(opts);
|
|
42
|
+
async function bind(res, a, b) {
|
|
43
|
+
const bindOpts = typeof a === "string" ? b : a;
|
|
44
|
+
let sessionId;
|
|
45
|
+
if (typeof a === "string") {
|
|
46
|
+
sessionId = a;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// JWT path: no sessionId. An explicit deviceHint wins; otherwise the kit
|
|
50
|
+
// manages a per-device cookie so each browser binds independently.
|
|
51
|
+
const deviceHint = bindOpts.deviceHint ?? resolveDeviceHint(res, secure);
|
|
52
|
+
sessionId = await deriveSessionId({
|
|
53
|
+
userId: bindOpts.userId,
|
|
54
|
+
deviceHint,
|
|
55
|
+
...(bindOpts.namespace !== undefined && { namespace: bindOpts.namespace }),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
await bindSession(res, sessionId, opts.storage, {
|
|
59
|
+
userId: bindOpts.userId,
|
|
60
|
+
secure,
|
|
61
|
+
registrationPath,
|
|
62
|
+
...(opts.registrationCookieTtl !== undefined && {
|
|
63
|
+
registrationCookieTtl: opts.registrationCookieTtl,
|
|
64
|
+
}),
|
|
65
|
+
...(opts.sessionTtl !== undefined && { sessionTtl: opts.sessionTtl }),
|
|
66
|
+
});
|
|
67
|
+
return sessionId;
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
middleware: () => middleware,
|
|
71
|
+
install(app) {
|
|
72
|
+
if (opts.trustProxy !== false)
|
|
73
|
+
app.set("trust proxy", true);
|
|
74
|
+
const json = express.json();
|
|
75
|
+
app.use(boundRegistrationPath, json);
|
|
76
|
+
app.use(boundRefreshPath, json);
|
|
77
|
+
app.use(middleware);
|
|
78
|
+
if (clientPath !== false) {
|
|
79
|
+
const clientDir = fileURLToPath(new URL("../client/", import.meta.url));
|
|
80
|
+
app.use(clientPath, express.static(clientDir));
|
|
81
|
+
}
|
|
82
|
+
return app;
|
|
83
|
+
},
|
|
84
|
+
bind,
|
|
85
|
+
requireProof,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=create-dbsc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-dbsc.js","sourceRoot":"","sources":["../../src/express/create-dbsc.ts"],"names":[],"mappings":"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"}
|
package/dist/express/index.d.ts
CHANGED
|
@@ -2,6 +2,15 @@ import type { Response, RequestHandler } from "express";
|
|
|
2
2
|
import { type DbscOptions, type StorageAdapter, type ProtectionTier, type SkippedEntry } from "../core/index.js";
|
|
3
3
|
export { requireBoundProof } from "./proof.js";
|
|
4
4
|
export type { RequireBoundProofOptions } from "./proof.js";
|
|
5
|
+
export { requireProof } from "./require-proof.js";
|
|
6
|
+
export { createDbsc } from "./create-dbsc.js";
|
|
7
|
+
export type { CreateDbscOptions, DbscKit, BindOptions } from "./create-dbsc.js";
|
|
8
|
+
/** Internal carrier so `requireProof()` can reach storage without re-passing it. */
|
|
9
|
+
export interface DbscInternal {
|
|
10
|
+
storage: StorageAdapter;
|
|
11
|
+
secure: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare const DBSC_INTERNAL: unique symbol;
|
|
5
14
|
export interface DbscExpressOptions extends DbscOptions {
|
|
6
15
|
secure?: boolean;
|
|
7
16
|
boundStatePath?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/express/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,QAAQ,EAAgB,cAAc,EAAE,MAAM,SAAS,CAAC;AAE/E,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/express/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,QAAQ,EAAgB,cAAc,EAAE,MAAM,SAAS,CAAC;AAE/E,OAAO,EAoBL,KAAK,WAAW,EAChB,KAAK,cAAc,EAEnB,KAAK,cAAc,EACnB,KAAK,YAAY,EAElB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,YAAY,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEhF,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;CACjB;AACD,eAAO,MAAM,aAAa,EAAE,OAAO,MAAgD,CAAC;AAYpF,MAAM,WAAW,kBAAmB,SAAQ,WAAW;IACrD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,MAAM;YACd,IAAI,EAAE,UAAU,CAAC;SAClB;KACF;CACF;AAuBD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,gHAAgH;IAChH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,WAAW,CAC/B,GAAG,EAAE,QAAQ,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,IAAI,CAAC,CAyCf;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,kBAAkB,GAAG,cAAc,CAwe7D"}
|
package/dist/express/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { handleRegistration, handleRefresh, handleBoundRegistration, handleBoundRefresh, issueChallenge, buildRegistrationHeader, buildChallengeHeader, readSessionResponseHeader, parseSessionSkippedHeader, REGISTRATION_HEADER, CHALLENGE_HEADER, LEGACY_REGISTRATION_HEADER, LEGACY_CHALLENGE_HEADER, NoopRateLimiter, emit, DbscProtocolError, DbscVerificationError, ErrorCodes, } from "../core/index.js";
|
|
1
|
+
import { handleRegistration, handleRefresh, handleBoundRegistration, handleBoundRefresh, issueChallenge, buildRegistrationHeader, buildChallengeHeader, readSessionResponseHeader, parseSessionSkippedHeader, REGISTRATION_HEADER, CHALLENGE_HEADER, LEGACY_REGISTRATION_HEADER, LEGACY_CHALLENGE_HEADER, NoopRateLimiter, emit, parseCookieHeader, DbscProtocolError, DbscVerificationError, ErrorCodes, } from "../core/index.js";
|
|
2
2
|
export { requireBoundProof } from "./proof.js";
|
|
3
|
+
export { requireProof } from "./require-proof.js";
|
|
4
|
+
export { createDbsc } from "./create-dbsc.js";
|
|
5
|
+
export const DBSC_INTERNAL = Symbol("dbsc-toolkit.express.internal");
|
|
3
6
|
const cookieNames = (secure) => ({
|
|
4
7
|
bound: secure ? "__Host-dbsc-session" : "dbsc-session",
|
|
5
8
|
reg: secure ? "__Host-dbsc-reg" : "dbsc-reg",
|
|
@@ -410,6 +413,9 @@ export function dbsc(opts) {
|
|
|
410
413
|
}
|
|
411
414
|
}
|
|
412
415
|
return async (req, res, next) => {
|
|
416
|
+
if (!req.cookies) {
|
|
417
|
+
req.cookies = parseCookieHeader(req.headers.cookie);
|
|
418
|
+
}
|
|
413
419
|
if (req.method === "POST" && req.path === registrationPath) {
|
|
414
420
|
await handleRegistrationRoute(req, res);
|
|
415
421
|
return;
|
|
@@ -448,6 +454,10 @@ export function dbsc(opts) {
|
|
|
448
454
|
]);
|
|
449
455
|
},
|
|
450
456
|
};
|
|
457
|
+
res.locals[DBSC_INTERNAL] = {
|
|
458
|
+
storage,
|
|
459
|
+
secure,
|
|
460
|
+
};
|
|
451
461
|
if (sessionId) {
|
|
452
462
|
const session = await storage.getSession(sessionId);
|
|
453
463
|
if (session) {
|