dbsc-toolkit 2.6.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 +12 -5
- package/dist/core/crypto/jwk.js +3 -1
- package/dist/core/crypto/jwk.js.map +1 -1
- package/dist/core/protocol/cookies.d.ts.map +1 -1
- package/dist/core/protocol/cookies.js +3 -1
- package/dist/core/protocol/cookies.js.map +1 -1
- package/dist/express/create-dbsc.d.ts +6 -1
- package/dist/express/create-dbsc.d.ts.map +1 -1
- package/dist/express/create-dbsc.js +36 -5
- package/dist/express/create-dbsc.js.map +1 -1
- package/dist/fastify/create-dbsc.d.ts +4 -1
- package/dist/fastify/create-dbsc.d.ts.map +1 -1
- package/dist/fastify/create-dbsc.js +30 -4
- package/dist/fastify/create-dbsc.js.map +1 -1
- package/dist/hono/create-dbsc.d.ts +4 -1
- package/dist/hono/create-dbsc.d.ts.map +1 -1
- package/dist/hono/create-dbsc.js +31 -4
- package/dist/hono/create-dbsc.js.map +1 -1
- package/dist/nextjs/create-dbsc.d.ts +12 -1
- package/dist/nextjs/create-dbsc.d.ts.map +1 -1
- package/dist/nextjs/create-dbsc.js +27 -4
- package/dist/nextjs/create-dbsc.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,8 +42,8 @@ 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
|
|
@@ -127,7 +127,7 @@ app.post("/logout", async (req, res) => {
|
|
|
127
127
|
|
|
128
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.
|
|
129
129
|
|
|
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. Per-system recipes: [docs/integration-recipes.md](./docs/integration-recipes.md).
|
|
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).
|
|
131
131
|
|
|
132
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).
|
|
133
133
|
|
|
@@ -162,13 +162,20 @@ Tree-shaking eliminates anything you don't import. Using Koa, Hapi, raw `http`,
|
|
|
162
162
|
|
|
163
163
|
## Protection tiers
|
|
164
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
|
+
|
|
165
167
|
| Tier | Mechanism | Protects against |
|
|
166
168
|
|------|-----------|------------------|
|
|
167
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 |
|
|
168
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. |
|
|
169
|
-
| `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.
|
|
170
177
|
|
|
171
|
-
|
|
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).
|
|
172
179
|
|
|
173
180
|
## Going deeper
|
|
174
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"}
|
|
@@ -1 +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,
|
|
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"}
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
* middlewares read DBSC cookies without depending on `cookie-parser`.
|
|
4
4
|
*/
|
|
5
5
|
export function parseCookieHeader(header) {
|
|
6
|
-
|
|
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);
|
|
7
9
|
if (!header)
|
|
8
10
|
return out;
|
|
9
11
|
for (const part of header.split(";")) {
|
|
@@ -1 +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,MAAM,GAAG,GAA2B,
|
|
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"}
|
|
@@ -11,7 +11,12 @@ export interface CreateDbscOptions extends DbscExpressOptions {
|
|
|
11
11
|
}
|
|
12
12
|
export interface BindOptions {
|
|
13
13
|
userId: string;
|
|
14
|
-
/**
|
|
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
|
+
*/
|
|
15
20
|
deviceHint?: string;
|
|
16
21
|
/** Namespace to scope derived ids. */
|
|
17
22
|
namespace?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-dbsc.d.ts","sourceRoot":"","sources":["../../src/express/create-dbsc.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,KAAK,OAAO,
|
|
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"}
|
|
@@ -1,8 +1,32 @@
|
|
|
1
1
|
import express from "express";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import {
|
|
3
|
+
import { randomBytes } from "node:crypto";
|
|
4
|
+
import { deriveSessionId, parseCookieHeader } from "../core/index.js";
|
|
4
5
|
import { dbsc, bindSession } from "./index.js";
|
|
5
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
|
+
}
|
|
6
30
|
/**
|
|
7
31
|
* Builds a configured DBSC kit. Storage, `secure`, TTLs, rate limiter and
|
|
8
32
|
* telemetry are set once here; `install()`, `bind()` and `requireProof()` all
|
|
@@ -17,13 +41,20 @@ export function createDbsc(opts) {
|
|
|
17
41
|
const middleware = dbsc(opts);
|
|
18
42
|
async function bind(res, a, b) {
|
|
19
43
|
const bindOpts = typeof a === "string" ? b : a;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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({
|
|
23
53
|
userId: bindOpts.userId,
|
|
24
|
-
|
|
54
|
+
deviceHint,
|
|
25
55
|
...(bindOpts.namespace !== undefined && { namespace: bindOpts.namespace }),
|
|
26
56
|
});
|
|
57
|
+
}
|
|
27
58
|
await bindSession(res, sessionId, opts.storage, {
|
|
28
59
|
userId: bindOpts.userId,
|
|
29
60
|
secure,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-dbsc.js","sourceRoot":"","sources":["../../src/express/create-dbsc.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"create-dbsc.js","sourceRoot":"","sources":["../../src/express/create-dbsc.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,10 @@ export interface CreateDbscOptions extends DbscFastifyOptions {
|
|
|
7
7
|
}
|
|
8
8
|
export interface BindOptions {
|
|
9
9
|
userId: string;
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Manual per-device value. Optional — when omitted on the no-sessionId
|
|
12
|
+
* (JWT) path, the kit manages a `__Host-dbsc-device` cookie itself.
|
|
13
|
+
*/
|
|
11
14
|
deviceHint?: string;
|
|
12
15
|
/** Namespace to scope derived ids. */
|
|
13
16
|
namespace?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-dbsc.d.ts","sourceRoot":"","sources":["../../src/fastify/create-dbsc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"create-dbsc.d.ts","sourceRoot":"","sources":["../../src/fastify/create-dbsc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AAEzF,OAAO,EAAmB,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAqB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAwBxE,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,mEAAmE;IACnE,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC5D,iFAAiF;IACjF,IAAI,CAAC,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACjF,IAAI,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9D,+CAA+C;IAC/C,YAAY,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,0BAA0B,CAAC;CACtE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAyC3D"}
|
|
@@ -1,6 +1,27 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
1
2
|
import { deriveSessionId } from "../core/index.js";
|
|
2
3
|
import { dbsc, bindSession } from "./index.js";
|
|
3
4
|
import { requireProof } from "./require-proof.js";
|
|
5
|
+
const DEVICE_COOKIE_TTL_SEC = 365 * 24 * 60 * 60;
|
|
6
|
+
/**
|
|
7
|
+
* Returns a stable per-device value for the JWT `bind()` path: reads the
|
|
8
|
+
* `__Host-dbsc-device` cookie, or mints + sets one if absent.
|
|
9
|
+
*/
|
|
10
|
+
function resolveDeviceHint(reply, secure) {
|
|
11
|
+
const name = secure ? "__Host-dbsc-device" : "dbsc-device";
|
|
12
|
+
const existing = reply.request.cookies?.[name];
|
|
13
|
+
if (existing)
|
|
14
|
+
return existing;
|
|
15
|
+
const value = randomBytes(16).toString("hex");
|
|
16
|
+
reply.setCookie(name, value, {
|
|
17
|
+
httpOnly: true,
|
|
18
|
+
secure,
|
|
19
|
+
sameSite: "lax",
|
|
20
|
+
path: "/",
|
|
21
|
+
maxAge: DEVICE_COOKIE_TTL_SEC,
|
|
22
|
+
});
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
4
25
|
/**
|
|
5
26
|
* Builds a configured DBSC kit for Fastify. The static client SDK is not
|
|
6
27
|
* mounted by `install()` — serve `dist/client/` yourself if you have a frontend.
|
|
@@ -10,13 +31,18 @@ export function createDbsc(opts) {
|
|
|
10
31
|
const registrationPath = opts.registrationPath ?? "/dbsc/registration";
|
|
11
32
|
async function bind(reply, a, b) {
|
|
12
33
|
const bindOpts = typeof a === "string" ? b : a;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
34
|
+
let sessionId;
|
|
35
|
+
if (typeof a === "string") {
|
|
36
|
+
sessionId = a;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const deviceHint = bindOpts.deviceHint ?? resolveDeviceHint(reply, secure);
|
|
40
|
+
sessionId = await deriveSessionId({
|
|
16
41
|
userId: bindOpts.userId,
|
|
17
|
-
|
|
42
|
+
deviceHint,
|
|
18
43
|
...(bindOpts.namespace !== undefined && { namespace: bindOpts.namespace }),
|
|
19
44
|
});
|
|
45
|
+
}
|
|
20
46
|
await bindSession(reply, sessionId, opts.storage, {
|
|
21
47
|
userId: bindOpts.userId,
|
|
22
48
|
secure,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-dbsc.js","sourceRoot":"","sources":["../../src/fastify/create-dbsc.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAA4B,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,WAAW,EAA2B,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"create-dbsc.js","sourceRoot":"","sources":["../../src/fastify/create-dbsc.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,10 @@ export interface CreateDbscOptions extends DbscHonoOptions {
|
|
|
7
7
|
}
|
|
8
8
|
export interface BindOptions {
|
|
9
9
|
userId: string;
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Manual per-device value. Optional — when omitted on the no-sessionId
|
|
12
|
+
* (JWT) path, the kit manages a `__Host-dbsc-device` cookie itself.
|
|
13
|
+
*/
|
|
11
14
|
deviceHint?: string;
|
|
12
15
|
/** Namespace to scope derived ids. */
|
|
13
16
|
namespace?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-dbsc.d.ts","sourceRoot":"","sources":["../../src/hono/create-dbsc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"create-dbsc.d.ts","sourceRoot":"","sources":["../../src/hono/create-dbsc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAG7D,OAAO,EAAmB,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAwBrE,MAAM,WAAW,iBAAkB,SAAQ,eAAe;IACxD,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,iDAAiD;IACjD,OAAO,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,oDAAoD;IACpD,UAAU,IAAI,iBAAiB,CAAC;IAChC,iFAAiF;IACjF,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxE,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,uEAAuE;IACvE,YAAY,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,iBAAiB,CAAC;CAC7D;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAuC3D"}
|
package/dist/hono/create-dbsc.js
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
|
+
import { getCookie, setCookie } from "hono/cookie";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
1
3
|
import { deriveSessionId } from "../core/index.js";
|
|
2
4
|
import { dbsc, bindSession } from "./index.js";
|
|
3
5
|
import { requireProof } from "./require-proof.js";
|
|
6
|
+
const DEVICE_COOKIE_TTL_SEC = 365 * 24 * 60 * 60;
|
|
7
|
+
/**
|
|
8
|
+
* Returns a stable per-device value for the JWT `bind()` path: reads the
|
|
9
|
+
* `__Host-dbsc-device` cookie, or mints + sets one if absent.
|
|
10
|
+
*/
|
|
11
|
+
function resolveDeviceHint(c, secure) {
|
|
12
|
+
const name = secure ? "__Host-dbsc-device" : "dbsc-device";
|
|
13
|
+
const existing = getCookie(c, name);
|
|
14
|
+
if (existing)
|
|
15
|
+
return existing;
|
|
16
|
+
const value = randomBytes(16).toString("hex");
|
|
17
|
+
setCookie(c, name, value, {
|
|
18
|
+
httpOnly: true,
|
|
19
|
+
secure,
|
|
20
|
+
sameSite: "Lax",
|
|
21
|
+
path: "/",
|
|
22
|
+
maxAge: DEVICE_COOKIE_TTL_SEC,
|
|
23
|
+
});
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
4
26
|
/**
|
|
5
27
|
* Builds a configured DBSC kit for Hono. The static client SDK is not mounted
|
|
6
28
|
* by `install()` — serve `dist/client/` with your runtime's static handler.
|
|
@@ -11,13 +33,18 @@ export function createDbsc(opts) {
|
|
|
11
33
|
const middleware = dbsc(opts);
|
|
12
34
|
async function bind(c, a, b) {
|
|
13
35
|
const bindOpts = typeof a === "string" ? b : a;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
36
|
+
let sessionId;
|
|
37
|
+
if (typeof a === "string") {
|
|
38
|
+
sessionId = a;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const deviceHint = bindOpts.deviceHint ?? resolveDeviceHint(c, secure);
|
|
42
|
+
sessionId = await deriveSessionId({
|
|
17
43
|
userId: bindOpts.userId,
|
|
18
|
-
|
|
44
|
+
deviceHint,
|
|
19
45
|
...(bindOpts.namespace !== undefined && { namespace: bindOpts.namespace }),
|
|
20
46
|
});
|
|
47
|
+
}
|
|
21
48
|
await bindSession(c, sessionId, opts.storage, {
|
|
22
49
|
userId: bindOpts.userId,
|
|
23
50
|
secure,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-dbsc.js","sourceRoot":"","sources":["../../src/hono/create-dbsc.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAA4B,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,WAAW,EAAwB,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"create-dbsc.js","sourceRoot":"","sources":["../../src/hono/create-dbsc.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,eAAe,EAA4B,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,WAAW,EAAwB,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,qBAAqB,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAEjD;;;GAGG;AACH,SAAS,iBAAiB,CAAC,CAAU,EAAE,MAAe;IACpD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,aAAa,CAAC;IAC3D,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACpC,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE;QACxB,QAAQ,EAAE,IAAI;QACd,MAAM;QACN,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,GAAG;QACT,MAAM,EAAE,qBAAqB;KAC9B,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC;AA8BD;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAuB;IAChD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;IACnC,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,IAAI,oBAAoB,CAAC;IACvE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IAE9B,KAAK,UAAU,IAAI,CAAC,CAAU,EAAE,CAAuB,EAAE,CAAe;QACtE,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,CAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,IAAI,SAAiB,CAAC;QACtB,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1B,SAAS,GAAG,CAAC,CAAC;QAChB,CAAC;aAAM,CAAC;YACN,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,IAAI,iBAAiB,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YACvE,SAAS,GAAG,MAAM,eAAe,CAAC;gBAChC,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,UAAU;gBACV,GAAG,CAAC,QAAQ,CAAC,SAAS,KAAK,SAAS,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC;aAC3E,CAAC,CAAC;QACL,CAAC;QACD,MAAM,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE;YAC5C,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,MAAM;YACN,gBAAgB;YAChB,GAAG,CAAC,IAAI,CAAC,qBAAqB,KAAK,SAAS,IAAI;gBAC9C,qBAAqB,EAAE,IAAI,CAAC,qBAAqB;aAClD,CAAC;YACF,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,GAAS;YACf,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACpB,OAAO,GAAG,CAAC;QACb,CAAC;QACD,IAAI;QACJ,YAAY;KACb,CAAC;AACJ,CAAC"}
|
|
@@ -8,8 +8,19 @@ export interface CreateDbscOptions extends DbscNextOptions {
|
|
|
8
8
|
}
|
|
9
9
|
export interface BindOptions {
|
|
10
10
|
userId: string;
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Manual per-device value. Optional — on the no-sessionId (JWT) path, pass
|
|
13
|
+
* `req` (below) instead and the kit manages a `__Host-dbsc-device` cookie
|
|
14
|
+
* itself. Pass `deviceHint` only to control device identity yourself.
|
|
15
|
+
*/
|
|
12
16
|
deviceHint?: string;
|
|
17
|
+
/**
|
|
18
|
+
* The request, for the no-sessionId (JWT) path. When given, the kit
|
|
19
|
+
* reads/sets a `__Host-dbsc-device` cookie so each browser binds
|
|
20
|
+
* independently. Without it (and without `deviceHint`), the derived id is
|
|
21
|
+
* userId-only — unsafe for a user with two browsers.
|
|
22
|
+
*/
|
|
23
|
+
req?: NextRequest;
|
|
13
24
|
/** Namespace to scope derived ids. */
|
|
14
25
|
namespace?: string;
|
|
15
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-dbsc.d.ts","sourceRoot":"","sources":["../../src/nextjs/create-dbsc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"create-dbsc.d.ts","sourceRoot":"","sources":["../../src/nextjs/create-dbsc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAK9C,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAgB,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAErG,MAAM,WAAW,iBAAkB,SAAQ,eAAe;IACxD,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,+CAA+C;IAC/C,UAAU,IAAI,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAC1D,iFAAiF;IACjF,IAAI,CAAC,GAAG,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/E,IAAI,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5D,oDAAoD;IACpD,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC3E,6DAA6D;IAC7D,YAAY,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAC3F;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CA4D3D"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
1
2
|
import { deriveSessionId } from "../core/index.js";
|
|
3
|
+
const DEVICE_COOKIE_TTL_SEC = 365 * 24 * 60 * 60;
|
|
2
4
|
import { createDbscMiddleware, bindSession, getDbscSession, } from "./index.js";
|
|
3
5
|
import { requireProof } from "./require-proof.js";
|
|
4
6
|
/**
|
|
@@ -10,15 +12,36 @@ export function createDbsc(opts) {
|
|
|
10
12
|
const secure = opts.secure ?? true;
|
|
11
13
|
const registrationPath = opts.registrationPath ?? "/dbsc/registration";
|
|
12
14
|
const mw = createDbscMiddleware(opts);
|
|
15
|
+
function resolveDeviceHint(req, res) {
|
|
16
|
+
const name = secure ? "__Host-dbsc-device" : "dbsc-device";
|
|
17
|
+
const existing = req.cookies.get(name)?.value;
|
|
18
|
+
if (existing)
|
|
19
|
+
return existing;
|
|
20
|
+
const value = randomBytes(16).toString("hex");
|
|
21
|
+
res.cookies.set(name, value, {
|
|
22
|
+
httpOnly: true,
|
|
23
|
+
secure,
|
|
24
|
+
sameSite: "lax",
|
|
25
|
+
path: "/",
|
|
26
|
+
maxAge: DEVICE_COOKIE_TTL_SEC,
|
|
27
|
+
});
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
13
30
|
async function bind(res, a, b) {
|
|
14
31
|
const bindOpts = typeof a === "string" ? b : a;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
32
|
+
let sessionId;
|
|
33
|
+
if (typeof a === "string") {
|
|
34
|
+
sessionId = a;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
const deviceHint = bindOpts.deviceHint ??
|
|
38
|
+
(bindOpts.req ? resolveDeviceHint(bindOpts.req, res) : undefined);
|
|
39
|
+
sessionId = await deriveSessionId({
|
|
18
40
|
userId: bindOpts.userId,
|
|
19
|
-
...(
|
|
41
|
+
...(deviceHint !== undefined && { deviceHint }),
|
|
20
42
|
...(bindOpts.namespace !== undefined && { namespace: bindOpts.namespace }),
|
|
21
43
|
});
|
|
44
|
+
}
|
|
22
45
|
await bindSession(res, sessionId, opts.storage, {
|
|
23
46
|
userId: bindOpts.userId,
|
|
24
47
|
secure,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-dbsc.js","sourceRoot":"","sources":["../../src/nextjs/create-dbsc.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"create-dbsc.js","sourceRoot":"","sources":["../../src/nextjs/create-dbsc.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dbsc-toolkit",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.1",
|
|
4
4
|
"description": "Server-side Device Bound Session Credentials (DBSC) for Node.js plus a Web Crypto polyfill for Firefox, Safari, and older Chromium. Cookie-theft protection on every modern browser.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|