@blamejs/core 0.7.18 → 0.7.19
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/CHANGELOG.md +425 -423
- package/README.md +150 -150
- package/bin/blamejs.js +0 -0
- package/index.js +310 -308
- package/lib/api-key.js +660 -660
- package/lib/api-snapshot.js +338 -338
- package/lib/app-shutdown.js +385 -385
- package/lib/app.js +365 -365
- package/lib/archive.js +250 -250
- package/lib/atomic-file.js +544 -544
- package/lib/audit-chain.js +177 -177
- package/lib/audit-sign.js +344 -344
- package/lib/audit-tools.js +677 -677
- package/lib/audit.js +766 -766
- package/lib/auth/jwt-external.js +365 -0
- package/lib/auth/jwt.js +337 -311
- package/lib/auth/lockout.js +436 -436
- package/lib/auth/oauth.js +721 -721
- package/lib/auth/passkey.js +181 -181
- package/lib/auth/password.js +628 -594
- package/lib/backup/bundle.js +217 -217
- package/lib/backup/crypto.js +176 -176
- package/lib/backup/index.js +515 -515
- package/lib/backup/manifest.js +282 -282
- package/lib/break-glass.js +1338 -1338
- package/lib/bundler.js +441 -441
- package/lib/cache-redis.js +256 -256
- package/lib/cache.js +1206 -1206
- package/lib/canonical-json.js +115 -115
- package/lib/chain-writer.js +234 -234
- package/lib/cli-helpers.js +206 -206
- package/lib/cli.js +2334 -2334
- package/lib/cluster-provider-db.js +317 -317
- package/lib/cluster-storage.js +226 -226
- package/lib/cluster.js +703 -703
- package/lib/config-drift.js +301 -301
- package/lib/consent.js +222 -222
- package/lib/constants.js +191 -191
- package/lib/cookies.js +315 -315
- package/lib/credential-hash.js +322 -322
- package/lib/crypto.js +266 -266
- package/lib/csv.js +275 -275
- package/lib/db-declare-row-policy.js +267 -267
- package/lib/db-declare-view.js +420 -420
- package/lib/db-query.js +406 -406
- package/lib/db-schema.js +319 -319
- package/lib/db.js +1288 -1288
- package/lib/deprecate.js +222 -222
- package/lib/dev.js +335 -335
- package/lib/dual-control.js +473 -473
- package/lib/error-page.js +420 -420
- package/lib/external-db-migrate.js +441 -441
- package/lib/external-db.js +1061 -1061
- package/lib/file-type.js +273 -273
- package/lib/forms.js +422 -422
- package/lib/framework-error.js +293 -293
- package/lib/framework-schema.js +717 -717
- package/lib/handlers.js +350 -350
- package/lib/http-client-cookie-jar.js +508 -508
- package/lib/http-client.js +1195 -1195
- package/lib/i18n.js +878 -878
- package/lib/jobs.js +185 -185
- package/lib/log-stream-cloudwatch.js +369 -369
- package/lib/log-stream-local.js +146 -146
- package/lib/log-stream-otlp-grpc.js +410 -410
- package/lib/log-stream-otlp.js +286 -286
- package/lib/log-stream-syslog.js +302 -302
- package/lib/log-stream-webhook.js +199 -199
- package/lib/log-stream.js +330 -330
- package/lib/log.js +500 -500
- package/lib/mail-bounce.js +528 -528
- package/lib/mail-dkim.js +369 -369
- package/lib/mail.js +981 -981
- package/lib/metrics.js +683 -683
- package/lib/middleware/api-encrypt.js +936 -936
- package/lib/middleware/attach-user.js +157 -157
- package/lib/middleware/bearer-auth.js +152 -0
- package/lib/middleware/body-parser.js +1170 -1170
- package/lib/middleware/bot-guard.js +178 -178
- package/lib/middleware/compression.js +452 -452
- package/lib/middleware/cors.js +314 -314
- package/lib/middleware/csp-nonce.js +348 -348
- package/lib/middleware/csrf-protect.js +316 -316
- package/lib/middleware/db-role-for.js +264 -264
- package/lib/middleware/health.js +392 -392
- package/lib/middleware/index.js +82 -79
- package/lib/middleware/rate-limit.js +358 -358
- package/lib/middleware/request-id.js +61 -61
- package/lib/middleware/request-log.js +168 -168
- package/lib/middleware/require-auth.js +104 -104
- package/lib/middleware/security-headers.js +116 -116
- package/lib/middleware/sse.js +166 -166
- package/lib/migrations.js +383 -383
- package/lib/mtls-ca.js +518 -518
- package/lib/mtls-engine-default.js +481 -481
- package/lib/network-dns.js +632 -632
- package/lib/network-heartbeat.js +290 -290
- package/lib/network-nts.js +574 -574
- package/lib/network-proxy.js +265 -265
- package/lib/network-tls.js +328 -328
- package/lib/network.js +233 -233
- package/lib/notify.js +612 -612
- package/lib/ntp-check.js +229 -229
- package/lib/numeric-bounds.js +111 -111
- package/lib/object-store/azure-blob-bucket-ops.js +349 -349
- package/lib/object-store/azure-blob.js +488 -488
- package/lib/object-store/gcs-bucket-ops.js +351 -351
- package/lib/object-store/gcs.js +519 -519
- package/lib/object-store/http-put.js +153 -153
- package/lib/object-store/index.js +197 -197
- package/lib/object-store/sigv4-bucket-ops.js +1092 -1092
- package/lib/object-store/sigv4.js +903 -903
- package/lib/observability.js +151 -151
- package/lib/otel-export.js +269 -269
- package/lib/pagination.js +464 -464
- package/lib/parsers/index.js +80 -80
- package/lib/parsers/safe-env.js +642 -642
- package/lib/parsers/safe-ini.js +292 -292
- package/lib/parsers/safe-toml.js +784 -784
- package/lib/parsers/safe-xml.js +390 -390
- package/lib/parsers/safe-yaml.js +1015 -1015
- package/lib/permissions.js +708 -708
- package/lib/pqc-agent.js +87 -87
- package/lib/pqc-gate.js +279 -279
- package/lib/protobuf-encoder.js +190 -190
- package/lib/protocol-dispatcher.js +161 -161
- package/lib/pubsub-redis.js +167 -167
- package/lib/pubsub.js +429 -429
- package/lib/queue-local.js +476 -476
- package/lib/queue-redis.js +745 -745
- package/lib/queue-sqs.js +319 -319
- package/lib/queue.js +695 -695
- package/lib/redis-client.js +519 -519
- package/lib/request-helpers.js +340 -340
- package/lib/restore-bundle.js +237 -237
- package/lib/restore-rollback.js +259 -259
- package/lib/restore.js +409 -409
- package/lib/retry.js +376 -376
- package/lib/router.js +748 -748
- package/lib/safe-async.js +735 -735
- package/lib/safe-buffer.js +237 -237
- package/lib/safe-json.js +541 -541
- package/lib/safe-schema.js +1266 -1266
- package/lib/safe-url.js +159 -159
- package/lib/scheduler.js +706 -706
- package/lib/security-assert.js +373 -373
- package/lib/seeders.js +618 -618
- package/lib/session.js +535 -478
- package/lib/slug.js +269 -269
- package/lib/ssrf-guard.js +401 -401
- package/lib/storage.js +471 -471
- package/lib/subject.js +281 -281
- package/lib/template.js +791 -791
- package/lib/testing.js +798 -798
- package/lib/time.js +310 -310
- package/lib/totp.js +302 -302
- package/lib/tracing.js +494 -494
- package/lib/uuid.js +132 -132
- package/lib/validate-opts.js +340 -340
- package/lib/vault/index.js +308 -308
- package/lib/vault/rotate.js +784 -784
- package/lib/vault/wrap.js +296 -296
- package/lib/vendor/noble-ciphers.cjs +9 -9
- package/lib/webhook.js +595 -595
- package/lib/websocket.js +1048 -1048
- package/package.json +77 -77
- package/sbom.cyclonedx.json +7 -7
package/lib/auth/passkey.js
CHANGED
|
@@ -1,181 +1,181 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Passkey / WebAuthn (FIDO2) — registration + authentication primitives.
|
|
4
|
-
*
|
|
5
|
-
* Built on the vendored @simplewebauthn/server (lib/vendor/simplewebauthn-
|
|
6
|
-
* server.cjs). This file is a thin wrapper that names the surface in the
|
|
7
|
-
* framework's auth-namespace style and validates inputs through
|
|
8
|
-
* AuthError so failures are framed consistently with auth.password and
|
|
9
|
-
* auth.totp. The vendor handles CBOR parsing, attestation statement
|
|
10
|
-
* validation, COSE key conversion, and signature verification across
|
|
11
|
-
* the WebAuthn algorithm set; we don't reimplement any of it.
|
|
12
|
-
*
|
|
13
|
-
* The four phases of a WebAuthn flow:
|
|
14
|
-
*
|
|
15
|
-
* Registration (user adds a passkey to their account):
|
|
16
|
-
* 1. server: startRegistration({ rpName, rpId, userName, userDisplayName,
|
|
17
|
-
* excludeCredentials? }) → { challenge, … }. Server stores the
|
|
18
|
-
* challenge in the session.
|
|
19
|
-
* 2. browser: navigator.credentials.create({ publicKey: <options> })
|
|
20
|
-
* → registration response with attestation.
|
|
21
|
-
* 3. server: verifyRegistration({ response, expectedChallenge,
|
|
22
|
-
* expectedOrigin, expectedRPID }) → { verified, registrationInfo:
|
|
23
|
-
* { credential: { id, publicKey, counter }, … } }. Persist
|
|
24
|
-
* credential.id (base64url) + credential.publicKey + counter.
|
|
25
|
-
*
|
|
26
|
-
* Authentication (user logs in with their passkey):
|
|
27
|
-
* 1. server: startAuthentication({ rpId, userVerification? })
|
|
28
|
-
* → { challenge, … }. Server stores challenge in session.
|
|
29
|
-
* 2. browser: navigator.credentials.get({ publicKey: <options> })
|
|
30
|
-
* → assertion response.
|
|
31
|
-
* 3. server: lookup the credential by response.id (base64url),
|
|
32
|
-
* then verifyAuthentication({ response, expectedChallenge,
|
|
33
|
-
* expectedOrigin, expectedRPID, credential: { id, publicKey,
|
|
34
|
-
* counter, transports? } }) → { verified, authenticationInfo:
|
|
35
|
-
* { newCounter } }. Persist newCounter (clone-detection).
|
|
36
|
-
*
|
|
37
|
-
* Public API (b.auth.passkey.*):
|
|
38
|
-
* await passkey.startRegistration(opts) → registration options
|
|
39
|
-
* await passkey.verifyRegistration(opts) → { verified, registrationInfo? }
|
|
40
|
-
* await passkey.startAuthentication(opts) → authentication options
|
|
41
|
-
* await passkey.verifyAuthentication(opts) → { verified, authenticationInfo? }
|
|
42
|
-
*
|
|
43
|
-
* Framework defaults:
|
|
44
|
-
* - attestationType: "none" — don't request attestation. Most apps
|
|
45
|
-
* don't need it, and "direct" or "enterprise" attestation has
|
|
46
|
-
* deployment friction (cert chains, MDS lookups). Operators who
|
|
47
|
-
* genuinely need attestation override.
|
|
48
|
-
* - residentKey: "preferred" — discoverable credentials when the
|
|
49
|
-
* authenticator supports them; falls back to non-discoverable.
|
|
50
|
-
* - userVerification: "preferred" — accept biometric / PIN when
|
|
51
|
-
* available; fall back to presence-only.
|
|
52
|
-
* - hints: ["client-device", "hybrid"] — surface platform
|
|
53
|
-
* authenticators (Touch ID, Windows Hello) AND cross-device
|
|
54
|
-
* (1Password / Bitwarden / mobile-as-roaming-authenticator).
|
|
55
|
-
*
|
|
56
|
-
* No middleware decisions made here — the wrapper does NOT touch
|
|
57
|
-
* sessions, audit, or DB. Routes integrate that themselves; the
|
|
58
|
-
* primitive stays the smallest correct surface.
|
|
59
|
-
*/
|
|
60
|
-
var _wa = require("../vendor/simplewebauthn-server.cjs");
|
|
61
|
-
var { AuthError } = require("../framework-error");
|
|
62
|
-
|
|
63
|
-
function _vendor() {
|
|
64
|
-
return _wa;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function _requireString(v, name) {
|
|
68
|
-
if (typeof v !== "string" || v.length === 0) {
|
|
69
|
-
throw new AuthError("auth-passkey/missing-" + name,
|
|
70
|
-
name + " is required (non-empty string)");
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// ---- Registration ----
|
|
75
|
-
|
|
76
|
-
async function startRegistration(opts) {
|
|
77
|
-
if (!opts) throw new AuthError("auth-passkey/missing-opts", "opts is required");
|
|
78
|
-
_requireString(opts.rpName, "rpName");
|
|
79
|
-
_requireString(opts.rpId, "rpId");
|
|
80
|
-
_requireString(opts.userName, "userName");
|
|
81
|
-
|
|
82
|
-
var sel = opts.authenticatorSelection || {};
|
|
83
|
-
var options = await _vendor().generateRegistrationOptions({
|
|
84
|
-
rpName: opts.rpName,
|
|
85
|
-
rpID: opts.rpId,
|
|
86
|
-
userName: opts.userName,
|
|
87
|
-
userDisplayName: opts.userDisplayName || opts.userName,
|
|
88
|
-
attestationType: opts.attestationType || "none",
|
|
89
|
-
excludeCredentials: opts.excludeCredentials || [],
|
|
90
|
-
authenticatorSelection: {
|
|
91
|
-
residentKey: sel.residentKey || "preferred",
|
|
92
|
-
userVerification: sel.userVerification || "preferred",
|
|
93
|
-
authenticatorAttachment: sel.authenticatorAttachment,
|
|
94
|
-
requireResidentKey: sel.requireResidentKey,
|
|
95
|
-
},
|
|
96
|
-
timeout: opts.timeout,
|
|
97
|
-
extensions: opts.extensions,
|
|
98
|
-
});
|
|
99
|
-
// Hint the browser to surface platform + cross-device authenticators
|
|
100
|
-
// (Touch ID / Windows Hello AND 1Password / Bitwarden / phone-as-key).
|
|
101
|
-
if (!opts.hints) {
|
|
102
|
-
options.hints = ["client-device", "hybrid"];
|
|
103
|
-
} else {
|
|
104
|
-
options.hints = opts.hints;
|
|
105
|
-
}
|
|
106
|
-
return options;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async function verifyRegistration(opts) {
|
|
110
|
-
if (!opts) throw new AuthError("auth-passkey/missing-opts", "opts is required");
|
|
111
|
-
if (!opts.response) {
|
|
112
|
-
throw new AuthError("auth-passkey/missing-response", "opts.response is required");
|
|
113
|
-
}
|
|
114
|
-
_requireString(opts.expectedChallenge, "expectedChallenge");
|
|
115
|
-
_requireString(opts.expectedOrigin, "expectedOrigin");
|
|
116
|
-
_requireString(opts.expectedRPID, "expectedRPID");
|
|
117
|
-
|
|
118
|
-
return await _vendor().verifyRegistrationResponse({
|
|
119
|
-
response: opts.response,
|
|
120
|
-
expectedChallenge: opts.expectedChallenge,
|
|
121
|
-
expectedOrigin: opts.expectedOrigin,
|
|
122
|
-
expectedRPID: opts.expectedRPID,
|
|
123
|
-
requireUserVerification: opts.requireUserVerification !== false,
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// ---- Authentication ----
|
|
128
|
-
|
|
129
|
-
async function startAuthentication(opts) {
|
|
130
|
-
if (!opts) throw new AuthError("auth-passkey/missing-opts", "opts is required");
|
|
131
|
-
_requireString(opts.rpId, "rpId");
|
|
132
|
-
|
|
133
|
-
var options = await _vendor().generateAuthenticationOptions({
|
|
134
|
-
rpID: opts.rpId,
|
|
135
|
-
userVerification: opts.userVerification || "preferred",
|
|
136
|
-
allowCredentials: opts.allowCredentials || [],
|
|
137
|
-
timeout: opts.timeout,
|
|
138
|
-
extensions: opts.extensions,
|
|
139
|
-
});
|
|
140
|
-
if (!opts.hints) {
|
|
141
|
-
options.hints = ["client-device", "hybrid"];
|
|
142
|
-
} else {
|
|
143
|
-
options.hints = opts.hints;
|
|
144
|
-
}
|
|
145
|
-
return options;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async function verifyAuthentication(opts) {
|
|
149
|
-
if (!opts) throw new AuthError("auth-passkey/missing-opts", "opts is required");
|
|
150
|
-
if (!opts.response) {
|
|
151
|
-
throw new AuthError("auth-passkey/missing-response", "opts.response is required");
|
|
152
|
-
}
|
|
153
|
-
_requireString(opts.expectedChallenge, "expectedChallenge");
|
|
154
|
-
_requireString(opts.expectedOrigin, "expectedOrigin");
|
|
155
|
-
_requireString(opts.expectedRPID, "expectedRPID");
|
|
156
|
-
if (!opts.credential || !opts.credential.id || !opts.credential.publicKey) {
|
|
157
|
-
throw new AuthError("auth-passkey/missing-credential",
|
|
158
|
-
"opts.credential { id, publicKey, counter? } is required");
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return await _vendor().verifyAuthenticationResponse({
|
|
162
|
-
response: opts.response,
|
|
163
|
-
expectedChallenge: opts.expectedChallenge,
|
|
164
|
-
expectedOrigin: opts.expectedOrigin,
|
|
165
|
-
expectedRPID: opts.expectedRPID,
|
|
166
|
-
credential: {
|
|
167
|
-
id: opts.credential.id,
|
|
168
|
-
publicKey: opts.credential.publicKey,
|
|
169
|
-
counter: opts.credential.counter || 0,
|
|
170
|
-
transports: opts.credential.transports,
|
|
171
|
-
},
|
|
172
|
-
requireUserVerification: opts.requireUserVerification !== false,
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
module.exports = {
|
|
177
|
-
startRegistration: startRegistration,
|
|
178
|
-
verifyRegistration: verifyRegistration,
|
|
179
|
-
startAuthentication: startAuthentication,
|
|
180
|
-
verifyAuthentication: verifyAuthentication,
|
|
181
|
-
};
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Passkey / WebAuthn (FIDO2) — registration + authentication primitives.
|
|
4
|
+
*
|
|
5
|
+
* Built on the vendored @simplewebauthn/server (lib/vendor/simplewebauthn-
|
|
6
|
+
* server.cjs). This file is a thin wrapper that names the surface in the
|
|
7
|
+
* framework's auth-namespace style and validates inputs through
|
|
8
|
+
* AuthError so failures are framed consistently with auth.password and
|
|
9
|
+
* auth.totp. The vendor handles CBOR parsing, attestation statement
|
|
10
|
+
* validation, COSE key conversion, and signature verification across
|
|
11
|
+
* the WebAuthn algorithm set; we don't reimplement any of it.
|
|
12
|
+
*
|
|
13
|
+
* The four phases of a WebAuthn flow:
|
|
14
|
+
*
|
|
15
|
+
* Registration (user adds a passkey to their account):
|
|
16
|
+
* 1. server: startRegistration({ rpName, rpId, userName, userDisplayName,
|
|
17
|
+
* excludeCredentials? }) → { challenge, … }. Server stores the
|
|
18
|
+
* challenge in the session.
|
|
19
|
+
* 2. browser: navigator.credentials.create({ publicKey: <options> })
|
|
20
|
+
* → registration response with attestation.
|
|
21
|
+
* 3. server: verifyRegistration({ response, expectedChallenge,
|
|
22
|
+
* expectedOrigin, expectedRPID }) → { verified, registrationInfo:
|
|
23
|
+
* { credential: { id, publicKey, counter }, … } }. Persist
|
|
24
|
+
* credential.id (base64url) + credential.publicKey + counter.
|
|
25
|
+
*
|
|
26
|
+
* Authentication (user logs in with their passkey):
|
|
27
|
+
* 1. server: startAuthentication({ rpId, userVerification? })
|
|
28
|
+
* → { challenge, … }. Server stores challenge in session.
|
|
29
|
+
* 2. browser: navigator.credentials.get({ publicKey: <options> })
|
|
30
|
+
* → assertion response.
|
|
31
|
+
* 3. server: lookup the credential by response.id (base64url),
|
|
32
|
+
* then verifyAuthentication({ response, expectedChallenge,
|
|
33
|
+
* expectedOrigin, expectedRPID, credential: { id, publicKey,
|
|
34
|
+
* counter, transports? } }) → { verified, authenticationInfo:
|
|
35
|
+
* { newCounter } }. Persist newCounter (clone-detection).
|
|
36
|
+
*
|
|
37
|
+
* Public API (b.auth.passkey.*):
|
|
38
|
+
* await passkey.startRegistration(opts) → registration options
|
|
39
|
+
* await passkey.verifyRegistration(opts) → { verified, registrationInfo? }
|
|
40
|
+
* await passkey.startAuthentication(opts) → authentication options
|
|
41
|
+
* await passkey.verifyAuthentication(opts) → { verified, authenticationInfo? }
|
|
42
|
+
*
|
|
43
|
+
* Framework defaults:
|
|
44
|
+
* - attestationType: "none" — don't request attestation. Most apps
|
|
45
|
+
* don't need it, and "direct" or "enterprise" attestation has
|
|
46
|
+
* deployment friction (cert chains, MDS lookups). Operators who
|
|
47
|
+
* genuinely need attestation override.
|
|
48
|
+
* - residentKey: "preferred" — discoverable credentials when the
|
|
49
|
+
* authenticator supports them; falls back to non-discoverable.
|
|
50
|
+
* - userVerification: "preferred" — accept biometric / PIN when
|
|
51
|
+
* available; fall back to presence-only.
|
|
52
|
+
* - hints: ["client-device", "hybrid"] — surface platform
|
|
53
|
+
* authenticators (Touch ID, Windows Hello) AND cross-device
|
|
54
|
+
* (1Password / Bitwarden / mobile-as-roaming-authenticator).
|
|
55
|
+
*
|
|
56
|
+
* No middleware decisions made here — the wrapper does NOT touch
|
|
57
|
+
* sessions, audit, or DB. Routes integrate that themselves; the
|
|
58
|
+
* primitive stays the smallest correct surface.
|
|
59
|
+
*/
|
|
60
|
+
var _wa = require("../vendor/simplewebauthn-server.cjs");
|
|
61
|
+
var { AuthError } = require("../framework-error");
|
|
62
|
+
|
|
63
|
+
function _vendor() {
|
|
64
|
+
return _wa;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function _requireString(v, name) {
|
|
68
|
+
if (typeof v !== "string" || v.length === 0) {
|
|
69
|
+
throw new AuthError("auth-passkey/missing-" + name,
|
|
70
|
+
name + " is required (non-empty string)");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ---- Registration ----
|
|
75
|
+
|
|
76
|
+
async function startRegistration(opts) {
|
|
77
|
+
if (!opts) throw new AuthError("auth-passkey/missing-opts", "opts is required");
|
|
78
|
+
_requireString(opts.rpName, "rpName");
|
|
79
|
+
_requireString(opts.rpId, "rpId");
|
|
80
|
+
_requireString(opts.userName, "userName");
|
|
81
|
+
|
|
82
|
+
var sel = opts.authenticatorSelection || {};
|
|
83
|
+
var options = await _vendor().generateRegistrationOptions({
|
|
84
|
+
rpName: opts.rpName,
|
|
85
|
+
rpID: opts.rpId,
|
|
86
|
+
userName: opts.userName,
|
|
87
|
+
userDisplayName: opts.userDisplayName || opts.userName,
|
|
88
|
+
attestationType: opts.attestationType || "none",
|
|
89
|
+
excludeCredentials: opts.excludeCredentials || [],
|
|
90
|
+
authenticatorSelection: {
|
|
91
|
+
residentKey: sel.residentKey || "preferred",
|
|
92
|
+
userVerification: sel.userVerification || "preferred",
|
|
93
|
+
authenticatorAttachment: sel.authenticatorAttachment,
|
|
94
|
+
requireResidentKey: sel.requireResidentKey,
|
|
95
|
+
},
|
|
96
|
+
timeout: opts.timeout,
|
|
97
|
+
extensions: opts.extensions,
|
|
98
|
+
});
|
|
99
|
+
// Hint the browser to surface platform + cross-device authenticators
|
|
100
|
+
// (Touch ID / Windows Hello AND 1Password / Bitwarden / phone-as-key).
|
|
101
|
+
if (!opts.hints) {
|
|
102
|
+
options.hints = ["client-device", "hybrid"];
|
|
103
|
+
} else {
|
|
104
|
+
options.hints = opts.hints;
|
|
105
|
+
}
|
|
106
|
+
return options;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function verifyRegistration(opts) {
|
|
110
|
+
if (!opts) throw new AuthError("auth-passkey/missing-opts", "opts is required");
|
|
111
|
+
if (!opts.response) {
|
|
112
|
+
throw new AuthError("auth-passkey/missing-response", "opts.response is required");
|
|
113
|
+
}
|
|
114
|
+
_requireString(opts.expectedChallenge, "expectedChallenge");
|
|
115
|
+
_requireString(opts.expectedOrigin, "expectedOrigin");
|
|
116
|
+
_requireString(opts.expectedRPID, "expectedRPID");
|
|
117
|
+
|
|
118
|
+
return await _vendor().verifyRegistrationResponse({
|
|
119
|
+
response: opts.response,
|
|
120
|
+
expectedChallenge: opts.expectedChallenge,
|
|
121
|
+
expectedOrigin: opts.expectedOrigin,
|
|
122
|
+
expectedRPID: opts.expectedRPID,
|
|
123
|
+
requireUserVerification: opts.requireUserVerification !== false,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ---- Authentication ----
|
|
128
|
+
|
|
129
|
+
async function startAuthentication(opts) {
|
|
130
|
+
if (!opts) throw new AuthError("auth-passkey/missing-opts", "opts is required");
|
|
131
|
+
_requireString(opts.rpId, "rpId");
|
|
132
|
+
|
|
133
|
+
var options = await _vendor().generateAuthenticationOptions({
|
|
134
|
+
rpID: opts.rpId,
|
|
135
|
+
userVerification: opts.userVerification || "preferred",
|
|
136
|
+
allowCredentials: opts.allowCredentials || [],
|
|
137
|
+
timeout: opts.timeout,
|
|
138
|
+
extensions: opts.extensions,
|
|
139
|
+
});
|
|
140
|
+
if (!opts.hints) {
|
|
141
|
+
options.hints = ["client-device", "hybrid"];
|
|
142
|
+
} else {
|
|
143
|
+
options.hints = opts.hints;
|
|
144
|
+
}
|
|
145
|
+
return options;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function verifyAuthentication(opts) {
|
|
149
|
+
if (!opts) throw new AuthError("auth-passkey/missing-opts", "opts is required");
|
|
150
|
+
if (!opts.response) {
|
|
151
|
+
throw new AuthError("auth-passkey/missing-response", "opts.response is required");
|
|
152
|
+
}
|
|
153
|
+
_requireString(opts.expectedChallenge, "expectedChallenge");
|
|
154
|
+
_requireString(opts.expectedOrigin, "expectedOrigin");
|
|
155
|
+
_requireString(opts.expectedRPID, "expectedRPID");
|
|
156
|
+
if (!opts.credential || !opts.credential.id || !opts.credential.publicKey) {
|
|
157
|
+
throw new AuthError("auth-passkey/missing-credential",
|
|
158
|
+
"opts.credential { id, publicKey, counter? } is required");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return await _vendor().verifyAuthenticationResponse({
|
|
162
|
+
response: opts.response,
|
|
163
|
+
expectedChallenge: opts.expectedChallenge,
|
|
164
|
+
expectedOrigin: opts.expectedOrigin,
|
|
165
|
+
expectedRPID: opts.expectedRPID,
|
|
166
|
+
credential: {
|
|
167
|
+
id: opts.credential.id,
|
|
168
|
+
publicKey: opts.credential.publicKey,
|
|
169
|
+
counter: opts.credential.counter || 0,
|
|
170
|
+
transports: opts.credential.transports,
|
|
171
|
+
},
|
|
172
|
+
requireUserVerification: opts.requireUserVerification !== false,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
module.exports = {
|
|
177
|
+
startRegistration: startRegistration,
|
|
178
|
+
verifyRegistration: verifyRegistration,
|
|
179
|
+
startAuthentication: startAuthentication,
|
|
180
|
+
verifyAuthentication: verifyAuthentication,
|
|
181
|
+
};
|