@simplewebauthn/server 8.1.1 → 8.3.2
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/esm/authentication/verifyAuthenticationResponse.d.ts +2 -0
- package/esm/authentication/verifyAuthenticationResponse.js +14 -2
- package/esm/deps.d.ts +1 -1
- package/esm/deps.js +1 -1
- package/esm/helpers/parseAuthenticatorData.js +16 -0
- package/esm/registration/verifyRegistrationResponse.d.ts +2 -0
- package/esm/registration/verifyRegistrationResponse.js +14 -2
- package/package.json +1 -1
- package/script/authentication/verifyAuthenticationResponse.d.ts +2 -0
- package/script/authentication/verifyAuthenticationResponse.js +14 -2
- package/script/deps.d.ts +1 -1
- package/script/deps.js +1 -1
- package/script/helpers/parseAuthenticatorData.js +16 -0
- package/script/registration/verifyRegistrationResponse.d.ts +2 -0
- package/script/registration/verifyRegistrationResponse.js +14 -2
|
@@ -5,6 +5,7 @@ export type VerifyAuthenticationResponseOpts = {
|
|
|
5
5
|
expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>);
|
|
6
6
|
expectedOrigin: string | string[];
|
|
7
7
|
expectedRPID: string | string[];
|
|
8
|
+
expectedType?: string | string[];
|
|
8
9
|
authenticator: AuthenticatorDevice;
|
|
9
10
|
requireUserVerification?: boolean;
|
|
10
11
|
advancedFIDOConfig?: {
|
|
@@ -21,6 +22,7 @@ export type VerifyAuthenticationResponseOpts = {
|
|
|
21
22
|
* `generateAuthenticationOptions()`
|
|
22
23
|
* @param expectedOrigin Website URL (or array of URLs) that the registration should have occurred on
|
|
23
24
|
* @param expectedRPID RP ID (or array of IDs) that was specified in the registration options
|
|
25
|
+
* @param expectedType (Optional) The response type expected ('webauthn.get')
|
|
24
26
|
* @param authenticator An internal {@link AuthenticatorDevice} matching the credential's ID
|
|
25
27
|
* @param requireUserVerification (Optional) Enforce user verification by the authenticator
|
|
26
28
|
* (via PIN, fingerprint, etc...)
|
|
@@ -15,6 +15,7 @@ import { isoBase64URL, isoUint8Array } from '../helpers/iso/index.js';
|
|
|
15
15
|
* `generateAuthenticationOptions()`
|
|
16
16
|
* @param expectedOrigin Website URL (or array of URLs) that the registration should have occurred on
|
|
17
17
|
* @param expectedRPID RP ID (or array of IDs) that was specified in the registration options
|
|
18
|
+
* @param expectedType (Optional) The response type expected ('webauthn.get')
|
|
18
19
|
* @param authenticator An internal {@link AuthenticatorDevice} matching the credential's ID
|
|
19
20
|
* @param requireUserVerification (Optional) Enforce user verification by the authenticator
|
|
20
21
|
* (via PIN, fingerprint, etc...)
|
|
@@ -25,7 +26,7 @@ import { isoBase64URL, isoUint8Array } from '../helpers/iso/index.js';
|
|
|
25
26
|
* unless this value is `"required"`
|
|
26
27
|
*/
|
|
27
28
|
export async function verifyAuthenticationResponse(options) {
|
|
28
|
-
const { response, expectedChallenge, expectedOrigin, expectedRPID, authenticator, requireUserVerification = true, advancedFIDOConfig, } = options;
|
|
29
|
+
const { response, expectedChallenge, expectedOrigin, expectedRPID, expectedType, authenticator, requireUserVerification = true, advancedFIDOConfig, } = options;
|
|
29
30
|
const { id, rawId, type: credentialType, response: assertionResponse } = response;
|
|
30
31
|
// Ensure credential specified an ID
|
|
31
32
|
if (!id) {
|
|
@@ -48,7 +49,18 @@ export async function verifyAuthenticationResponse(options) {
|
|
|
48
49
|
const clientDataJSON = decodeClientDataJSON(assertionResponse.clientDataJSON);
|
|
49
50
|
const { type, origin, challenge, tokenBinding } = clientDataJSON;
|
|
50
51
|
// Make sure we're handling an authentication
|
|
51
|
-
if (
|
|
52
|
+
if (Array.isArray(expectedType)) {
|
|
53
|
+
if (!expectedType.includes(type)) {
|
|
54
|
+
const joinedExpectedType = expectedType.join(', ');
|
|
55
|
+
throw new Error(`Unexpected authentication response type "${type}", expected one of: ${joinedExpectedType}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else if (expectedType) {
|
|
59
|
+
if (type !== expectedType) {
|
|
60
|
+
throw new Error(`Unexpected authentication response type "${type}", expected "${expectedType}"`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else if (type !== 'webauthn.get') {
|
|
52
64
|
throw new Error(`Unexpected authentication response type: ${type}`);
|
|
53
65
|
}
|
|
54
66
|
// Ensure the device provided the challenge we gave it
|
package/esm/deps.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { AttestationConveyancePreference, AuthenticationExtensionsClientInputs, AuthenticationResponseJSON, AuthenticatorDevice, AuthenticatorSelectionCriteria, Base64URLString, COSEAlgorithmIdentifier, CredentialDeviceType, Crypto, PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialDescriptorFuture, PublicKeyCredentialParameters, PublicKeyCredentialRequestOptionsJSON, RegistrationResponseJSON, UserVerificationRequirement, } from '@simplewebauthn/typescript-types';
|
|
2
|
-
export * as cborx from 'cbor-x';
|
|
2
|
+
export * as cborx from 'cbor-x/encode';
|
|
3
3
|
export { default as base64 } from '@hexagon/base64';
|
|
4
4
|
export { fetch as crossFetch } from 'cross-fetch';
|
|
5
5
|
export { AsnParser, AsnSerializer } from '@peculiar/asn1-schema';
|
package/esm/deps.js
CHANGED
|
@@ -34,6 +34,22 @@ export function parseAuthenticatorData(authData) {
|
|
|
34
34
|
const credIDLen = dataView.getUint16(pointer);
|
|
35
35
|
pointer += 2;
|
|
36
36
|
credentialID = authData.slice(pointer, pointer += credIDLen);
|
|
37
|
+
/**
|
|
38
|
+
* Firefox 117 incorrectly CBOR-encodes authData when EdDSA (-8) is used for the public key.
|
|
39
|
+
* A CBOR "Map of 3 items" (0xa3) should be "Map of 4 items" (0xa4), and if we manually adjust
|
|
40
|
+
* the single byte there's a good chance the authData can be correctly parsed.
|
|
41
|
+
*
|
|
42
|
+
* This browser release also incorrectly uses the string labels "OKP" and "Ed25519" instead of
|
|
43
|
+
* their integer representations for kty and crv respectively. That's why the COSE public key
|
|
44
|
+
* in the hex below looks so odd.
|
|
45
|
+
*/
|
|
46
|
+
// Bytes decode to `{ 1: "OKP", 3: -8, -1: "Ed25519" }` (it's missing key -2 a.k.a. COSEKEYS.x)
|
|
47
|
+
const badEdDSACBOR = isoUint8Array.fromHex('a301634f4b500327206745643235353139');
|
|
48
|
+
const bytesAtCurrentPosition = authData.slice(pointer, pointer + badEdDSACBOR.byteLength);
|
|
49
|
+
if (isoUint8Array.areEqual(badEdDSACBOR, bytesAtCurrentPosition)) {
|
|
50
|
+
// Change the bad CBOR 0xa3 to 0xa4 so that the credential public key can be recognized
|
|
51
|
+
authData[pointer] = 0xa4;
|
|
52
|
+
}
|
|
37
53
|
// Decode the next CBOR item in the buffer, then re-encode it back to a Buffer
|
|
38
54
|
const firstDecoded = isoCBOR.decodeFirst(authData.slice(pointer));
|
|
39
55
|
const firstEncoded = Uint8Array.from(isoCBOR.encode(firstDecoded));
|
|
@@ -6,6 +6,7 @@ export type VerifyRegistrationResponseOpts = {
|
|
|
6
6
|
expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>);
|
|
7
7
|
expectedOrigin: string | string[];
|
|
8
8
|
expectedRPID?: string | string[];
|
|
9
|
+
expectedType?: string | string[];
|
|
9
10
|
requireUserVerification?: boolean;
|
|
10
11
|
supportedAlgorithmIDs?: COSEAlgorithmIdentifier[];
|
|
11
12
|
};
|
|
@@ -19,6 +20,7 @@ export type VerifyRegistrationResponseOpts = {
|
|
|
19
20
|
* `generateRegistrationOptions()`
|
|
20
21
|
* @param expectedOrigin Website URL (or array of URLs) that the registration should have occurred on
|
|
21
22
|
* @param expectedRPID RP ID (or array of IDs) that was specified in the registration options
|
|
23
|
+
* @param expectedType (Optional) The response type expected ('webauthn.create')
|
|
22
24
|
* @param requireUserVerification (Optional) Enforce user verification by the authenticator
|
|
23
25
|
* (via PIN, fingerprint, etc...)
|
|
24
26
|
* @param supportedAlgorithmIDs Array of numeric COSE algorithm identifiers supported for
|
|
@@ -26,13 +26,14 @@ import { verifyAttestationApple } from './verifications/verifyAttestationApple.j
|
|
|
26
26
|
* `generateRegistrationOptions()`
|
|
27
27
|
* @param expectedOrigin Website URL (or array of URLs) that the registration should have occurred on
|
|
28
28
|
* @param expectedRPID RP ID (or array of IDs) that was specified in the registration options
|
|
29
|
+
* @param expectedType (Optional) The response type expected ('webauthn.create')
|
|
29
30
|
* @param requireUserVerification (Optional) Enforce user verification by the authenticator
|
|
30
31
|
* (via PIN, fingerprint, etc...)
|
|
31
32
|
* @param supportedAlgorithmIDs Array of numeric COSE algorithm identifiers supported for
|
|
32
33
|
* attestation by this RP. See https://www.iana.org/assignments/cose/cose.xhtml#algorithms
|
|
33
34
|
*/
|
|
34
35
|
export async function verifyRegistrationResponse(options) {
|
|
35
|
-
const { response, expectedChallenge, expectedOrigin, expectedRPID, requireUserVerification = true, supportedAlgorithmIDs = supportedCOSEAlgorithmIdentifiers, } = options;
|
|
36
|
+
const { response, expectedChallenge, expectedOrigin, expectedRPID, expectedType, requireUserVerification = true, supportedAlgorithmIDs = supportedCOSEAlgorithmIdentifiers, } = options;
|
|
36
37
|
const { id, rawId, type: credentialType, response: attestationResponse } = response;
|
|
37
38
|
// Ensure credential specified an ID
|
|
38
39
|
if (!id) {
|
|
@@ -49,7 +50,18 @@ export async function verifyRegistrationResponse(options) {
|
|
|
49
50
|
const clientDataJSON = decodeClientDataJSON(attestationResponse.clientDataJSON);
|
|
50
51
|
const { type, origin, challenge, tokenBinding } = clientDataJSON;
|
|
51
52
|
// Make sure we're handling an registration
|
|
52
|
-
if (
|
|
53
|
+
if (Array.isArray(expectedType)) {
|
|
54
|
+
if (!expectedType.includes(type)) {
|
|
55
|
+
const joinedExpectedType = expectedType.join(', ');
|
|
56
|
+
throw new Error(`Unexpected registration response type "${type}", expected one of: ${joinedExpectedType}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else if (expectedType) {
|
|
60
|
+
if (type !== expectedType) {
|
|
61
|
+
throw new Error(`Unexpected registration response type "${type}", expected "${expectedType}"`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else if (type !== 'webauthn.create') {
|
|
53
65
|
throw new Error(`Unexpected registration response type: ${type}`);
|
|
54
66
|
}
|
|
55
67
|
// Ensure the device provided the challenge we gave it
|
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@ export type VerifyAuthenticationResponseOpts = {
|
|
|
5
5
|
expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>);
|
|
6
6
|
expectedOrigin: string | string[];
|
|
7
7
|
expectedRPID: string | string[];
|
|
8
|
+
expectedType?: string | string[];
|
|
8
9
|
authenticator: AuthenticatorDevice;
|
|
9
10
|
requireUserVerification?: boolean;
|
|
10
11
|
advancedFIDOConfig?: {
|
|
@@ -21,6 +22,7 @@ export type VerifyAuthenticationResponseOpts = {
|
|
|
21
22
|
* `generateAuthenticationOptions()`
|
|
22
23
|
* @param expectedOrigin Website URL (or array of URLs) that the registration should have occurred on
|
|
23
24
|
* @param expectedRPID RP ID (or array of IDs) that was specified in the registration options
|
|
25
|
+
* @param expectedType (Optional) The response type expected ('webauthn.get')
|
|
24
26
|
* @param authenticator An internal {@link AuthenticatorDevice} matching the credential's ID
|
|
25
27
|
* @param requireUserVerification (Optional) Enforce user verification by the authenticator
|
|
26
28
|
* (via PIN, fingerprint, etc...)
|
|
@@ -18,6 +18,7 @@ const index_js_1 = require("../helpers/iso/index.js");
|
|
|
18
18
|
* `generateAuthenticationOptions()`
|
|
19
19
|
* @param expectedOrigin Website URL (or array of URLs) that the registration should have occurred on
|
|
20
20
|
* @param expectedRPID RP ID (or array of IDs) that was specified in the registration options
|
|
21
|
+
* @param expectedType (Optional) The response type expected ('webauthn.get')
|
|
21
22
|
* @param authenticator An internal {@link AuthenticatorDevice} matching the credential's ID
|
|
22
23
|
* @param requireUserVerification (Optional) Enforce user verification by the authenticator
|
|
23
24
|
* (via PIN, fingerprint, etc...)
|
|
@@ -28,7 +29,7 @@ const index_js_1 = require("../helpers/iso/index.js");
|
|
|
28
29
|
* unless this value is `"required"`
|
|
29
30
|
*/
|
|
30
31
|
async function verifyAuthenticationResponse(options) {
|
|
31
|
-
const { response, expectedChallenge, expectedOrigin, expectedRPID, authenticator, requireUserVerification = true, advancedFIDOConfig, } = options;
|
|
32
|
+
const { response, expectedChallenge, expectedOrigin, expectedRPID, expectedType, authenticator, requireUserVerification = true, advancedFIDOConfig, } = options;
|
|
32
33
|
const { id, rawId, type: credentialType, response: assertionResponse } = response;
|
|
33
34
|
// Ensure credential specified an ID
|
|
34
35
|
if (!id) {
|
|
@@ -51,7 +52,18 @@ async function verifyAuthenticationResponse(options) {
|
|
|
51
52
|
const clientDataJSON = (0, decodeClientDataJSON_js_1.decodeClientDataJSON)(assertionResponse.clientDataJSON);
|
|
52
53
|
const { type, origin, challenge, tokenBinding } = clientDataJSON;
|
|
53
54
|
// Make sure we're handling an authentication
|
|
54
|
-
if (
|
|
55
|
+
if (Array.isArray(expectedType)) {
|
|
56
|
+
if (!expectedType.includes(type)) {
|
|
57
|
+
const joinedExpectedType = expectedType.join(', ');
|
|
58
|
+
throw new Error(`Unexpected authentication response type "${type}", expected one of: ${joinedExpectedType}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else if (expectedType) {
|
|
62
|
+
if (type !== expectedType) {
|
|
63
|
+
throw new Error(`Unexpected authentication response type "${type}", expected "${expectedType}"`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else if (type !== 'webauthn.get') {
|
|
55
67
|
throw new Error(`Unexpected authentication response type: ${type}`);
|
|
56
68
|
}
|
|
57
69
|
// Ensure the device provided the challenge we gave it
|
package/script/deps.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { AttestationConveyancePreference, AuthenticationExtensionsClientInputs, AuthenticationResponseJSON, AuthenticatorDevice, AuthenticatorSelectionCriteria, Base64URLString, COSEAlgorithmIdentifier, CredentialDeviceType, Crypto, PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialDescriptorFuture, PublicKeyCredentialParameters, PublicKeyCredentialRequestOptionsJSON, RegistrationResponseJSON, UserVerificationRequirement, } from '@simplewebauthn/typescript-types';
|
|
2
|
-
export * as cborx from 'cbor-x';
|
|
2
|
+
export * as cborx from 'cbor-x/encode';
|
|
3
3
|
export { default as base64 } from '@hexagon/base64';
|
|
4
4
|
export { fetch as crossFetch } from 'cross-fetch';
|
|
5
5
|
export { AsnParser, AsnSerializer } from '@peculiar/asn1-schema';
|
package/script/deps.js
CHANGED
|
@@ -28,7 +28,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.KeyDescription = exports.id_ce_keyDescription = exports.RSAPublicKey = exports.id_secp384r1 = exports.id_secp256r1 = exports.id_ecPublicKey = exports.ECParameters = exports.ECDSASigValue = exports.SubjectKeyIdentifier = exports.SubjectAlternativeName = exports.Name = exports.id_ce_subjectKeyIdentifier = exports.id_ce_subjectAltName = exports.id_ce_extKeyUsage = exports.id_ce_cRLDistributionPoints = exports.id_ce_basicConstraints = exports.id_ce_authorityKeyIdentifier = exports.ExtendedKeyUsage = exports.CRLDistributionPoints = exports.CertificateList = exports.Certificate = exports.BasicConstraints = exports.AuthorityKeyIdentifier = exports.AsnSerializer = exports.AsnParser = exports.crossFetch = exports.base64 = exports.cborx = void 0;
|
|
30
30
|
// cbor (a.k.a. cbor-x in Node land)
|
|
31
|
-
exports.cborx = __importStar(require("cbor-x"));
|
|
31
|
+
exports.cborx = __importStar(require("cbor-x/encode"));
|
|
32
32
|
// b64 (a.k.a. @hexagon/base64 in Node land)
|
|
33
33
|
var base64_1 = require("@hexagon/base64");
|
|
34
34
|
Object.defineProperty(exports, "base64", { enumerable: true, get: function () { return __importDefault(base64_1).default; } });
|
|
@@ -37,6 +37,22 @@ function parseAuthenticatorData(authData) {
|
|
|
37
37
|
const credIDLen = dataView.getUint16(pointer);
|
|
38
38
|
pointer += 2;
|
|
39
39
|
credentialID = authData.slice(pointer, pointer += credIDLen);
|
|
40
|
+
/**
|
|
41
|
+
* Firefox 117 incorrectly CBOR-encodes authData when EdDSA (-8) is used for the public key.
|
|
42
|
+
* A CBOR "Map of 3 items" (0xa3) should be "Map of 4 items" (0xa4), and if we manually adjust
|
|
43
|
+
* the single byte there's a good chance the authData can be correctly parsed.
|
|
44
|
+
*
|
|
45
|
+
* This browser release also incorrectly uses the string labels "OKP" and "Ed25519" instead of
|
|
46
|
+
* their integer representations for kty and crv respectively. That's why the COSE public key
|
|
47
|
+
* in the hex below looks so odd.
|
|
48
|
+
*/
|
|
49
|
+
// Bytes decode to `{ 1: "OKP", 3: -8, -1: "Ed25519" }` (it's missing key -2 a.k.a. COSEKEYS.x)
|
|
50
|
+
const badEdDSACBOR = index_js_1.isoUint8Array.fromHex('a301634f4b500327206745643235353139');
|
|
51
|
+
const bytesAtCurrentPosition = authData.slice(pointer, pointer + badEdDSACBOR.byteLength);
|
|
52
|
+
if (index_js_1.isoUint8Array.areEqual(badEdDSACBOR, bytesAtCurrentPosition)) {
|
|
53
|
+
// Change the bad CBOR 0xa3 to 0xa4 so that the credential public key can be recognized
|
|
54
|
+
authData[pointer] = 0xa4;
|
|
55
|
+
}
|
|
40
56
|
// Decode the next CBOR item in the buffer, then re-encode it back to a Buffer
|
|
41
57
|
const firstDecoded = index_js_1.isoCBOR.decodeFirst(authData.slice(pointer));
|
|
42
58
|
const firstEncoded = Uint8Array.from(index_js_1.isoCBOR.encode(firstDecoded));
|
|
@@ -6,6 +6,7 @@ export type VerifyRegistrationResponseOpts = {
|
|
|
6
6
|
expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>);
|
|
7
7
|
expectedOrigin: string | string[];
|
|
8
8
|
expectedRPID?: string | string[];
|
|
9
|
+
expectedType?: string | string[];
|
|
9
10
|
requireUserVerification?: boolean;
|
|
10
11
|
supportedAlgorithmIDs?: COSEAlgorithmIdentifier[];
|
|
11
12
|
};
|
|
@@ -19,6 +20,7 @@ export type VerifyRegistrationResponseOpts = {
|
|
|
19
20
|
* `generateRegistrationOptions()`
|
|
20
21
|
* @param expectedOrigin Website URL (or array of URLs) that the registration should have occurred on
|
|
21
22
|
* @param expectedRPID RP ID (or array of IDs) that was specified in the registration options
|
|
23
|
+
* @param expectedType (Optional) The response type expected ('webauthn.create')
|
|
22
24
|
* @param requireUserVerification (Optional) Enforce user verification by the authenticator
|
|
23
25
|
* (via PIN, fingerprint, etc...)
|
|
24
26
|
* @param supportedAlgorithmIDs Array of numeric COSE algorithm identifiers supported for
|
|
@@ -29,13 +29,14 @@ const verifyAttestationApple_js_1 = require("./verifications/verifyAttestationAp
|
|
|
29
29
|
* `generateRegistrationOptions()`
|
|
30
30
|
* @param expectedOrigin Website URL (or array of URLs) that the registration should have occurred on
|
|
31
31
|
* @param expectedRPID RP ID (or array of IDs) that was specified in the registration options
|
|
32
|
+
* @param expectedType (Optional) The response type expected ('webauthn.create')
|
|
32
33
|
* @param requireUserVerification (Optional) Enforce user verification by the authenticator
|
|
33
34
|
* (via PIN, fingerprint, etc...)
|
|
34
35
|
* @param supportedAlgorithmIDs Array of numeric COSE algorithm identifiers supported for
|
|
35
36
|
* attestation by this RP. See https://www.iana.org/assignments/cose/cose.xhtml#algorithms
|
|
36
37
|
*/
|
|
37
38
|
async function verifyRegistrationResponse(options) {
|
|
38
|
-
const { response, expectedChallenge, expectedOrigin, expectedRPID, requireUserVerification = true, supportedAlgorithmIDs = generateRegistrationOptions_js_1.supportedCOSEAlgorithmIdentifiers, } = options;
|
|
39
|
+
const { response, expectedChallenge, expectedOrigin, expectedRPID, expectedType, requireUserVerification = true, supportedAlgorithmIDs = generateRegistrationOptions_js_1.supportedCOSEAlgorithmIdentifiers, } = options;
|
|
39
40
|
const { id, rawId, type: credentialType, response: attestationResponse } = response;
|
|
40
41
|
// Ensure credential specified an ID
|
|
41
42
|
if (!id) {
|
|
@@ -52,7 +53,18 @@ async function verifyRegistrationResponse(options) {
|
|
|
52
53
|
const clientDataJSON = (0, decodeClientDataJSON_js_1.decodeClientDataJSON)(attestationResponse.clientDataJSON);
|
|
53
54
|
const { type, origin, challenge, tokenBinding } = clientDataJSON;
|
|
54
55
|
// Make sure we're handling an registration
|
|
55
|
-
if (
|
|
56
|
+
if (Array.isArray(expectedType)) {
|
|
57
|
+
if (!expectedType.includes(type)) {
|
|
58
|
+
const joinedExpectedType = expectedType.join(', ');
|
|
59
|
+
throw new Error(`Unexpected registration response type "${type}", expected one of: ${joinedExpectedType}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else if (expectedType) {
|
|
63
|
+
if (type !== expectedType) {
|
|
64
|
+
throw new Error(`Unexpected registration response type "${type}", expected "${expectedType}"`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else if (type !== 'webauthn.create') {
|
|
56
68
|
throw new Error(`Unexpected registration response type: ${type}`);
|
|
57
69
|
}
|
|
58
70
|
// Ensure the device provided the challenge we gave it
|