dbsc-toolkit 2.10.0 → 2.11.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 (38) hide show
  1. package/README.md +21 -7
  2. package/dist/koa/create-dbsc.d.ts +25 -0
  3. package/dist/koa/create-dbsc.d.ts.map +1 -0
  4. package/dist/koa/create-dbsc.js +32 -0
  5. package/dist/koa/create-dbsc.js.map +1 -0
  6. package/dist/koa/index.d.ts +19 -0
  7. package/dist/koa/index.d.ts.map +1 -0
  8. package/dist/koa/index.js +26 -0
  9. package/dist/koa/index.js.map +1 -0
  10. package/dist/koa/require-proof.d.ts +9 -0
  11. package/dist/koa/require-proof.d.ts.map +1 -0
  12. package/dist/koa/require-proof.js +69 -0
  13. package/dist/koa/require-proof.js.map +1 -0
  14. package/dist/nestjs/index.d.ts +45 -0
  15. package/dist/nestjs/index.d.ts.map +1 -0
  16. package/dist/nestjs/index.js +147 -0
  17. package/dist/nestjs/index.js.map +1 -0
  18. package/dist/node/create-dbsc.d.ts +29 -0
  19. package/dist/node/create-dbsc.d.ts.map +1 -0
  20. package/dist/node/create-dbsc.js +33 -0
  21. package/dist/node/create-dbsc.js.map +1 -0
  22. package/dist/node/index.d.ts +53 -0
  23. package/dist/node/index.d.ts.map +1 -0
  24. package/dist/node/index.js +412 -0
  25. package/dist/node/index.js.map +1 -0
  26. package/dist/node/require-proof.d.ts +17 -0
  27. package/dist/node/require-proof.d.ts.map +1 -0
  28. package/dist/node/require-proof.js +74 -0
  29. package/dist/node/require-proof.js.map +1 -0
  30. package/dist/sveltekit/index.d.ts +48 -0
  31. package/dist/sveltekit/index.d.ts.map +1 -0
  32. package/dist/sveltekit/index.js +318 -0
  33. package/dist/sveltekit/index.js.map +1 -0
  34. package/dist/sveltekit/require-proof.d.ts +15 -0
  35. package/dist/sveltekit/require-proof.d.ts.map +1 -0
  36. package/dist/sveltekit/require-proof.js +52 -0
  37. package/dist/sveltekit/require-proof.js.map +1 -0
  38. package/package.json +41 -2
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  <p align="center">
8
8
  <strong>Stop stolen session cookies from being replayed on another device.</strong><br>
9
- A language-neutral DBSC protocol spec plus a reference implementation for Node.js — with a Web Crypto polyfill so every browser is covered, not just Chrome.
9
+ Device Bound Session Credentials for Node.js — one framework-agnostic core with adapters for Express, Fastify, Hono, Next.js, NestJS, Koa, SvelteKit and raw <code>node:http</code>, plus a Web Crypto polyfill so every browser is covered, not just Chrome. A language-neutral protocol spec with a Node reference implementation.
10
10
  </p>
11
11
 
12
12
  <p align="center">
@@ -122,9 +122,23 @@ Load the polyfill in your HTML so non-Chromium browsers reach `tier: "bound"`:
122
122
 
123
123
  Full walk-through, failure modes, and migration timeline: **[docs/getting-started.md](./docs/getting-started.md)** and **[docs/integrating-existing-auth.md](./docs/integrating-existing-auth.md)**.
124
124
 
125
- ### Not on Express?
125
+ ### Any framework
126
126
 
127
- The protocol lives in a framework-agnostic core — plain functions plus a `StorageAdapter`, no HTTP-layer assumptions. The Express/Fastify/Hono/Next.js adapters are thin wrappers. Build on the core directly for any runtime:
127
+ The protocol lives in a framework-agnostic core — plain functions plus a `StorageAdapter`, no HTTP-layer assumptions. The adapters are thin wrappers; pick yours:
128
+
129
+ | Framework | Import |
130
+ |---|---|
131
+ | Express | `dbsc-toolkit/express` |
132
+ | Fastify | `dbsc-toolkit/fastify` |
133
+ | Hono (Node, Bun, Deno, Workers) | `dbsc-toolkit/hono` |
134
+ | Next.js (App Router) | `dbsc-toolkit/nextjs` |
135
+ | NestJS | `dbsc-toolkit/nestjs` |
136
+ | Koa | `dbsc-toolkit/koa` |
137
+ | SvelteKit | `dbsc-toolkit/sveltekit` |
138
+ | Any other server (raw `node:http`) | `dbsc-toolkit/node` |
139
+ | [Better Auth](https://better-auth.com) | `@dbsc-toolkit/better-auth` |
140
+
141
+ **No adapter for your framework? You can still use it.** Every adapter is a thin shell over the same core, so any HTTP framework on Node works — wire the core in directly:
128
142
 
129
143
  ```ts
130
144
  import {
@@ -136,7 +150,7 @@ import {
136
150
  } from "dbsc-toolkit";
137
151
  ```
138
152
 
139
- Complete raw-`http` example: [docs/adapters.md](./docs/adapters.md#writing-your-own-adapter).
153
+ The generic `dbsc-toolkit/node` adapter is exactly this over raw `node:http`. Complete example: [docs/adapters.md](./docs/adapters.md#writing-your-own-adapter).
140
154
 
141
155
  ## How it compares
142
156
 
@@ -186,7 +200,7 @@ The polyfill is on by default. To run native DBSC only (Chromium 145+, no `bound
186
200
 
187
201
  | Package | What it is |
188
202
  |---|---|
189
- | `dbsc-toolkit` | Core + Express/Fastify/Hono/Next.js adapters, memory/Redis/Postgres storage |
203
+ | `dbsc-toolkit` | Core + adapters for Express, Fastify, Hono, Next.js, NestJS, Koa, SvelteKit & raw `node:http`; memory/Redis/Postgres storage |
190
204
  | `dbsc-toolkit/client` | Browser SDK + Web Crypto polyfill |
191
205
  | [`@dbsc-toolkit/better-auth`](./packages/better-auth/) | First-class [Better Auth](https://better-auth.com) plugin — binds every sign-in method automatically |
192
206
 
@@ -211,7 +225,7 @@ The wire protocol is documented as a language-neutral spec in [`spec/`](./spec/)
211
225
  - [x] Per-request proof + body signing + replay cache
212
226
  - [x] Multi-subdomain binding (`cookieScope: "site"`)
213
227
  - [x] Better Auth plugin
214
- - [ ] Koa / NestJS adapters
228
+ - [x] NestJS, Koa, SvelteKit & generic `node:http` adapters
215
229
  - [ ] Bun / Deno native paths
216
230
  - [ ] Third-party security audit
217
231
 
@@ -220,7 +234,7 @@ The wire protocol is documented as a language-neutral spec in [`spec/`](./spec/)
220
234
  | Import | What it is |
221
235
  |---|---|
222
236
  | `dbsc-toolkit` | Core: types, crypto, protocol handlers, framework-agnostic |
223
- | `dbsc-toolkit/express` · `/fastify` · `/hono` · `/nextjs` | Framework adapters |
237
+ | `dbsc-toolkit/express` · `/fastify` · `/hono` · `/nextjs` · `/nestjs` · `/koa` · `/sveltekit` · `/node` | Framework adapters |
224
238
  | `dbsc-toolkit/client` | Browser SDK + polyfill |
225
239
  | `dbsc-toolkit/storage/{memory,redis,postgres}` | Storage adapters |
226
240
 
@@ -0,0 +1,25 @@
1
+ import type { Context, Middleware } from "koa";
2
+ import type Application from "koa";
3
+ import { type RequireProofOptions } from "../core/index.js";
4
+ import { type DbscKoaOptions } from "./index.js";
5
+ export interface CreateDbscOptions extends DbscKoaOptions {
6
+ /** Default session TTL (ms) for `bind()`. */
7
+ sessionTtl?: number;
8
+ }
9
+ export interface BindOptions {
10
+ userId: string;
11
+ namespace?: string;
12
+ }
13
+ export interface DbscKit {
14
+ /** Mount the dbsc middleware on the Koa app. */
15
+ install(app: Application): Application;
16
+ /** The raw dbsc middleware, for manual mounting. */
17
+ middleware(): Middleware;
18
+ /** Start a binding for an explicit session id. */
19
+ bind(ctx: Context, sessionId: string, opts: BindOptions): Promise<string>;
20
+ /** The route guard — requires a bound device + a per-request proof. */
21
+ requireProof(opts?: RequireProofOptions): Middleware;
22
+ }
23
+ /** Builds a configured DBSC kit for Koa. */
24
+ export declare function createDbsc(opts: CreateDbscOptions): DbscKit;
25
+ //# sourceMappingURL=create-dbsc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-dbsc.d.ts","sourceRoot":"","sources":["../../src/koa/create-dbsc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAC/C,OAAO,KAAK,WAAW,MAAM,KAAK,CAAC;AACnC,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAGpE,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACvD,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,gDAAgD;IAChD,OAAO,CAAC,GAAG,EAAE,WAAW,GAAG,WAAW,CAAC;IACvC,oDAAoD;IACpD,UAAU,IAAI,UAAU,CAAC;IACzB,kDAAkD;IAClD,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1E,uEAAuE;IACvE,YAAY,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,UAAU,CAAC;CACtD;AAED,4CAA4C;AAC5C,wBAAgB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CA6B3D"}
@@ -0,0 +1,32 @@
1
+ import { dbsc, bindSession } from "./index.js";
2
+ import { requireProof } from "./require-proof.js";
3
+ /** Builds a configured DBSC kit for Koa. */
4
+ export function createDbsc(opts) {
5
+ const secure = opts.secure ?? true;
6
+ const cookieScope = opts.cookieScope;
7
+ const cookieDomain = opts.cookieDomain;
8
+ const registrationPath = opts.registrationPath ?? "/dbsc/registration";
9
+ const middleware = dbsc(opts);
10
+ async function bind(ctx, sessionId, bindOpts) {
11
+ await bindSession(ctx, sessionId, opts.storage, {
12
+ userId: bindOpts.userId,
13
+ secure,
14
+ ...(cookieScope !== undefined && { cookieScope }),
15
+ ...(cookieDomain !== undefined && { cookieDomain }),
16
+ registrationPath,
17
+ ...(opts.registrationCookieTtl !== undefined && { registrationCookieTtl: opts.registrationCookieTtl }),
18
+ ...(opts.sessionTtl !== undefined && { sessionTtl: opts.sessionTtl }),
19
+ });
20
+ return sessionId;
21
+ }
22
+ return {
23
+ middleware: () => middleware,
24
+ install(app) {
25
+ app.use(middleware);
26
+ return app;
27
+ },
28
+ bind,
29
+ requireProof,
30
+ };
31
+ }
32
+ //# sourceMappingURL=create-dbsc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-dbsc.js","sourceRoot":"","sources":["../../src/koa/create-dbsc.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,WAAW,EAAuB,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAuBlD,4CAA4C;AAC5C,MAAM,UAAU,UAAU,CAAC,IAAuB;IAChD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;IACnC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACrC,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;IACvC,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,IAAI,oBAAoB,CAAC;IACvE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IAE9B,KAAK,UAAU,IAAI,CAAC,GAAY,EAAE,SAAiB,EAAE,QAAqB;QACxE,MAAM,WAAW,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE;YAC9C,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,MAAM;YACN,GAAG,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,CAAC;YACjD,GAAG,CAAC,YAAY,KAAK,SAAS,IAAI,EAAE,YAAY,EAAE,CAAC;YACnD,gBAAgB;YAChB,GAAG,CAAC,IAAI,CAAC,qBAAqB,KAAK,SAAS,IAAI,EAAE,qBAAqB,EAAE,IAAI,CAAC,qBAAqB,EAAE,CAAC;YACtG,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;SACtE,CAAC,CAAC;QACH,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,UAAU,EAAE,GAAG,EAAE,CAAC,UAAU;QAC5B,OAAO,CAAC,GAAgB;YACtB,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACpB,OAAO,GAAG,CAAC;QACb,CAAC;QACD,IAAI;QACJ,YAAY;KACb,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { Context, Middleware } from "koa";
2
+ import type { StorageAdapter } from "../core/index.js";
3
+ import { type DbscNodeOptions, type BindSessionOptions } from "../node/index.js";
4
+ export { requireProof } from "./require-proof.js";
5
+ export { createDbsc } from "./create-dbsc.js";
6
+ export type { CreateDbscOptions, DbscKit, BindOptions } from "./create-dbsc.js";
7
+ export type { DbscNodeSession as DbscKoaSession, BindSessionOptions } from "../node/index.js";
8
+ export interface DbscKoaOptions extends DbscNodeOptions {
9
+ }
10
+ /**
11
+ * Koa middleware. Koa's `ctx.req` / `ctx.res` are the raw `node:http` objects,
12
+ * so this delegates to the generic node handler: when it answers a DBSC
13
+ * protocol route it sets `ctx.respond = false` (the node handler already wrote
14
+ * the response). Otherwise the resolved session lands on `ctx.state.dbsc`.
15
+ */
16
+ export declare function dbsc(opts: DbscKoaOptions): Middleware;
17
+ /** Start a binding from a Koa login handler, then set your own `ctx.body`. */
18
+ export declare function bindSession(ctx: Context, sessionId: string, storage: StorageAdapter, opts: BindSessionOptions): Promise<void>;
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/koa/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAIL,KAAK,eAAe,EAEpB,KAAK,kBAAkB,EACxB,MAAM,kBAAkB,CAAC;AAE1B,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;AAChF,YAAY,EAAE,eAAe,IAAI,cAAc,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE9F,MAAM,WAAW,cAAe,SAAQ,eAAe;CAAG;AAE1D;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,CAWrD;AAED,8EAA8E;AAC9E,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,IAAI,CAAC,CAEf"}
@@ -0,0 +1,26 @@
1
+ import { dbsc as nodeDbsc, bindSession as nodeBindSession, getDbscSession, } from "../node/index.js";
2
+ export { requireProof } from "./require-proof.js";
3
+ export { createDbsc } from "./create-dbsc.js";
4
+ /**
5
+ * Koa middleware. Koa's `ctx.req` / `ctx.res` are the raw `node:http` objects,
6
+ * so this delegates to the generic node handler: when it answers a DBSC
7
+ * protocol route it sets `ctx.respond = false` (the node handler already wrote
8
+ * the response). Otherwise the resolved session lands on `ctx.state.dbsc`.
9
+ */
10
+ export function dbsc(opts) {
11
+ const handler = nodeDbsc(opts);
12
+ return async (ctx, next) => {
13
+ const handled = await handler(ctx.req, ctx.res);
14
+ if (handled) {
15
+ ctx.respond = false;
16
+ return;
17
+ }
18
+ ctx.state.dbsc = getDbscSession(ctx.req);
19
+ await next();
20
+ };
21
+ }
22
+ /** Start a binding from a Koa login handler, then set your own `ctx.body`. */
23
+ export async function bindSession(ctx, sessionId, storage, opts) {
24
+ await nodeBindSession(ctx.res, sessionId, storage, opts);
25
+ }
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/koa/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,IAAI,IAAI,QAAQ,EAChB,WAAW,IAAI,eAAe,EAC9B,cAAc,GAIf,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAM9C;;;;;GAKG;AACH,MAAM,UAAU,IAAI,CAAC,IAAoB;IACvC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QAChD,IAAI,OAAO,EAAE,CAAC;YACZ,GAAG,CAAC,OAAO,GAAG,KAAK,CAAC;YACpB,OAAO;QACT,CAAC;QACA,GAAG,CAAC,KAAgD,CAAC,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrF,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,GAAY,EACZ,SAAiB,EACjB,OAAuB,EACvB,IAAwB;IAExB,MAAM,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { Middleware } from "koa";
2
+ import { type RequireProofOptions } from "../core/index.js";
3
+ /**
4
+ * The route guard for Koa. Mount `dbsc()` first so the session is on
5
+ * `ctx.state.dbsc`. Reads the raw body from `ctx.request.rawBody` when a body
6
+ * parser populated it, else from the socket.
7
+ */
8
+ export declare function requireProof(opts?: RequireProofOptions): Middleware;
9
+ //# sourceMappingURL=require-proof.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-proof.d.ts","sourceRoot":"","sources":["../../src/koa/require-proof.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,UAAU,EAAE,MAAM,KAAK,CAAC;AAE/C,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,kBAAkB,CAAC;AAgB1B;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,GAAE,mBAAwB,GAAG,UAAU,CAmDvE"}
@@ -0,0 +1,69 @@
1
+ import { verifyBoundProof, noBindingReason, DbscVerificationError, } from "../core/index.js";
2
+ import { DBSC_INTERNAL } from "../node/index.js";
3
+ async function readRawBody(ctx) {
4
+ const rawBody = ctx.request.rawBody;
5
+ if (typeof rawBody === "string")
6
+ return new TextEncoder().encode(rawBody);
7
+ const req = ctx.req;
8
+ const cached = req["__dbscRawBody"];
9
+ if (Buffer.isBuffer(cached))
10
+ return new Uint8Array(cached);
11
+ const chunks = [];
12
+ for await (const chunk of req)
13
+ chunks.push(chunk);
14
+ const raw = Buffer.concat(chunks);
15
+ req["__dbscRawBody"] = raw;
16
+ return new Uint8Array(raw);
17
+ }
18
+ /**
19
+ * The route guard for Koa. Mount `dbsc()` first so the session is on
20
+ * `ctx.state.dbsc`. Reads the raw body from `ctx.request.rawBody` when a body
21
+ * parser populated it, else from the socket.
22
+ */
23
+ export function requireProof(opts = {}) {
24
+ return async (ctx, next) => {
25
+ const session = ctx.state.dbsc;
26
+ const tier = session?.tier ?? "none";
27
+ const skipped = session?.skipped ?? [];
28
+ if (!session?.sessionId || tier === "none") {
29
+ ctx.status = 403;
30
+ ctx.body = { error: "device-bound session required", currentTier: "none", reason: noBindingReason(skipped), skipped };
31
+ return;
32
+ }
33
+ const internal = session[DBSC_INTERNAL];
34
+ const storage = opts.storage ?? internal?.storage;
35
+ if (!storage) {
36
+ ctx.status = 500;
37
+ ctx.body = { error: "requireProof: storage unavailable — mount dbsc() before this route, or pass { storage }" };
38
+ return;
39
+ }
40
+ const allowDbscWithoutProof = opts.allowDbscWithoutProof ?? (internal?.boundEnabled === false ? true : undefined);
41
+ if (tier === "dbsc" && allowDbscWithoutProof) {
42
+ await next();
43
+ return;
44
+ }
45
+ const proofHeader = ctx.get("x-dbsc-bound-proof") || undefined;
46
+ try {
47
+ await verifyBoundProof({
48
+ sessionId: session.sessionId,
49
+ proofHeader,
50
+ method: ctx.method,
51
+ path: ctx.path,
52
+ signBody: true,
53
+ bodyBytes: await readRawBody(ctx),
54
+ ...(opts.timestampWindowMs !== undefined && { timestampWindowMs: opts.timestampWindowMs }),
55
+ ...(internal?.replayCache !== undefined && { replayCache: internal.replayCache }),
56
+ }, storage);
57
+ await next();
58
+ }
59
+ catch (err) {
60
+ if (err instanceof DbscVerificationError) {
61
+ ctx.status = 403;
62
+ ctx.body = { error: err.message, code: err.code };
63
+ return;
64
+ }
65
+ throw err;
66
+ }
67
+ };
68
+ }
69
+ //# sourceMappingURL=require-proof.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-proof.js","sourceRoot":"","sources":["../../src/koa/require-proof.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import { type DynamicModule, type NestModule, type MiddlewareConsumer, type CanActivate, type ExecutionContext } from "@nestjs/common";
2
+ import type { Response } from "express";
3
+ import { type RequireProofOptions } from "../core/index.js";
4
+ import { type DbscExpressOptions, type BindOptions } from "../express/index.js";
5
+ export { bindSession } from "../express/index.js";
6
+ export type { DbscExpressOptions as DbscNestOptions, BindOptions } from "../express/index.js";
7
+ /** DI token for the DBSC options passed to `DbscModule.forRoot()`. */
8
+ export declare const DBSC_OPTIONS: unique symbol;
9
+ /** Injectable wrapper around the Express kit's `bind()` — call it in your login controller. */
10
+ export declare class DbscService {
11
+ private readonly kit;
12
+ constructor(opts: DbscExpressOptions);
13
+ /** Start a binding for an explicit session id. */
14
+ bind(res: Response, sessionId: string, opts: BindOptions): Promise<string>;
15
+ }
16
+ /**
17
+ * Registers DBSC on a NestJS app (Express platform). It mounts the protocol
18
+ * middleware for every route and exposes `DbscService`:
19
+ *
20
+ * @Module({ imports: [DbscModule.forRoot({ storage })] })
21
+ * export class AppModule {}
22
+ */
23
+ export declare class DbscModule implements NestModule {
24
+ private readonly opts;
25
+ constructor(opts: DbscExpressOptions);
26
+ static forRoot(opts: DbscExpressOptions): DynamicModule;
27
+ configure(consumer: MiddlewareConsumer): void;
28
+ }
29
+ /**
30
+ * Zero-config route guard. Requires a bound device + a per-request proof:
31
+ *
32
+ * @UseGuards(DbscGuard)
33
+ * @Post("payment")
34
+ * pay() { ... }
35
+ *
36
+ * POST bodies are body-hashed, so a guarded POST must deliver raw bytes (set
37
+ * `rawBody: true` in `NestFactory.create` and disable the JSON parser on that
38
+ * route, or use a raw-body middleware). GET routes need no parser.
39
+ */
40
+ export declare class DbscGuard implements CanActivate {
41
+ canActivate(context: ExecutionContext): Promise<boolean>;
42
+ }
43
+ /** Builds a guard with options baked in (e.g. a storage override or timestamp window). */
44
+ export declare function createDbscGuard(opts: RequireProofOptions): new () => CanActivate;
45
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/nestjs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAW,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAIL,KAAK,kBAAkB,EAGvB,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,YAAY,EAAE,kBAAkB,IAAI,eAAe,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE9F,sEAAsE;AACtE,eAAO,MAAM,YAAY,eAAwC,CAAC;AAElE,+FAA+F;AAC/F,qBACa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAU;gBACI,IAAI,EAAE,kBAAkB;IAG1D,kDAAkD;IAClD,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;CAG3E;AAED;;;;;;GAMG;AACH,qBACa,UAAW,YAAW,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,kBAAkB;IAE3E,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,kBAAkB,GAAG,aAAa;IASvD,SAAS,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI;CAG9C;AAiDD;;;;;;;;;;GAUG;AACH,qBACa,SAAU,YAAW,WAAW;IACrC,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;CAK/D;AAED,0FAA0F;AAC1F,wBAAgB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,UAAU,WAAW,CAUhF"}
@@ -0,0 +1,147 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ var DbscModule_1;
14
+ import { Injectable, Module, Inject, ForbiddenException, InternalServerErrorException, } from "@nestjs/common";
15
+ import { verifyBoundProof, noBindingReason, DbscVerificationError, } from "../core/index.js";
16
+ import { dbsc, createDbsc, DBSC_INTERNAL, } from "../express/index.js";
17
+ export { bindSession } from "../express/index.js";
18
+ /** DI token for the DBSC options passed to `DbscModule.forRoot()`. */
19
+ export const DBSC_OPTIONS = Symbol("dbsc-toolkit.nestjs.options");
20
+ /** Injectable wrapper around the Express kit's `bind()` — call it in your login controller. */
21
+ let DbscService = class DbscService {
22
+ kit;
23
+ constructor(opts) {
24
+ this.kit = createDbsc(opts);
25
+ }
26
+ /** Start a binding for an explicit session id. */
27
+ bind(res, sessionId, opts) {
28
+ return this.kit.bind(res, sessionId, opts);
29
+ }
30
+ };
31
+ DbscService = __decorate([
32
+ Injectable(),
33
+ __param(0, Inject(DBSC_OPTIONS)),
34
+ __metadata("design:paramtypes", [Object])
35
+ ], DbscService);
36
+ export { DbscService };
37
+ /**
38
+ * Registers DBSC on a NestJS app (Express platform). It mounts the protocol
39
+ * middleware for every route and exposes `DbscService`:
40
+ *
41
+ * @Module({ imports: [DbscModule.forRoot({ storage })] })
42
+ * export class AppModule {}
43
+ */
44
+ let DbscModule = DbscModule_1 = class DbscModule {
45
+ opts;
46
+ constructor(opts) {
47
+ this.opts = opts;
48
+ }
49
+ static forRoot(opts) {
50
+ return {
51
+ module: DbscModule_1,
52
+ global: true,
53
+ providers: [{ provide: DBSC_OPTIONS, useValue: opts }, DbscService],
54
+ exports: [DBSC_OPTIONS, DbscService],
55
+ };
56
+ }
57
+ configure(consumer) {
58
+ consumer.apply(dbsc(this.opts)).forRoutes("*");
59
+ }
60
+ };
61
+ DbscModule = DbscModule_1 = __decorate([
62
+ Module({}),
63
+ __param(0, Inject(DBSC_OPTIONS)),
64
+ __metadata("design:paramtypes", [Object])
65
+ ], DbscModule);
66
+ export { DbscModule };
67
+ async function runProof(req, res, opts) {
68
+ const dbscLocals = res.locals.dbsc;
69
+ const tier = dbscLocals?.tier ?? "none";
70
+ const skipped = dbscLocals?.skipped ?? [];
71
+ if (!dbscLocals?.sessionId || tier === "none") {
72
+ throw new ForbiddenException({ error: "device-bound session required", currentTier: "none", reason: noBindingReason(skipped), skipped });
73
+ }
74
+ const internal = res.locals[DBSC_INTERNAL];
75
+ const storage = opts.storage ?? internal?.storage;
76
+ if (!storage) {
77
+ throw new InternalServerErrorException("requireProof: storage unavailable — import DbscModule.forRoot(...)");
78
+ }
79
+ const allowDbscWithoutProof = opts.allowDbscWithoutProof ?? (internal?.boundEnabled === false ? true : undefined);
80
+ if (tier === "dbsc" && allowDbscWithoutProof)
81
+ return;
82
+ let bodyBytes;
83
+ const raw = req.body;
84
+ if (raw instanceof Buffer)
85
+ bodyBytes = new Uint8Array(raw.buffer, raw.byteOffset, raw.byteLength);
86
+ else if (raw instanceof Uint8Array)
87
+ bodyBytes = raw;
88
+ else if (typeof raw === "string")
89
+ bodyBytes = new TextEncoder().encode(raw);
90
+ else
91
+ bodyBytes = new Uint8Array(0);
92
+ try {
93
+ await verifyBoundProof({
94
+ sessionId: dbscLocals.sessionId,
95
+ proofHeader: req.headers["x-dbsc-bound-proof"],
96
+ method: req.method,
97
+ path: req.path,
98
+ signBody: true,
99
+ bodyBytes,
100
+ ...(opts.timestampWindowMs !== undefined && { timestampWindowMs: opts.timestampWindowMs }),
101
+ ...(internal?.replayCache !== undefined && { replayCache: internal.replayCache }),
102
+ }, storage);
103
+ }
104
+ catch (err) {
105
+ if (err instanceof DbscVerificationError) {
106
+ throw new ForbiddenException({ error: err.message, code: err.code });
107
+ }
108
+ throw err;
109
+ }
110
+ }
111
+ /**
112
+ * Zero-config route guard. Requires a bound device + a per-request proof:
113
+ *
114
+ * @UseGuards(DbscGuard)
115
+ * @Post("payment")
116
+ * pay() { ... }
117
+ *
118
+ * POST bodies are body-hashed, so a guarded POST must deliver raw bytes (set
119
+ * `rawBody: true` in `NestFactory.create` and disable the JSON parser on that
120
+ * route, or use a raw-body middleware). GET routes need no parser.
121
+ */
122
+ let DbscGuard = class DbscGuard {
123
+ async canActivate(context) {
124
+ const http = context.switchToHttp();
125
+ await runProof(http.getRequest(), http.getResponse(), {});
126
+ return true;
127
+ }
128
+ };
129
+ DbscGuard = __decorate([
130
+ Injectable()
131
+ ], DbscGuard);
132
+ export { DbscGuard };
133
+ /** Builds a guard with options baked in (e.g. a storage override or timestamp window). */
134
+ export function createDbscGuard(opts) {
135
+ let ConfiguredDbscGuard = class ConfiguredDbscGuard {
136
+ async canActivate(context) {
137
+ const http = context.switchToHttp();
138
+ await runProof(http.getRequest(), http.getResponse(), opts);
139
+ return true;
140
+ }
141
+ };
142
+ ConfiguredDbscGuard = __decorate([
143
+ Injectable()
144
+ ], ConfiguredDbscGuard);
145
+ return ConfiguredDbscGuard;
146
+ }
147
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/nestjs/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,OAAO,EACL,UAAU,EACV,MAAM,EACN,MAAM,EACN,kBAAkB,EAClB,4BAA4B,GAM7B,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,qBAAqB,GAEtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,IAAI,EACJ,UAAU,EACV,aAAa,GAKd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlD,sEAAsE;AACtE,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,6BAA6B,CAAC,CAAC;AAElE,+FAA+F;AAExF,IAAM,WAAW,GAAjB,MAAM,WAAW;IACL,GAAG,CAAU;IAC9B,YAAkC,IAAwB;QACxD,IAAI,CAAC,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IACD,kDAAkD;IAClD,IAAI,CAAC,GAAa,EAAE,SAAiB,EAAE,IAAiB;QACtD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;CACF,CAAA;AATY,WAAW;IADvB,UAAU,EAAE;IAGE,WAAA,MAAM,CAAC,YAAY,CAAC,CAAA;;GAFtB,WAAW,CASvB;;AAED;;;;;;GAMG;AAEI,IAAM,UAAU,kBAAhB,MAAM,UAAU;IAC8B;IAAnD,YAAmD,IAAwB;QAAxB,SAAI,GAAJ,IAAI,CAAoB;IAAG,CAAC;IAE/E,MAAM,CAAC,OAAO,CAAC,IAAwB;QACrC,OAAO;YACL,MAAM,EAAE,YAAU;YAClB,MAAM,EAAE,IAAI;YACZ,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,WAAW,CAAC;YACnE,OAAO,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC;SACrC,CAAC;IACJ,CAAC;IAED,SAAS,CAAC,QAA4B;QACpC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACjD,CAAC;CACF,CAAA;AAfY,UAAU;IADtB,MAAM,CAAC,EAAE,CAAC;IAEI,WAAA,MAAM,CAAC,YAAY,CAAC,CAAA;;GADtB,UAAU,CAetB;;AAED,KAAK,UAAU,QAAQ,CAAC,GAAY,EAAE,GAAa,EAAE,IAAyB;IAC5E,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;IACnC,MAAM,IAAI,GAAG,UAAU,EAAE,IAAI,IAAI,MAAM,CAAC;IACxC,MAAM,OAAO,GAAG,UAAU,EAAE,OAAO,IAAI,EAAE,CAAC;IAC1C,IAAI,CAAC,UAAU,EAAE,SAAS,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QAC9C,MAAM,IAAI,kBAAkB,CAAC,EAAE,KAAK,EAAE,+BAA+B,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IAC3I,CAAC;IAED,MAAM,QAAQ,GAAI,GAAG,CAAC,MAAuC,CAAC,aAAa,CAA6B,CAAC;IACzG,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,QAAQ,EAAE,OAAO,CAAC;IAClD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,4BAA4B,CAAC,oEAAoE,CAAC,CAAC;IAC/G,CAAC;IAED,MAAM,qBAAqB,GACzB,IAAI,CAAC,qBAAqB,IAAI,CAAC,QAAQ,EAAE,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACtF,IAAI,IAAI,KAAK,MAAM,IAAI,qBAAqB;QAAE,OAAO;IAErD,IAAI,SAAqB,CAAC;IAC1B,MAAM,GAAG,GAAG,GAAG,CAAC,IAAe,CAAC;IAChC,IAAI,GAAG,YAAY,MAAM;QAAE,SAAS,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;SAC7F,IAAI,GAAG,YAAY,UAAU;QAAE,SAAS,GAAG,GAAG,CAAC;SAC/C,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,SAAS,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;;QACvE,SAAS,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAEnC,IAAI,CAAC;QACH,MAAM,gBAAgB,CACpB;YACE,SAAS,EAAE,UAAU,CAAC,SAAS;YAC/B,WAAW,EAAE,GAAG,CAAC,OAAO,CAAC,oBAAoB,CAAuB;YACpE,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,QAAQ,EAAE,IAAI;YACd,SAAS;YACT,GAAG,CAAC,IAAI,CAAC,iBAAiB,KAAK,SAAS,IAAI,EAAE,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC1F,GAAG,CAAC,QAAQ,EAAE,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC;SAClF,EACD,OAAO,CACR,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,qBAAqB,EAAE,CAAC;YACzC,MAAM,IAAI,kBAAkB,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AAEI,IAAM,SAAS,GAAf,MAAM,SAAS;IACpB,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;QACpC,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAW,EAAE,IAAI,CAAC,WAAW,EAAY,EAAE,EAAE,CAAC,CAAC;QAC7E,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AANY,SAAS;IADrB,UAAU,EAAE;GACA,SAAS,CAMrB;;AAED,0FAA0F;AAC1F,MAAM,UAAU,eAAe,CAAC,IAAyB;IAEvD,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;QACvB,KAAK,CAAC,WAAW,CAAC,OAAyB;YACzC,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;YACpC,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAW,EAAE,IAAI,CAAC,WAAW,EAAY,EAAE,IAAI,CAAC,CAAC;YAC/E,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAAA;IANK,mBAAmB;QADxB,UAAU,EAAE;OACP,mBAAmB,CAMxB;IACD,OAAO,mBAAmB,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import { type RequireProofOptions } from "../core/index.js";
3
+ import { type DbscNodeOptions, type DbscNodeHandler, type DbscNodeSession } from "./index.js";
4
+ import { type NodeProofGuard } from "./require-proof.js";
5
+ export interface CreateDbscOptions extends DbscNodeOptions {
6
+ /** Default session TTL (ms) for `bind()`. */
7
+ sessionTtl?: number;
8
+ }
9
+ export interface BindOptions {
10
+ userId: string;
11
+ namespace?: string;
12
+ }
13
+ export interface DbscKit {
14
+ /** The dbsc handler — run it first in your request pipeline. Returns true when it answered a protocol route. */
15
+ handler(): DbscNodeHandler;
16
+ /** Read the resolved session off a request the handler has processed. */
17
+ getSession(req: IncomingMessage): DbscNodeSession | undefined;
18
+ /** Start a binding for an explicit session id (e.g. your server-session id). */
19
+ bind(res: ServerResponse, sessionId: string, opts: BindOptions): Promise<string>;
20
+ /** The route guard — requires a bound device + a per-request proof. */
21
+ requireProof(opts?: RequireProofOptions): NodeProofGuard;
22
+ }
23
+ /**
24
+ * Builds a configured DBSC kit for raw `node:http`. There is no `install()`
25
+ * because raw http has no router — wire `handler()` at the top of your request
26
+ * listener and branch on its boolean return.
27
+ */
28
+ export declare function createDbsc(opts: CreateDbscOptions): DbscKit;
29
+ //# sourceMappingURL=create-dbsc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-dbsc.d.ts","sourceRoot":"","sources":["../../src/node/create-dbsc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEvE,MAAM,WAAW,iBAAkB,SAAQ,eAAe;IACxD,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,gHAAgH;IAChH,OAAO,IAAI,eAAe,CAAC;IAC3B,yEAAyE;IACzE,UAAU,CAAC,GAAG,EAAE,eAAe,GAAG,eAAe,GAAG,SAAS,CAAC;IAC9D,gFAAgF;IAChF,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACjF,uEAAuE;IACvE,YAAY,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,cAAc,CAAC;CAC1D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CA0B3D"}
@@ -0,0 +1,33 @@
1
+ import { dbsc, bindSession, getDbscSession, } from "./index.js";
2
+ import { requireProof } from "./require-proof.js";
3
+ /**
4
+ * Builds a configured DBSC kit for raw `node:http`. There is no `install()`
5
+ * because raw http has no router — wire `handler()` at the top of your request
6
+ * listener and branch on its boolean return.
7
+ */
8
+ export function createDbsc(opts) {
9
+ const secure = opts.secure ?? true;
10
+ const cookieScope = opts.cookieScope;
11
+ const cookieDomain = opts.cookieDomain;
12
+ const registrationPath = opts.registrationPath ?? "/dbsc/registration";
13
+ const handler = dbsc(opts);
14
+ async function bind(res, sessionId, bindOpts) {
15
+ await bindSession(res, sessionId, opts.storage, {
16
+ userId: bindOpts.userId,
17
+ secure,
18
+ ...(cookieScope !== undefined && { cookieScope }),
19
+ ...(cookieDomain !== undefined && { cookieDomain }),
20
+ registrationPath,
21
+ ...(opts.registrationCookieTtl !== undefined && { registrationCookieTtl: opts.registrationCookieTtl }),
22
+ ...(opts.sessionTtl !== undefined && { sessionTtl: opts.sessionTtl }),
23
+ });
24
+ return sessionId;
25
+ }
26
+ return {
27
+ handler: () => handler,
28
+ getSession: getDbscSession,
29
+ bind,
30
+ requireProof,
31
+ };
32
+ }
33
+ //# sourceMappingURL=create-dbsc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-dbsc.js","sourceRoot":"","sources":["../../src/node/create-dbsc.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,IAAI,EACJ,WAAW,EACX,cAAc,GAIf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAuB,MAAM,oBAAoB,CAAC;AAuBvE;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAAuB;IAChD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;IACnC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACrC,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;IACvC,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,IAAI,oBAAoB,CAAC;IACvE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IAE3B,KAAK,UAAU,IAAI,CAAC,GAAmB,EAAE,SAAiB,EAAE,QAAqB;QAC/E,MAAM,WAAW,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE;YAC9C,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,MAAM;YACN,GAAG,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,CAAC;YACjD,GAAG,CAAC,YAAY,KAAK,SAAS,IAAI,EAAE,YAAY,EAAE,CAAC;YACnD,gBAAgB;YAChB,GAAG,CAAC,IAAI,CAAC,qBAAqB,KAAK,SAAS,IAAI,EAAE,qBAAqB,EAAE,IAAI,CAAC,qBAAqB,EAAE,CAAC;YACtG,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;SACtE,CAAC,CAAC;QACH,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO;QACtB,UAAU,EAAE,cAAc;QAC1B,IAAI;QACJ,YAAY;KACb,CAAC;AACJ,CAAC"}
@@ -0,0 +1,53 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import { type DbscOptions, type StorageAdapter, type ProofReplayCache, type ProtectionTier, type SkippedEntry, type CookieScope } from "../core/index.js";
3
+ export { requireProof } from "./require-proof.js";
4
+ export { createDbsc } from "./create-dbsc.js";
5
+ export type { CreateDbscOptions, DbscKit, BindOptions } from "./create-dbsc.js";
6
+ /** Internal carrier so `requireProof()` can reach storage without re-passing it. */
7
+ export interface DbscInternal {
8
+ storage: StorageAdapter;
9
+ secure: boolean;
10
+ /** When false, `requireProof()` auto-relaxes the native dbsc tier. */
11
+ boundEnabled: boolean;
12
+ replayCache?: ProofReplayCache;
13
+ }
14
+ export declare const DBSC_INTERNAL: unique symbol;
15
+ export interface DbscNodeOptions extends DbscOptions {
16
+ secure?: boolean;
17
+ boundStatePath?: string;
18
+ boundChallengePath?: string;
19
+ boundRegistrationPath?: string;
20
+ boundRefreshPath?: string;
21
+ }
22
+ export interface DbscNodeSession {
23
+ sessionId: string | null;
24
+ tier: ProtectionTier;
25
+ skipped: SkippedEntry[];
26
+ revoke: () => Promise<void>;
27
+ }
28
+ /**
29
+ * The dbsc handler for raw `node:http`. Call it first in your request
30
+ * pipeline: it returns `true` when it has fully answered a DBSC protocol route
31
+ * (the response is ended — stop), and `false` otherwise, having attached the
32
+ * resolved session to the request. Read it back with `getDbscSession(req)`.
33
+ */
34
+ export type DbscNodeHandler = (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
35
+ /** Reads the session the `dbsc()` handler attached to this request. */
36
+ export declare function getDbscSession(req: IncomingMessage): DbscNodeSession | undefined;
37
+ /** Reads and JSON-parses the raw request body. Returns `{}` on empty/invalid. */
38
+ export declare function readJsonBody(req: IncomingMessage): Promise<Record<string, unknown>>;
39
+ export interface BindSessionOptions {
40
+ userId: string;
41
+ /** Match the value passed to dbsc({ secure }). Defaults true. */
42
+ secure?: boolean;
43
+ /** Match the value passed to dbsc({ cookieScope }). Defaults "host". */
44
+ cookieScope?: CookieScope;
45
+ /** Match the value passed to dbsc({ cookieDomain }). Required for cookieScope: "site". */
46
+ cookieDomain?: string;
47
+ registrationPath?: string;
48
+ registrationCookieTtl?: number;
49
+ sessionTtl?: number;
50
+ }
51
+ export declare function bindSession(res: ServerResponse, sessionId: string, storage: StorageAdapter, opts: BindSessionOptions): Promise<void>;
52
+ export declare function dbsc(opts: DbscNodeOptions): DbscNodeHandler;
53
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAwBL,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAC;AAE1B,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;IAChB,sEAAsE;IACtE,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,gBAAgB,CAAC;CAChC;AACD,eAAO,MAAM,aAAa,EAAE,OAAO,MAA6C,CAAC;AAejF,MAAM,WAAW,eAAgB,SAAQ,WAAW;IAClD,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,eAAe;IAC9B,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;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE9F,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG,eAAe,GAAG,SAAS,CAEhF;AAmED,iFAAiF;AACjF,wBAAsB,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAiBzF;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wEAAwE;IACxE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,0FAA0F;IAC1F,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,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,cAAc,EACnB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,IAAI,CAAC,CAsCf;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,eAAe,GAAG,eAAe,CAwT3D"}