From f12457d11ed1945b03564c31faf438ed36d14260 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Tue, 16 Aug 2022 22:21:02 +0900 Subject: [PATCH 01/37] Implement `verifyDevicePubKey` --- .../src/extensions/devicePubKey.test.ts | 11 +++++++++++ .../server/src/extensions/devicePubKey.ts | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 packages/server/src/extensions/devicePubKey.test.ts create mode 100644 packages/server/src/extensions/devicePubKey.ts diff --git a/packages/server/src/extensions/devicePubKey.test.ts b/packages/server/src/extensions/devicePubKey.test.ts new file mode 100644 index 00000000..14c7aad3 --- /dev/null +++ b/packages/server/src/extensions/devicePubKey.test.ts @@ -0,0 +1,11 @@ +import { verifyDevicePublicKey } from './devicePubKey'; + +it('should verify a device public key extension', () => { + const clientDataHash = 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiaVpzVkN6dHJEVzdEMlVfR0hDSWxZS0x3VjJiQ3NCVFJxVlFVbkpYbjlUayIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9'; + const authDataBuffer = Buffer.from('0d75fcc563fda779db2e343eea489888758b78549d493a4fdbea1cd96aa31cc48500000000a16c6465766963655075624b6579a56364706b584da5010203262001215820991aabed9de4271a9edead8806f9dc96d6dccd0c476253a5510489ec8379be5b225820a0973cfdedbb79e27fef4ee7481673fb3312504ddca5434cfd23431d6ad29eda6373696758473045022049526cd28aef6b4e621a7d5936d2b504952fc0ae2313a4f0357aafffaea964740221009d513acaefb0b32c765aae6feba8c294685eff63ff1cbf11ecf2107af4feb8f8656e6f6e6365406573636f706541006661616775696450b93fd961f2e6462fb12282002247de78', 'hex'); + const encodedSignature = 'MEUCIElSbNKK72tOYhp9WTbStQSVL8CuIxOk8DV6r_-uqWR0AiEAnVE6yu-wsyx2Wq5v66jClGhe_2P_HL8R7PIQevT-uPg'; + const publicKey = Buffer.from('A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', 'hex'); + + const result = verifyDevicePublicKey(clientDataHash, authDataBuffer, publicKey, encodedSignature); + expect(result).toEqual(true); +}); diff --git a/packages/server/src/extensions/devicePubKey.ts b/packages/server/src/extensions/devicePubKey.ts new file mode 100644 index 00000000..6dc941a8 --- /dev/null +++ b/packages/server/src/extensions/devicePubKey.ts @@ -0,0 +1,19 @@ +import base64url from "base64url"; +import { convertPublicKeyToPEM } from "../helpers/convertPublicKeyToPEM"; +import { toHash } from "../helpers/toHash"; +import { verifySignature } from "../helpers/verifySignature"; + +export function verifyDevicePublicKey( + clientDataJSON: string, + authDataBuffer: Buffer, + publicKey: Buffer, + encodedSignature: string, +): boolean { + const clientDataHash = toHash(base64url.toBuffer(clientDataJSON)); + const signatureBase = Buffer.concat([authDataBuffer, clientDataHash]); + + const PEM = convertPublicKeyToPEM(publicKey); + const signature = base64url.toBuffer(encodedSignature); + + return verifySignature(signature, signatureBase, PEM); +} From 54b2629d4e2e914408f53fbdc37b12208e315ef6 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Wed, 17 Aug 2022 20:14:10 +0900 Subject: [PATCH 02/37] Working `verifyDevicePublicKey`. --- .../src/extensions/devicePubKey.test.ts | 12 +++++++----- .../server/src/extensions/devicePubKey.ts | 19 ++++++++++--------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/server/src/extensions/devicePubKey.test.ts b/packages/server/src/extensions/devicePubKey.test.ts index 14c7aad3..b7528908 100644 --- a/packages/server/src/extensions/devicePubKey.test.ts +++ b/packages/server/src/extensions/devicePubKey.test.ts @@ -1,11 +1,13 @@ +import base64url from 'base64url'; import { verifyDevicePublicKey } from './devicePubKey'; it('should verify a device public key extension', () => { - const clientDataHash = 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiaVpzVkN6dHJEVzdEMlVfR0hDSWxZS0x3VjJiQ3NCVFJxVlFVbkpYbjlUayIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9'; - const authDataBuffer = Buffer.from('0d75fcc563fda779db2e343eea489888758b78549d493a4fdbea1cd96aa31cc48500000000a16c6465766963655075624b6579a56364706b584da5010203262001215820991aabed9de4271a9edead8806f9dc96d6dccd0c476253a5510489ec8379be5b225820a0973cfdedbb79e27fef4ee7481673fb3312504ddca5434cfd23431d6ad29eda6373696758473045022049526cd28aef6b4e621a7d5936d2b504952fc0ae2313a4f0357aafffaea964740221009d513acaefb0b32c765aae6feba8c294685eff63ff1cbf11ecf2107af4feb8f8656e6f6e6365406573636f706541006661616775696450b93fd961f2e6462fb12282002247de78', 'hex'); - const encodedSignature = 'MEUCIElSbNKK72tOYhp9WTbStQSVL8CuIxOk8DV6r_-uqWR0AiEAnVE6yu-wsyx2Wq5v66jClGhe_2P_HL8R7PIQevT-uPg'; - const publicKey = Buffer.from('A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', 'hex'); + const credentialID = 'cxjDB1h5nG6jpQW3EeeZNA'; + const clientDataJSON = 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoicTh1SVR0d0czMkhUU3RmdlVxVTcwWXNGNFJfS1A4WnZEYkVESVpZekNDdyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9'; + const nonce = ''; + const dpk = Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'); + const signature = Buffer.from('3045022100BC6DD9AF5E47BB3AB82731299EAE82A779189E4E416E3A0E37A3BA64C38F991202205671EFAC0E8CD6DE1D3640CE7E4E89D3A97E0517B603D8AC28F23E4E1F74E639', 'hex'); - const result = verifyDevicePublicKey(clientDataHash, authDataBuffer, publicKey, encodedSignature); + const result = verifyDevicePublicKey(credentialID, clientDataJSON, nonce, dpk, signature); expect(result).toEqual(true); }); diff --git a/packages/server/src/extensions/devicePubKey.ts b/packages/server/src/extensions/devicePubKey.ts index 6dc941a8..7af5b8d8 100644 --- a/packages/server/src/extensions/devicePubKey.ts +++ b/packages/server/src/extensions/devicePubKey.ts @@ -1,19 +1,20 @@ import base64url from "base64url"; -import { convertPublicKeyToPEM } from "../helpers/convertPublicKeyToPEM"; import { toHash } from "../helpers/toHash"; import { verifySignature } from "../helpers/verifySignature"; +import { convertPublicKeyToPEM } from "../helpers/convertPublicKeyToPEM"; export function verifyDevicePublicKey( + credentialID: string, clientDataJSON: string, - authDataBuffer: Buffer, - publicKey: Buffer, - encodedSignature: string, + nonce: string, + dpk: Buffer, + signature: Buffer, ): boolean { + const _credentialID = base64url.toBuffer(credentialID); const clientDataHash = toHash(base64url.toBuffer(clientDataJSON)); - const signatureBase = Buffer.concat([authDataBuffer, clientDataHash]); - - const PEM = convertPublicKeyToPEM(publicKey); - const signature = base64url.toBuffer(encodedSignature); + const _nonce = base64url.toBuffer(nonce); + const signatureBase = Buffer.concat([_credentialID, clientDataHash, _nonce]); + const publicKey = convertPublicKeyToPEM(dpk); - return verifySignature(signature, signatureBase, PEM); + return verifySignature(signature, signatureBase, publicKey); } From 9506187f9d39337dae45494bbc50ddd01d822518 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Thu, 18 Aug 2022 14:27:00 +0900 Subject: [PATCH 03/37] Update DPK impl. --- .../src/extensions/devicePubKey.test.ts | 16 +++-- .../server/src/extensions/devicePubKey.ts | 70 +++++++++++++++++-- .../helpers/decodeAuthenticatorExtensions.ts | 11 +-- 3 files changed, 80 insertions(+), 17 deletions(-) diff --git a/packages/server/src/extensions/devicePubKey.test.ts b/packages/server/src/extensions/devicePubKey.test.ts index b7528908..d923f78f 100644 --- a/packages/server/src/extensions/devicePubKey.test.ts +++ b/packages/server/src/extensions/devicePubKey.test.ts @@ -1,13 +1,17 @@ -import base64url from 'base64url'; -import { verifyDevicePublicKey } from './devicePubKey'; +import { verifyDpkSignature } from './devicePubKey'; it('should verify a device public key extension', () => { const credentialID = 'cxjDB1h5nG6jpQW3EeeZNA'; const clientDataJSON = 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoicTh1SVR0d0czMkhUU3RmdlVxVTcwWXNGNFJfS1A4WnZEYkVESVpZekNDdyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9'; - const nonce = ''; - const dpk = Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'); - const signature = Buffer.from('3045022100BC6DD9AF5E47BB3AB82731299EAE82A779189E4E416E3A0E37A3BA64C38F991202205671EFAC0E8CD6DE1D3640CE7E4E89D3A97E0517B603D8AC28F23E4E1F74E639', 'hex'); + const devicePubKey = { + aaguid: Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), + dpk: Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'), + sig: Buffer.from('3045022100BC6DD9AF5E47BB3AB82731299EAE82A779189E4E416E3A0E37A3BA64C38F991202205671EFAC0E8CD6DE1D3640CE7E4E89D3A97E0517B603D8AC28F23E4E1F74E639', 'hex'), + nonce: Buffer.from('', 'hex'), + scope: Buffer.from('00', 'hex') + } + const signature = devicePubKey.sig; - const result = verifyDevicePublicKey(credentialID, clientDataJSON, nonce, dpk, signature); + const result = verifyDpkSignature(credentialID, clientDataJSON, devicePubKey, signature); expect(result).toEqual(true); }); diff --git a/packages/server/src/extensions/devicePubKey.ts b/packages/server/src/extensions/devicePubKey.ts index 7af5b8d8..15673098 100644 --- a/packages/server/src/extensions/devicePubKey.ts +++ b/packages/server/src/extensions/devicePubKey.ts @@ -2,19 +2,75 @@ import base64url from "base64url"; import { toHash } from "../helpers/toHash"; import { verifySignature } from "../helpers/verifySignature"; import { convertPublicKeyToPEM } from "../helpers/convertPublicKeyToPEM"; +import { DevicePublicKeyAuthenticatorOutput } from "helpers/decodeAuthenticatorExtensions"; -export function verifyDevicePublicKey( +/** + * https://pr-preview.s3.amazonaws.com/w3c/webauthn/pull/1663.html#sctn-device-publickey-extension-verification-create + * 3. Verify that `signature` is a valid signature over the assertion signature + * input by the device public key *dpk*. (The signature algorithm is the same + * as for the user credential.) + * @param credentialID + * @param clientDataJSON + * @param nonce + * @param dpk + * @param signature + * @returns + */ +export function verifyDpkSignature( credentialID: string, clientDataJSON: string, - nonce: string, - dpk: Buffer, + devicePubKey: DevicePublicKeyAuthenticatorOutput, signature: Buffer, ): boolean { - const _credentialID = base64url.toBuffer(credentialID); + const rawId = base64url.toBuffer(credentialID); const clientDataHash = toHash(base64url.toBuffer(clientDataJSON)); - const _nonce = base64url.toBuffer(nonce); - const signatureBase = Buffer.concat([_credentialID, clientDataHash, _nonce]); - const publicKey = convertPublicKeyToPEM(dpk); + const nonce = devicePubKey.nonce ? devicePubKey.nonce : Buffer.from(''); + const signatureBase = Buffer.concat([rawId, clientDataHash, nonce]); + const publicKey = convertPublicKeyToPEM(devicePubKey.dpk); + + // TODO: Implement a logic to verify attestation signatures return verifySignature(signature, signatureBase, publicKey); } + +/** + * https://pr-preview.s3.amazonaws.com/w3c/webauthn/pull/1663.html#sctn-device-publickey-extension-verification-get + * 4. If the Relying Party's user account mapped to the *credential*.id in play + * (i.e., for the user being authenticated) holds `aaguid`, `dpk`, `scope`, + * `fmt`, and `attStmt` values corresponding to the extracted + * *attObjForDevicePublicKey* fields, then perform binary equality checks + * between the corresponding stored values and the extracted field values. + * The Relying Party may have more than one set of `{aaguid, dpk, scope, fmt, + * attStmt}` values mapped to the user account and *credential*.id pair and + * each set must be checked. + * @param devicePubKey + * @param expectedDPK + * @returns + */ +export function verifyDevicePublicKey( + devicePubKey: DevicePublicKeyAuthenticatorOutput, + expectedDPK: DevicePublicKeyAuthenticatorOutput +): boolean { + if (!devicePubKey.aaguid.equals(expectedDPK.aaguid)) { + return false; + } + if (!devicePubKey.dpk.equals(expectedDPK.dpk)) { + return false; + } + if (!devicePubKey.scope.equals(expectedDPK.scope)) { + return false; + } + if (devicePubKey.fmt && + expectedDPK.fmt && + devicePubKey.fmt === expectedDPK.fmt && + !devicePubKey.fmt.equals(expectedDPK.fmt)) { + return false; + } + if (devicePubKey.attStmt && + expectedDPK.attStmt && + devicePubKey.attStmt === expectedDPK.attStmt && + !devicePubKey.attStmt.equals(expectedDPK.attStmt)) { + return false; + } + return true; +} diff --git a/packages/server/src/helpers/decodeAuthenticatorExtensions.ts b/packages/server/src/helpers/decodeAuthenticatorExtensions.ts index a8898797..246d3b0b 100644 --- a/packages/server/src/helpers/decodeAuthenticatorExtensions.ts +++ b/packages/server/src/helpers/decodeAuthenticatorExtensions.ts @@ -24,10 +24,13 @@ export type AuthenticationExtensionsAuthenticatorOutputs = { }; export type DevicePublicKeyAuthenticatorOutput = { - dpk?: Buffer; - scp?: Buffer; - sig?: string; - aaguid?: Buffer; + aaguid: Buffer; + dpk: Buffer; + scope: Buffer; + nonce?: Buffer; + fmt?: Buffer; + attStmt?: Buffer; + sig?: Buffer; }; // TODO: Need to verify this format From f124eca84acc412ca5bfc72d4549d2e25d9488a0 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Thu, 18 Aug 2022 18:50:53 +0900 Subject: [PATCH 04/37] Bump the version to 6.0.0 --- .../server/src/extensions/devicePubKey.test.ts | 4 ++-- packages/server/src/extensions/devicePubKey.ts | 16 ++++++---------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/server/src/extensions/devicePubKey.test.ts b/packages/server/src/extensions/devicePubKey.test.ts index d923f78f..90e46124 100644 --- a/packages/server/src/extensions/devicePubKey.test.ts +++ b/packages/server/src/extensions/devicePubKey.test.ts @@ -1,6 +1,6 @@ import { verifyDpkSignature } from './devicePubKey'; -it('should verify a device public key extension', () => { +it('should verify a device public key extension', async () => { const credentialID = 'cxjDB1h5nG6jpQW3EeeZNA'; const clientDataJSON = 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoicTh1SVR0d0czMkhUU3RmdlVxVTcwWXNGNFJfS1A4WnZEYkVESVpZekNDdyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9'; const devicePubKey = { @@ -12,6 +12,6 @@ it('should verify a device public key extension', () => { } const signature = devicePubKey.sig; - const result = verifyDpkSignature(credentialID, clientDataJSON, devicePubKey, signature); + const result = await verifyDpkSignature(credentialID, clientDataJSON, devicePubKey, signature); expect(result).toEqual(true); }); diff --git a/packages/server/src/extensions/devicePubKey.ts b/packages/server/src/extensions/devicePubKey.ts index 15673098..4cb7b5e9 100644 --- a/packages/server/src/extensions/devicePubKey.ts +++ b/packages/server/src/extensions/devicePubKey.ts @@ -1,7 +1,6 @@ import base64url from "base64url"; import { toHash } from "../helpers/toHash"; import { verifySignature } from "../helpers/verifySignature"; -import { convertPublicKeyToPEM } from "../helpers/convertPublicKeyToPEM"; import { DevicePublicKeyAuthenticatorOutput } from "helpers/decodeAuthenticatorExtensions"; /** @@ -14,23 +13,23 @@ import { DevicePublicKeyAuthenticatorOutput } from "helpers/decodeAuthenticatorE * @param nonce * @param dpk * @param signature - * @returns + * @returns Promise */ -export function verifyDpkSignature( +export async function verifyDpkSignature( credentialID: string, clientDataJSON: string, devicePubKey: DevicePublicKeyAuthenticatorOutput, signature: Buffer, -): boolean { +): Promise { const rawId = base64url.toBuffer(credentialID); const clientDataHash = toHash(base64url.toBuffer(clientDataJSON)); const nonce = devicePubKey.nonce ? devicePubKey.nonce : Buffer.from(''); const signatureBase = Buffer.concat([rawId, clientDataHash, nonce]); - const publicKey = convertPublicKeyToPEM(devicePubKey.dpk); + const credentialPublicKey = devicePubKey.dpk; // TODO: Implement a logic to verify attestation signatures - return verifySignature(signature, signatureBase, publicKey); + return verifySignature({ signature, signatureBase, credentialPublicKey }); } /** @@ -40,12 +39,9 @@ export function verifyDpkSignature( * `fmt`, and `attStmt` values corresponding to the extracted * *attObjForDevicePublicKey* fields, then perform binary equality checks * between the corresponding stored values and the extracted field values. - * The Relying Party may have more than one set of `{aaguid, dpk, scope, fmt, - * attStmt}` values mapped to the user account and *credential*.id pair and - * each set must be checked. * @param devicePubKey * @param expectedDPK - * @returns + * @returns boolean */ export function verifyDevicePublicKey( devicePubKey: DevicePublicKeyAuthenticatorOutput, From 82b74ff3fd66e84c767567f170cc6611ebb78c51 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Thu, 18 Aug 2022 21:22:41 +0900 Subject: [PATCH 05/37] Add temporary attestation verification --- .../src/extensions/devicePubKey.test.ts | 4 +- .../server/src/extensions/devicePubKey.ts | 81 ++++++++++++++++--- .../helpers/decodeAuthenticatorExtensions.ts | 5 +- 3 files changed, 73 insertions(+), 17 deletions(-) diff --git a/packages/server/src/extensions/devicePubKey.test.ts b/packages/server/src/extensions/devicePubKey.test.ts index 90e46124..0eaa7813 100644 --- a/packages/server/src/extensions/devicePubKey.test.ts +++ b/packages/server/src/extensions/devicePubKey.test.ts @@ -1,8 +1,8 @@ import { verifyDpkSignature } from './devicePubKey'; it('should verify a device public key extension', async () => { - const credentialID = 'cxjDB1h5nG6jpQW3EeeZNA'; const clientDataJSON = 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoicTh1SVR0d0czMkhUU3RmdlVxVTcwWXNGNFJfS1A4WnZEYkVESVpZekNDdyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9'; + const authData = Buffer.from('0D75FCC563FDA779DB2E343EEA489888758B78549D493A4FDBEA1CD96AA31CC4C5000000000000000000000000000000000000000000107318C30758799C6EA3A505B711E79934A50102032620012158208BA46FDB7E12D19439ADADE98889100833EC6CAA04DE031530B391C322506A882258209A6E86CC13D2CCFF486099D7FBCF51FF398A97AFAA412790DAAA26102E82AF7DA16C6465766963655075624B6579A56364706B584DA5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513637369675846304402200B1F095D8FCE1E0AC83D7F47C70FD87296950AF0DFD318E04A0503E836F7D68D02200A12147DD6CED4705ABF16D9190C48B78BF6DC5A852C1DA7CF08A9F9ABC9E9EB656E6F6E6365406573636F70654100666161677569645000000000000000000000000000000000', 'hex'); const devicePubKey = { aaguid: Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), dpk: Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'), @@ -12,6 +12,6 @@ it('should verify a device public key extension', async () => { } const signature = devicePubKey.sig; - const result = await verifyDpkSignature(credentialID, clientDataJSON, devicePubKey, signature); + const result = await verifyDpkSignature(clientDataJSON, authData, devicePubKey, signature); expect(result).toEqual(true); }); diff --git a/packages/server/src/extensions/devicePubKey.ts b/packages/server/src/extensions/devicePubKey.ts index 4cb7b5e9..86f6c5f8 100644 --- a/packages/server/src/extensions/devicePubKey.ts +++ b/packages/server/src/extensions/devicePubKey.ts @@ -1,7 +1,16 @@ import base64url from "base64url"; import { toHash } from "../helpers/toHash"; import { verifySignature } from "../helpers/verifySignature"; -import { DevicePublicKeyAuthenticatorOutput } from "helpers/decodeAuthenticatorExtensions"; +import { DevicePublicKeyAuthenticatorOutput } from "../helpers/decodeAuthenticatorExtensions"; +import { SettingsService } from "../services/settingsService"; +import { AttestationFormatVerifierOpts } from "../registration/verifyRegistrationResponse"; +import { parseAuthenticatorData } from "../helpers/parseAuthenticatorData"; +import { verifyAttestationFIDOU2F } from '../registration/verifications/verifyAttestationFIDOU2F'; +import { verifyAttestationPacked } from '../registration/verifications/verifyAttestationPacked'; +import { verifyAttestationAndroidSafetyNet } from '../registration/verifications/verifyAttestationAndroidSafetyNet'; +import { verifyAttestationTPM } from '../registration//verifications/tpm/verifyAttestationTPM'; +import { verifyAttestationAndroidKey } from '../registration/verifications/verifyAttestationAndroidKey'; +import { verifyAttestationApple } from '../registration/verifications/verifyAttestationApple'; /** * https://pr-preview.s3.amazonaws.com/w3c/webauthn/pull/1663.html#sctn-device-publickey-extension-verification-create @@ -16,18 +25,67 @@ import { DevicePublicKeyAuthenticatorOutput } from "helpers/decodeAuthenticatorE * @returns Promise */ export async function verifyDpkSignature( - credentialID: string, clientDataJSON: string, + authData: Buffer, devicePubKey: DevicePublicKeyAuthenticatorOutput, signature: Buffer, ): Promise { - const rawId = base64url.toBuffer(credentialID); const clientDataHash = toHash(base64url.toBuffer(clientDataJSON)); + const parsedAuthData = parseAuthenticatorData(authData); + const { rpIdHash, credentialID } = parsedAuthData; + + if (!credentialID) { + // `authData` without `credentialID` can't be verified. + return false; + } + const nonce = devicePubKey.nonce ? devicePubKey.nonce : Buffer.from(''); - const signatureBase = Buffer.concat([rawId, clientDataHash, nonce]); + const signatureBase = Buffer.concat([credentialID, clientDataHash, nonce]); const credentialPublicKey = devicePubKey.dpk; - // TODO: Implement a logic to verify attestation signatures + // If `fmt` and `attStmt` are not included, skip verification. + if (devicePubKey.fmt && devicePubKey.attStmt) { + const rootCertificates = SettingsService.getRootCertificates({ identifier: devicePubKey.fmt }); + + // Prepare arguments to pass to the relevant verification method + const verifierOpts: AttestationFormatVerifierOpts = { + aaguid: devicePubKey.aaguid, + attStmt: devicePubKey.attStmt, + authData, + clientDataHash, + credentialID, + credentialPublicKey, + rootCertificates, + rpIdHash, + }; + + // TODO: Implement logics to verify attestation signatures + let verified = false; + if (devicePubKey.fmt === 'fido-u2f') { + verified = await verifyAttestationFIDOU2F(verifierOpts); + } else if (devicePubKey.fmt === 'packed') { + verified = await verifyAttestationPacked(verifierOpts); + } else if (devicePubKey.fmt === 'android-safetynet') { + verified = await verifyAttestationAndroidSafetyNet(verifierOpts); + } else if (devicePubKey.fmt === 'android-key') { + verified = await verifyAttestationAndroidKey(verifierOpts); + } else if (devicePubKey.fmt === 'tpm') { + verified = await verifyAttestationTPM(verifierOpts); + } else if (devicePubKey.fmt === 'apple') { + verified = await verifyAttestationApple(verifierOpts); + } else if (devicePubKey.fmt === 'none') { + if (Object.keys(devicePubKey.attStmt).length > 0) { + throw new Error('None attestation had unexpected attestation statement'); + } + // This is the weaker of the attestations, so there's nothing else to really check + verified = true; + } else { + throw new Error(`Unsupported Attestation Format: ${devicePubKey.fmt}`); + } + if (!verified) { + return false; + } + } return verifySignature({ signature, signatureBase, credentialPublicKey }); } @@ -56,16 +114,13 @@ export function verifyDevicePublicKey( if (!devicePubKey.scope.equals(expectedDPK.scope)) { return false; } - if (devicePubKey.fmt && - expectedDPK.fmt && - devicePubKey.fmt === expectedDPK.fmt && - !devicePubKey.fmt.equals(expectedDPK.fmt)) { + if ((devicePubKey.fmt || expectedDPK.fmt) && + devicePubKey.fmt !== expectedDPK.fmt) { return false; } - if (devicePubKey.attStmt && - expectedDPK.attStmt && - devicePubKey.attStmt === expectedDPK.attStmt && - !devicePubKey.attStmt.equals(expectedDPK.attStmt)) { + if (devicePubKey.attStmt || + expectedDPK.attStmt) { + // TODO: Examine if comparing properties is a good idea. return false; } return true; diff --git a/packages/server/src/helpers/decodeAuthenticatorExtensions.ts b/packages/server/src/helpers/decodeAuthenticatorExtensions.ts index 246d3b0b..7ac357f7 100644 --- a/packages/server/src/helpers/decodeAuthenticatorExtensions.ts +++ b/packages/server/src/helpers/decodeAuthenticatorExtensions.ts @@ -1,4 +1,5 @@ import cbor from 'cbor'; +import { AttestationFormat, AttestationStatement } from './decodeAttestationObject'; /** * Convert authenticator extension data buffer to a proper object @@ -28,8 +29,8 @@ export type DevicePublicKeyAuthenticatorOutput = { dpk: Buffer; scope: Buffer; nonce?: Buffer; - fmt?: Buffer; - attStmt?: Buffer; + fmt?: AttestationFormat; + attStmt?: AttestationStatement; sig?: Buffer; }; From f83709cecb69abd2580445c352371184a77a21a4 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Fri, 19 Aug 2022 00:14:01 +0900 Subject: [PATCH 06/37] Update DPK logic --- packages/server/src/extensions/devicePubKey.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/server/src/extensions/devicePubKey.ts b/packages/server/src/extensions/devicePubKey.ts index 86f6c5f8..fff1e61e 100644 --- a/packages/server/src/extensions/devicePubKey.ts +++ b/packages/server/src/extensions/devicePubKey.ts @@ -17,10 +17,9 @@ import { verifyAttestationApple } from '../registration/verifications/verifyAtte * 3. Verify that `signature` is a valid signature over the assertion signature * input by the device public key *dpk*. (The signature algorithm is the same * as for the user credential.) - * @param credentialID * @param clientDataJSON - * @param nonce - * @param dpk + * @param authData + * @param devicePubKey * @param signature * @returns Promise */ @@ -31,8 +30,7 @@ export async function verifyDpkSignature( signature: Buffer, ): Promise { const clientDataHash = toHash(base64url.toBuffer(clientDataJSON)); - const parsedAuthData = parseAuthenticatorData(authData); - const { rpIdHash, credentialID } = parsedAuthData; + const { rpIdHash, credentialID } = parseAuthenticatorData(authData); if (!credentialID) { // `authData` without `credentialID` can't be verified. @@ -114,13 +112,12 @@ export function verifyDevicePublicKey( if (!devicePubKey.scope.equals(expectedDPK.scope)) { return false; } - if ((devicePubKey.fmt || expectedDPK.fmt) && - devicePubKey.fmt !== expectedDPK.fmt) { + if (devicePubKey.fmt !== expectedDPK.fmt) { return false; } if (devicePubKey.attStmt || expectedDPK.attStmt) { - // TODO: Examine if comparing properties is a good idea. + // TODO: Implement deep equal comparison logic return false; } return true; From 1c072b4d8777c7b4ac7c08c26210c875ff225196 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Fri, 19 Aug 2022 14:21:48 +0900 Subject: [PATCH 07/37] DPK update - Implement attStmt check - Expose DPK --- .../src/extensions/devicePubKey.test.ts | 2 ++ .../server/src/extensions/devicePubKey.ts | 36 +++++++++++++++++-- packages/server/src/index.ts | 5 +++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/packages/server/src/extensions/devicePubKey.test.ts b/packages/server/src/extensions/devicePubKey.test.ts index 0eaa7813..2a1ac222 100644 --- a/packages/server/src/extensions/devicePubKey.test.ts +++ b/packages/server/src/extensions/devicePubKey.test.ts @@ -15,3 +15,5 @@ it('should verify a device public key extension', async () => { const result = await verifyDpkSignature(clientDataJSON, authData, devicePubKey, signature); expect(result).toEqual(true); }); + +// TODO: Implement a test for `verifyDevicePublicKey` diff --git a/packages/server/src/extensions/devicePubKey.ts b/packages/server/src/extensions/devicePubKey.ts index fff1e61e..38841742 100644 --- a/packages/server/src/extensions/devicePubKey.ts +++ b/packages/server/src/extensions/devicePubKey.ts @@ -117,8 +117,40 @@ export function verifyDevicePublicKey( } if (devicePubKey.attStmt || expectedDPK.attStmt) { - // TODO: Implement deep equal comparison logic - return false; + const { attStmt } = devicePubKey; + const expectedAttStmt = expectedDPK.attStmt; + if (!attStmt || !expectedAttStmt) { + return false; + } + if (!attStmt.sig || !expectedAttStmt.sig || !attStmt.sig.equals(expectedAttStmt.sig)) { + return false; + } + if (!attStmt.x5c || !expectedAttStmt.x5c) { + return false; + } + if (attStmt.x5c.length !== expectedAttStmt.x5c.length) { + return false; + } + for (let i = 0; i < attStmt.x5c.length; i++) { + if (!attStmt.x5c[i].equals(expectedAttStmt.x5c[i])) { + return false; + } + } + if (!attStmt.response || !expectedAttStmt.response || !attStmt.response.equals(expectedAttStmt.response)) { + return false; + } + if (attStmt.alg !== expectedAttStmt.alg) { + return false; + } + if (attStmt.ver !== expectedAttStmt.ver) { + return false; + } + if (!attStmt.certInfo || !expectedAttStmt.certInfo || !attStmt.certInfo.equals(expectedAttStmt.certInfo)) { + return false; + } + if (!attStmt.pubArea || !expectedAttStmt.pubArea || !attStmt.pubArea.equals(expectedAttStmt.pubArea)) { + return false; + } } return true; } diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index e15054ad..ccdf51fd 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -8,6 +8,8 @@ import { generateAuthenticationOptions } from './authentication/generateAuthenti import { verifyAuthenticationResponse } from './authentication/verifyAuthenticationResponse'; import { MetadataService } from './services/metadataService'; import { SettingsService } from './services/settingsService'; +import { verifyDpkSignature, verifyDevicePublicKey } from 'extensions/devicePubKey'; +import { DevicePublicKeyAuthenticatorOutput } from 'helpers/decodeAuthenticatorExtensions'; export { generateRegistrationOptions, @@ -16,6 +18,8 @@ export { verifyAuthenticationResponse, MetadataService, SettingsService, + verifyDpkSignature, + verifyDevicePublicKey, }; import type { GenerateRegistrationOptionsOpts } from './registration/generateRegistrationOptions'; @@ -38,4 +42,5 @@ export type { VerifyAuthenticationResponseOpts, VerifiedRegistrationResponse, VerifiedAuthenticationResponse, + DevicePublicKeyAuthenticatorOutput, }; From 6dc3e804f9ac0a14c3bea9b6fbe20754241694ca Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Sat, 20 Aug 2022 19:34:45 +0900 Subject: [PATCH 08/37] Update DPK verifications --- .../server/src/extensions/devicePubKey.ts | 156 ------------------ .../verifyDevicePublicKey.test.ts | 1 + .../devicePublicKey/verifyDevicePublicKey.ts | 69 ++++++++ .../verifyDpkSignature.test.ts} | 4 +- .../devicePublicKey/verifyDpkSignature.ts | 99 +++++++++++ packages/server/src/index.ts | 3 +- 6 files changed, 172 insertions(+), 160 deletions(-) delete mode 100644 packages/server/src/extensions/devicePubKey.ts create mode 100644 packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.test.ts create mode 100644 packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.ts rename packages/server/src/extensions/{devicePubKey.test.ts => devicePublicKey/verifyDpkSignature.test.ts} (94%) create mode 100644 packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts diff --git a/packages/server/src/extensions/devicePubKey.ts b/packages/server/src/extensions/devicePubKey.ts deleted file mode 100644 index 38841742..00000000 --- a/packages/server/src/extensions/devicePubKey.ts +++ /dev/null @@ -1,156 +0,0 @@ -import base64url from "base64url"; -import { toHash } from "../helpers/toHash"; -import { verifySignature } from "../helpers/verifySignature"; -import { DevicePublicKeyAuthenticatorOutput } from "../helpers/decodeAuthenticatorExtensions"; -import { SettingsService } from "../services/settingsService"; -import { AttestationFormatVerifierOpts } from "../registration/verifyRegistrationResponse"; -import { parseAuthenticatorData } from "../helpers/parseAuthenticatorData"; -import { verifyAttestationFIDOU2F } from '../registration/verifications/verifyAttestationFIDOU2F'; -import { verifyAttestationPacked } from '../registration/verifications/verifyAttestationPacked'; -import { verifyAttestationAndroidSafetyNet } from '../registration/verifications/verifyAttestationAndroidSafetyNet'; -import { verifyAttestationTPM } from '../registration//verifications/tpm/verifyAttestationTPM'; -import { verifyAttestationAndroidKey } from '../registration/verifications/verifyAttestationAndroidKey'; -import { verifyAttestationApple } from '../registration/verifications/verifyAttestationApple'; - -/** - * https://pr-preview.s3.amazonaws.com/w3c/webauthn/pull/1663.html#sctn-device-publickey-extension-verification-create - * 3. Verify that `signature` is a valid signature over the assertion signature - * input by the device public key *dpk*. (The signature algorithm is the same - * as for the user credential.) - * @param clientDataJSON - * @param authData - * @param devicePubKey - * @param signature - * @returns Promise - */ -export async function verifyDpkSignature( - clientDataJSON: string, - authData: Buffer, - devicePubKey: DevicePublicKeyAuthenticatorOutput, - signature: Buffer, -): Promise { - const clientDataHash = toHash(base64url.toBuffer(clientDataJSON)); - const { rpIdHash, credentialID } = parseAuthenticatorData(authData); - - if (!credentialID) { - // `authData` without `credentialID` can't be verified. - return false; - } - - const nonce = devicePubKey.nonce ? devicePubKey.nonce : Buffer.from(''); - const signatureBase = Buffer.concat([credentialID, clientDataHash, nonce]); - const credentialPublicKey = devicePubKey.dpk; - - // If `fmt` and `attStmt` are not included, skip verification. - if (devicePubKey.fmt && devicePubKey.attStmt) { - const rootCertificates = SettingsService.getRootCertificates({ identifier: devicePubKey.fmt }); - - // Prepare arguments to pass to the relevant verification method - const verifierOpts: AttestationFormatVerifierOpts = { - aaguid: devicePubKey.aaguid, - attStmt: devicePubKey.attStmt, - authData, - clientDataHash, - credentialID, - credentialPublicKey, - rootCertificates, - rpIdHash, - }; - - // TODO: Implement logics to verify attestation signatures - let verified = false; - if (devicePubKey.fmt === 'fido-u2f') { - verified = await verifyAttestationFIDOU2F(verifierOpts); - } else if (devicePubKey.fmt === 'packed') { - verified = await verifyAttestationPacked(verifierOpts); - } else if (devicePubKey.fmt === 'android-safetynet') { - verified = await verifyAttestationAndroidSafetyNet(verifierOpts); - } else if (devicePubKey.fmt === 'android-key') { - verified = await verifyAttestationAndroidKey(verifierOpts); - } else if (devicePubKey.fmt === 'tpm') { - verified = await verifyAttestationTPM(verifierOpts); - } else if (devicePubKey.fmt === 'apple') { - verified = await verifyAttestationApple(verifierOpts); - } else if (devicePubKey.fmt === 'none') { - if (Object.keys(devicePubKey.attStmt).length > 0) { - throw new Error('None attestation had unexpected attestation statement'); - } - // This is the weaker of the attestations, so there's nothing else to really check - verified = true; - } else { - throw new Error(`Unsupported Attestation Format: ${devicePubKey.fmt}`); - } - if (!verified) { - return false; - } - } - - return verifySignature({ signature, signatureBase, credentialPublicKey }); -} - -/** - * https://pr-preview.s3.amazonaws.com/w3c/webauthn/pull/1663.html#sctn-device-publickey-extension-verification-get - * 4. If the Relying Party's user account mapped to the *credential*.id in play - * (i.e., for the user being authenticated) holds `aaguid`, `dpk`, `scope`, - * `fmt`, and `attStmt` values corresponding to the extracted - * *attObjForDevicePublicKey* fields, then perform binary equality checks - * between the corresponding stored values and the extracted field values. - * @param devicePubKey - * @param expectedDPK - * @returns boolean - */ -export function verifyDevicePublicKey( - devicePubKey: DevicePublicKeyAuthenticatorOutput, - expectedDPK: DevicePublicKeyAuthenticatorOutput -): boolean { - if (!devicePubKey.aaguid.equals(expectedDPK.aaguid)) { - return false; - } - if (!devicePubKey.dpk.equals(expectedDPK.dpk)) { - return false; - } - if (!devicePubKey.scope.equals(expectedDPK.scope)) { - return false; - } - if (devicePubKey.fmt !== expectedDPK.fmt) { - return false; - } - if (devicePubKey.attStmt || - expectedDPK.attStmt) { - const { attStmt } = devicePubKey; - const expectedAttStmt = expectedDPK.attStmt; - if (!attStmt || !expectedAttStmt) { - return false; - } - if (!attStmt.sig || !expectedAttStmt.sig || !attStmt.sig.equals(expectedAttStmt.sig)) { - return false; - } - if (!attStmt.x5c || !expectedAttStmt.x5c) { - return false; - } - if (attStmt.x5c.length !== expectedAttStmt.x5c.length) { - return false; - } - for (let i = 0; i < attStmt.x5c.length; i++) { - if (!attStmt.x5c[i].equals(expectedAttStmt.x5c[i])) { - return false; - } - } - if (!attStmt.response || !expectedAttStmt.response || !attStmt.response.equals(expectedAttStmt.response)) { - return false; - } - if (attStmt.alg !== expectedAttStmt.alg) { - return false; - } - if (attStmt.ver !== expectedAttStmt.ver) { - return false; - } - if (!attStmt.certInfo || !expectedAttStmt.certInfo || !attStmt.certInfo.equals(expectedAttStmt.certInfo)) { - return false; - } - if (!attStmt.pubArea || !expectedAttStmt.pubArea || !attStmt.pubArea.equals(expectedAttStmt.pubArea)) { - return false; - } - } - return true; -} diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.test.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.test.ts new file mode 100644 index 00000000..a6a218be --- /dev/null +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.test.ts @@ -0,0 +1 @@ +// TODO: Implement a test for `verifyDevicePublicKey` diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.ts new file mode 100644 index 00000000..157e17ef --- /dev/null +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.ts @@ -0,0 +1,69 @@ +import { DevicePublicKeyAuthenticatorOutput } from "../../helpers/decodeAuthenticatorExtensions"; + +/** + * https://pr-preview.s3.amazonaws.com/w3c/webauthn/pull/1663.html#sctn-device-publickey-extension-verification-get + * 4. If the Relying Party's user account mapped to the *credential*.id in play + * (i.e., for the user being authenticated) holds `aaguid`, `dpk`, `scope`, + * `fmt`, and `attStmt` values corresponding to the extracted + * *attObjForDevicePublicKey* fields, then perform binary equality checks + * between the corresponding stored values and the extracted field values. + * @param devicePubKey + * @param expectedDPK + * @returns boolean + */ +export function verifyDevicePublicKey( + devicePubKey: DevicePublicKeyAuthenticatorOutput, + expectedDPK: DevicePublicKeyAuthenticatorOutput +): boolean { + if (!devicePubKey.aaguid.equals(expectedDPK.aaguid)) { + return false; + } + if (!devicePubKey.dpk.equals(expectedDPK.dpk)) { + return false; + } + if (!devicePubKey.scope.equals(expectedDPK.scope)) { + return false; + } + if (devicePubKey.fmt !== expectedDPK.fmt) { + return false; + } + if (devicePubKey.attStmt && expectedDPK.attStmt) { + const { attStmt } = devicePubKey; + const expectedAttStmt = expectedDPK.attStmt; + + if (!attStmt.sig || !expectedAttStmt.sig || !attStmt.sig.equals(expectedAttStmt.sig)) { + return false; + } + if (!attStmt.x5c || !expectedAttStmt.x5c) { + return false; + } + if (attStmt.x5c.length !== expectedAttStmt.x5c.length) { + return false; + } + for (let i = 0; i < attStmt.x5c.length; i++) { + if (!attStmt.x5c[i].equals(expectedAttStmt.x5c[i])) { + return false; + } + } + if (!attStmt.response || !expectedAttStmt.response || !attStmt.response.equals(expectedAttStmt.response)) { + return false; + } + if (attStmt.alg !== expectedAttStmt.alg) { + return false; + } + if (attStmt.ver !== expectedAttStmt.ver) { + return false; + } + if (!attStmt.certInfo || !expectedAttStmt.certInfo || !attStmt.certInfo.equals(expectedAttStmt.certInfo)) { + return false; + } + if (!attStmt.pubArea || !expectedAttStmt.pubArea || !attStmt.pubArea.equals(expectedAttStmt.pubArea)) { + return false; + } + } else { + // `attStmt` is required field, though at the moment, as the test attestation + // omits it. Ignore this case intentionally. + // return false; + } + return true; +} \ No newline at end of file diff --git a/packages/server/src/extensions/devicePubKey.test.ts b/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.test.ts similarity index 94% rename from packages/server/src/extensions/devicePubKey.test.ts rename to packages/server/src/extensions/devicePublicKey/verifyDpkSignature.test.ts index 2a1ac222..4657ceaf 100644 --- a/packages/server/src/extensions/devicePubKey.test.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.test.ts @@ -1,4 +1,4 @@ -import { verifyDpkSignature } from './devicePubKey'; +import { verifyDpkSignature } from './verifyDpkSignature'; it('should verify a device public key extension', async () => { const clientDataJSON = 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoicTh1SVR0d0czMkhUU3RmdlVxVTcwWXNGNFJfS1A4WnZEYkVESVpZekNDdyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9'; @@ -15,5 +15,3 @@ it('should verify a device public key extension', async () => { const result = await verifyDpkSignature(clientDataJSON, authData, devicePubKey, signature); expect(result).toEqual(true); }); - -// TODO: Implement a test for `verifyDevicePublicKey` diff --git a/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts b/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts new file mode 100644 index 00000000..6bcd6921 --- /dev/null +++ b/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts @@ -0,0 +1,99 @@ +import base64url from "base64url"; +import { toHash } from "../../helpers/toHash"; +import { verifySignature } from "../../helpers/verifySignature"; +import { DevicePublicKeyAuthenticatorOutput } from "../../helpers/decodeAuthenticatorExtensions"; +import { SettingsService } from "../../services/settingsService"; +import { AttestationFormatVerifierOpts } from "../../registration/verifyRegistrationResponse"; +import { parseAuthenticatorData } from "../../helpers/parseAuthenticatorData"; +import { verifyAttestationFIDOU2F } from '../../registration/verifications/verifyAttestationFIDOU2F'; +import { verifyAttestationPacked } from '../../registration/verifications/verifyAttestationPacked'; +import { verifyAttestationAndroidSafetyNet } from '../../registration/verifications/verifyAttestationAndroidSafetyNet'; +import { verifyAttestationTPM } from '../../registration/verifications/tpm/verifyAttestationTPM'; +import { verifyAttestationAndroidKey } from '../../registration/verifications/verifyAttestationAndroidKey'; +import { verifyAttestationApple } from '../../registration/verifications/verifyAttestationApple'; + +/** + * https://pr-preview.s3.amazonaws.com/w3c/webauthn/pull/1663.html#sctn-device-publickey-extension-verification-create + * 3. Verify that `signature` is a valid signature over the assertion signature + * input by the device public key *dpk*. (The signature algorithm is the same + * as for the user credential.) + * @param clientDataJSON + * @param authData + * @param devicePubKey + * @param signature + * @returns Promise + */ +export async function verifyDpkSignature( + options: VerifyDpkSignatureOpts +): Promise { + const { clientDataJSON, authData, devicePubKey, signature } = options; + const clientDataHash = toHash(base64url.toBuffer(clientDataJSON)); + const { rpIdHash, credentialID } = parseAuthenticatorData(authData); + + if (!credentialID) { + // `authData` without `credentialID` can't be verified. + return false; + } + + const nonce = devicePubKey.nonce ? devicePubKey.nonce : Buffer.from(''); + // According to the spec, `authData` and `clientDataHash` are concatenated as + // the signature base, but this is an interim implementation. + const signatureBase = Buffer.concat([credentialID, clientDataHash, nonce]); + const credentialPublicKey = devicePubKey.dpk; + + if (devicePubKey.fmt && devicePubKey.attStmt) { + const rootCertificates = SettingsService.getRootCertificates({ identifier: devicePubKey.fmt }); + + // Prepare arguments to pass to the relevant verification method + const verifierOpts: AttestationFormatVerifierOpts = { + aaguid: devicePubKey.aaguid, + attStmt: devicePubKey.attStmt, + authData, + clientDataHash, + credentialID, + credentialPublicKey, + rootCertificates, + rpIdHash, + }; + + // TODO: Implement logics to verify attestation signatures + let verified = false; + if (devicePubKey.fmt === 'fido-u2f') { + verified = await verifyAttestationFIDOU2F(verifierOpts); + } else if (devicePubKey.fmt === 'packed') { + verified = await verifyAttestationPacked(verifierOpts); + } else if (devicePubKey.fmt === 'android-safetynet') { + verified = await verifyAttestationAndroidSafetyNet(verifierOpts); + } else if (devicePubKey.fmt === 'android-key') { + verified = await verifyAttestationAndroidKey(verifierOpts); + } else if (devicePubKey.fmt === 'tpm') { + verified = await verifyAttestationTPM(verifierOpts); + } else if (devicePubKey.fmt === 'apple') { + verified = await verifyAttestationApple(verifierOpts); + } else if (devicePubKey.fmt === 'none') { + if (Object.keys(devicePubKey.attStmt).length > 0) { + throw new Error('None attestation had unexpected attestation statement'); + } + // This is the weaker of the attestations, so there's nothing else to really check + verified = true; + } else { + throw new Error(`Unsupported Attestation Format: ${devicePubKey.fmt}`); + } + if (!verified) { + return false; + } + } else { + // `fmt` and `attStmt` are required fields, though at the moment, as the test + // attestation omits it. Ignore this case intentionally. + // return false; + } + + return verifySignature({ signature, signatureBase, credentialPublicKey }); +} + +export type VerifyDpkSignatureOpts = { + clientDataJSON: string; + authData: Buffer; + devicePubKey: DevicePublicKeyAuthenticatorOutput; + signature: Buffer; +}; diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index ccdf51fd..b223f01d 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -8,7 +8,8 @@ import { generateAuthenticationOptions } from './authentication/generateAuthenti import { verifyAuthenticationResponse } from './authentication/verifyAuthenticationResponse'; import { MetadataService } from './services/metadataService'; import { SettingsService } from './services/settingsService'; -import { verifyDpkSignature, verifyDevicePublicKey } from 'extensions/devicePubKey'; +import { verifyDpkSignature } from 'extensions/devicePublicKey/verifyDpkSignature'; +import { verifyDevicePublicKey } from 'extensions/devicePublicKey/verifyDevicePublicKey'; import { DevicePublicKeyAuthenticatorOutput } from 'helpers/decodeAuthenticatorExtensions'; export { From 8e8cfb469045846ca79cdf9df03b60909a42a6ad Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Sun, 21 Aug 2022 18:08:13 +0900 Subject: [PATCH 09/37] Reorganize the interface --- .../verifyDevicePublicKey.test.ts | 5 +- .../verifyDpkSignature.test.ts | 45 +++++++++++++-- .../devicePublicKey/verifyDpkSignature.ts | 57 +++++++++++++++---- packages/server/src/index.ts | 6 +- 4 files changed, 93 insertions(+), 20 deletions(-) diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.test.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.test.ts index a6a218be..d48322f5 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.test.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.test.ts @@ -1 +1,4 @@ -// TODO: Implement a test for `verifyDevicePublicKey` +it("should verify device public key", async () => { + // TODO: Implement a test for `verifyDevicePublicKey` + expect(true).toEqual(true); +}); diff --git a/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.test.ts b/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.test.ts index 4657ceaf..30a0cfc6 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.test.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.test.ts @@ -1,8 +1,45 @@ +import { AuthenticationCredentialJSON, AuthenticatorAssertionResponseJSON, AuthenticatorAttestationResponseJSON, RegistrationCredentialJSON } from '@simplewebauthn/typescript-types'; import { verifyDpkSignature } from './verifyDpkSignature'; -it('should verify a device public key extension', async () => { - const clientDataJSON = 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoicTh1SVR0d0czMkhUU3RmdlVxVTcwWXNGNFJfS1A4WnZEYkVESVpZekNDdyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9'; - const authData = Buffer.from('0D75FCC563FDA779DB2E343EEA489888758B78549D493A4FDBEA1CD96AA31CC4C5000000000000000000000000000000000000000000107318C30758799C6EA3A505B711E79934A50102032620012158208BA46FDB7E12D19439ADADE98889100833EC6CAA04DE031530B391C322506A882258209A6E86CC13D2CCFF486099D7FBCF51FF398A97AFAA412790DAAA26102E82AF7DA16C6465766963655075624B6579A56364706B584DA5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513637369675846304402200B1F095D8FCE1E0AC83D7F47C70FD87296950AF0DFD318E04A0503E836F7D68D02200A12147DD6CED4705ABF16D9190C48B78BF6DC5A852C1DA7CF08A9F9ABC9E9EB656E6F6E6365406573636F70654100666161677569645000000000000000000000000000000000', 'hex'); +it("should verify a registration response's device public key signature", async () => { + const credential = { + response: { + clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiNFF3dmdUVjhlaTF5TzYyaDF2bVFNWFM2SDZ3UGc0YWt2eDNKcF9VakF3cyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', + attestationObject: 'o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVkBaQ11_MVj_ad52y40PupImIh1i3hUnUk6T9vqHNlqoxzExQAAAAAAAAAAAAAAAAAAAAAAAAAAABBzGMMHWHmcbqOlBbcR55k0pQECAyYgASFYIIukb9t-EtGUOa2t6YiJEAgz7GyqBN4DFTCzkcMiUGqIIlggmm6GzBPSzP9IYJnX-89R_zmKl6-qQSeQ2qomEC6Cr32hbGRldmljZVB1YktleaVjZHBrWE2lAQIDJiABIVgg7erT_TV2nCPTQN3Bgwp_8g5zVfKdHHWqDcK2rBgup9MiWCA0UdyZkq-UaCW0QZRfydE04Xtzql_qlYA1HnyT9dNlE2NzaWdYRjBEAiALHwldj84eCsg9f0fHD9hylpUK8N_TGOBKBQPoNvfWjQIgChIUfdbO1HBavxbZGQxIt4v23FqFLB2nzwip-avJ6etlbm9uY2VAZXNjb3BlQQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAAA=', + }, + id: 'cxjDB1h5nG6jpQW3EeeZNA', + rawId: 'cxjDB1h5nG6jpQW3EeeZNA', + type: 'public-key', + transports: [], + clientExtensionResults: '' + } as RegistrationCredentialJSON; + + const devicePubKey = { + aaguid: Buffer.from('00000000000000000000000000000000', 'hex'), + dpk: Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'), + sig: Buffer.from('304402200B1F095D8FCE1E0AC83D7F47C70FD87296950AF0DFD318E04A0503E836F7D68D02200A12147DD6CED4705ABF16D9190C48B78BF6DC5A852C1DA7CF08A9F9ABC9E9EB', 'hex'), + nonce: Buffer.from('', 'hex'), + scope: Buffer.from('00', 'hex') + } + const signature = devicePubKey.sig; + + const result = await verifyDpkSignature({ credential, devicePubKey, signature }); + expect(result).toEqual(true); +}); + +it("should verify an authentication response's device public key signature", async () => { + const credential = { + response: { + clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoicTh1SVR0d0czMkhUU3RmdlVxVTcwWXNGNFJfS1A4WnZEYkVESVpZekNDdyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', + authenticatorData: 'DXX8xWP9p3nbLjQ-6kiYiHWLeFSdSTpP2-oc2WqjHMSFAAAAAKFsZGV2aWNlUHViS2V5pWNkcGtYTaUBAgMmIAEhWCDt6tP9NXacI9NA3cGDCn_yDnNV8p0cdaoNwrasGC6n0yJYIDRR3JmSr5RoJbRBlF_J0TThe3OqX-qVgDUefJP102UTY3NpZ1hHMEUCIQC8bdmvXke7OrgnMSmeroKneRieTkFuOg43o7pkw4-ZEgIgVnHvrA6M1t4dNkDOfk6J06l-BRe2A9isKPI-Th905jllbm9uY2VAZXNjb3BlQQBmYWFndWlkULk_2WHy5kYvsSKCACJH3ng=', + signature: 'MEUCIEXJbR9-0cpcUdGAJi25Qf3z22lnCidx3box2b0bWKhwAiEAkp5zCbVbN2CEtIyezQEa9SOG62xm8YHdE1G5qov64j8=', + userHandle: 'b2FPajFxcmM4MWo3QkFFel9RN2lEakh5RVNlU2RLNDF0Sl92eHpQYWV5UQ==', + }, + id: 'cxjDB1h5nG6jpQW3EeeZNA', + rawId: 'cxjDB1h5nG6jpQW3EeeZNA', + type: 'public-key', + } as AuthenticationCredentialJSON; + const devicePubKey = { aaguid: Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), dpk: Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'), @@ -12,6 +49,6 @@ it('should verify a device public key extension', async () => { } const signature = devicePubKey.sig; - const result = await verifyDpkSignature(clientDataJSON, authData, devicePubKey, signature); + const result = await verifyDpkSignature({ credential, devicePubKey, signature }); expect(result).toEqual(true); }); diff --git a/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts b/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts index 6bcd6921..f32fd8c4 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts @@ -11,24 +11,52 @@ import { verifyAttestationAndroidSafetyNet } from '../../registration/verificati import { verifyAttestationTPM } from '../../registration/verifications/tpm/verifyAttestationTPM'; import { verifyAttestationAndroidKey } from '../../registration/verifications/verifyAttestationAndroidKey'; import { verifyAttestationApple } from '../../registration/verifications/verifyAttestationApple'; +import { + AuthenticationCredentialJSON, + AuthenticatorAssertionResponseJSON, + RegistrationCredentialJSON, + AuthenticatorAttestationResponseJSON +} from "@simplewebauthn/typescript-types"; +import { decodeAttestationObject } from "../../helpers/decodeAttestationObject"; + +export type VerifyDpkSignatureOpts = { + credential: RegistrationCredentialJSON | AuthenticationCredentialJSON + devicePubKey: DevicePublicKeyAuthenticatorOutput; + signature: Buffer; +}; /** * https://pr-preview.s3.amazonaws.com/w3c/webauthn/pull/1663.html#sctn-device-publickey-extension-verification-create * 3. Verify that `signature` is a valid signature over the assertion signature * input by the device public key *dpk*. (The signature algorithm is the same * as for the user credential.) - * @param clientDataJSON - * @param authData - * @param devicePubKey - * @param signature + * @param options * @returns Promise */ export async function verifyDpkSignature( options: VerifyDpkSignatureOpts ): Promise { - const { clientDataJSON, authData, devicePubKey, signature } = options; + const { credential, devicePubKey, signature } = options; + + let authData; + if (isAuthenticationResponse(credential)) { + const { authenticatorData } = credential.response; + authData = base64url.toBuffer(authenticatorData); + } + if (isRegistrationResponse(credential)) { + const attestationObject = base64url.toBuffer(credential.response.attestationObject); + const { authData: authenticatorData } = decodeAttestationObject(attestationObject); + authData = authenticatorData; + } + if (authData === undefined) { + throw new Error("AuthenticatorResponse doesn't include authenticatorData"); + } + + const { clientDataJSON } = credential.response; const clientDataHash = toHash(base64url.toBuffer(clientDataJSON)); - const { rpIdHash, credentialID } = parseAuthenticatorData(authData); + const { id } = credential; + const credentialID = base64url.toBuffer(id); + const { rpIdHash } = parseAuthenticatorData(authData); if (!credentialID) { // `authData` without `credentialID` can't be verified. @@ -91,9 +119,14 @@ export async function verifyDpkSignature( return verifySignature({ signature, signatureBase, credentialPublicKey }); } -export type VerifyDpkSignatureOpts = { - clientDataJSON: string; - authData: Buffer; - devicePubKey: DevicePublicKeyAuthenticatorOutput; - signature: Buffer; -}; +function isAuthenticationResponse( + cred: AuthenticationCredentialJSON | RegistrationCredentialJSON +): cred is AuthenticationCredentialJSON { + return Object.keys(cred.response as AuthenticatorAssertionResponseJSON).indexOf('authenticatorData') >= 0; +} + +function isRegistrationResponse( + cred: AuthenticationCredentialJSON | RegistrationCredentialJSON +): cred is RegistrationCredentialJSON { + return Object.keys(cred.response as AuthenticatorAttestationResponseJSON).indexOf('attestationObject') >= 0; +} diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index b223f01d..82faea96 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -8,9 +8,9 @@ import { generateAuthenticationOptions } from './authentication/generateAuthenti import { verifyAuthenticationResponse } from './authentication/verifyAuthenticationResponse'; import { MetadataService } from './services/metadataService'; import { SettingsService } from './services/settingsService'; -import { verifyDpkSignature } from 'extensions/devicePublicKey/verifyDpkSignature'; -import { verifyDevicePublicKey } from 'extensions/devicePublicKey/verifyDevicePublicKey'; -import { DevicePublicKeyAuthenticatorOutput } from 'helpers/decodeAuthenticatorExtensions'; +import { verifyDpkSignature } from './extensions/devicePublicKey/verifyDpkSignature'; +import { verifyDevicePublicKey } from './extensions/devicePublicKey/verifyDevicePublicKey'; +import { DevicePublicKeyAuthenticatorOutput } from './helpers/decodeAuthenticatorExtensions'; export { generateRegistrationOptions, From 9250cd542e6767c0d796d8f5381ab562179080da Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Mon, 22 Aug 2022 21:40:40 +0900 Subject: [PATCH 10/37] Update packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts Co-authored-by: Matthew Miller --- .../src/extensions/devicePublicKey/verifyDpkSignature.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts b/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts index f32fd8c4..e20f5946 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts @@ -54,8 +54,7 @@ export async function verifyDpkSignature( const { clientDataJSON } = credential.response; const clientDataHash = toHash(base64url.toBuffer(clientDataJSON)); - const { id } = credential; - const credentialID = base64url.toBuffer(id); + const credentialID = base64url.toBuffer(credential.id); const { rpIdHash } = parseAuthenticatorData(authData); if (!credentialID) { From 9c21beac54141ff47f8f52e86a5381a4feffda64 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Mon, 22 Aug 2022 21:40:53 +0900 Subject: [PATCH 11/37] Update packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts Co-authored-by: Matthew Miller --- .../src/extensions/devicePublicKey/verifyDpkSignature.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts b/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts index e20f5946..6a22638d 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts @@ -42,8 +42,7 @@ export async function verifyDpkSignature( if (isAuthenticationResponse(credential)) { const { authenticatorData } = credential.response; authData = base64url.toBuffer(authenticatorData); - } - if (isRegistrationResponse(credential)) { + } else if (isRegistrationResponse(credential)) { const attestationObject = base64url.toBuffer(credential.response.attestationObject); const { authData: authenticatorData } = decodeAttestationObject(attestationObject); authData = authenticatorData; From 5edeb6307c0ef2b05165701c34b3eb4c940b5592 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Mon, 22 Aug 2022 21:41:27 +0900 Subject: [PATCH 12/37] Update packages/server/src/extensions/devicePublicKey/verifyDpkSignature.test.ts Co-authored-by: Matthew Miller --- .../src/extensions/devicePublicKey/verifyDpkSignature.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.test.ts b/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.test.ts index 30a0cfc6..e8aa0c6b 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.test.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.test.ts @@ -2,7 +2,7 @@ import { AuthenticationCredentialJSON, AuthenticatorAssertionResponseJSON, Authe import { verifyDpkSignature } from './verifyDpkSignature'; it("should verify a registration response's device public key signature", async () => { - const credential = { + const credential: RegistrationCredentialJSON = { response: { clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiNFF3dmdUVjhlaTF5TzYyaDF2bVFNWFM2SDZ3UGc0YWt2eDNKcF9VakF3cyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', attestationObject: 'o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVkBaQ11_MVj_ad52y40PupImIh1i3hUnUk6T9vqHNlqoxzExQAAAAAAAAAAAAAAAAAAAAAAAAAAABBzGMMHWHmcbqOlBbcR55k0pQECAyYgASFYIIukb9t-EtGUOa2t6YiJEAgz7GyqBN4DFTCzkcMiUGqIIlggmm6GzBPSzP9IYJnX-89R_zmKl6-qQSeQ2qomEC6Cr32hbGRldmljZVB1YktleaVjZHBrWE2lAQIDJiABIVgg7erT_TV2nCPTQN3Bgwp_8g5zVfKdHHWqDcK2rBgup9MiWCA0UdyZkq-UaCW0QZRfydE04Xtzql_qlYA1HnyT9dNlE2NzaWdYRjBEAiALHwldj84eCsg9f0fHD9hylpUK8N_TGOBKBQPoNvfWjQIgChIUfdbO1HBavxbZGQxIt4v23FqFLB2nzwip-avJ6etlbm9uY2VAZXNjb3BlQQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAAA=', @@ -12,7 +12,7 @@ it("should verify a registration response's device public key signature", async type: 'public-key', transports: [], clientExtensionResults: '' - } as RegistrationCredentialJSON; + }; const devicePubKey = { aaguid: Buffer.from('00000000000000000000000000000000', 'hex'), From 9694a80d5887409981c94b9cb4171f0be67b1060 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Mon, 22 Aug 2022 22:03:05 +0900 Subject: [PATCH 13/37] Update DPK --- ...st.ts => verifyDevicePublicKeySignature.test.ts} | 8 ++++---- ...gnature.ts => verifyDevicePublicKeySignature.ts} | 13 +++++-------- packages/server/src/index.ts | 4 ++-- 3 files changed, 11 insertions(+), 14 deletions(-) rename packages/server/src/extensions/devicePublicKey/{verifyDpkSignature.test.ts => verifyDevicePublicKeySignature.test.ts} (92%) rename packages/server/src/extensions/devicePublicKey/{verifyDpkSignature.ts => verifyDevicePublicKeySignature.ts} (94%) diff --git a/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.test.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.test.ts similarity index 92% rename from packages/server/src/extensions/devicePublicKey/verifyDpkSignature.test.ts rename to packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.test.ts index e8aa0c6b..9e5b3d3a 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.test.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.test.ts @@ -1,5 +1,5 @@ import { AuthenticationCredentialJSON, AuthenticatorAssertionResponseJSON, AuthenticatorAttestationResponseJSON, RegistrationCredentialJSON } from '@simplewebauthn/typescript-types'; -import { verifyDpkSignature } from './verifyDpkSignature'; +import { verifyDevicePublicKeySignature } from './verifyDevicePublicKeySignature'; it("should verify a registration response's device public key signature", async () => { const credential: RegistrationCredentialJSON = { @@ -11,7 +11,7 @@ it("should verify a registration response's device public key signature", async rawId: 'cxjDB1h5nG6jpQW3EeeZNA', type: 'public-key', transports: [], - clientExtensionResults: '' + clientExtensionResults: {} }; const devicePubKey = { @@ -23,7 +23,7 @@ it("should verify a registration response's device public key signature", async } const signature = devicePubKey.sig; - const result = await verifyDpkSignature({ credential, devicePubKey, signature }); + const result = await verifyDevicePublicKeySignature({ credential, devicePubKey, signature }); expect(result).toEqual(true); }); @@ -49,6 +49,6 @@ it("should verify an authentication response's device public key signature", asy } const signature = devicePubKey.sig; - const result = await verifyDpkSignature({ credential, devicePubKey, signature }); + const result = await verifyDevicePublicKeySignature({ credential, devicePubKey, signature }); expect(result).toEqual(true); }); diff --git a/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts similarity index 94% rename from packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts rename to packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts index 6a22638d..7fe17ff0 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDpkSignature.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts @@ -19,7 +19,7 @@ import { } from "@simplewebauthn/typescript-types"; import { decodeAttestationObject } from "../../helpers/decodeAttestationObject"; -export type VerifyDpkSignatureOpts = { +export type VerifyDevicePublicKeySignatureOpts = { credential: RegistrationCredentialJSON | AuthenticationCredentialJSON devicePubKey: DevicePublicKeyAuthenticatorOutput; signature: Buffer; @@ -33,8 +33,8 @@ export type VerifyDpkSignatureOpts = { * @param options * @returns Promise */ -export async function verifyDpkSignature( - options: VerifyDpkSignatureOpts +export async function verifyDevicePublicKeySignature( + options: VerifyDevicePublicKeySignatureOpts ): Promise { const { credential, devicePubKey, signature } = options; @@ -56,15 +56,12 @@ export async function verifyDpkSignature( const credentialID = base64url.toBuffer(credential.id); const { rpIdHash } = parseAuthenticatorData(authData); - if (!credentialID) { - // `authData` without `credentialID` can't be verified. - return false; - } - const nonce = devicePubKey.nonce ? devicePubKey.nonce : Buffer.from(''); // According to the spec, `authData` and `clientDataHash` are concatenated as // the signature base, but this is an interim implementation. const signatureBase = Buffer.concat([credentialID, clientDataHash, nonce]); + // It's a device public key and not a credential public key, but to align with + // the `verifySinature` signature, we name it `credentialPublicKey`. const credentialPublicKey = devicePubKey.dpk; if (devicePubKey.fmt && devicePubKey.attStmt) { diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 82faea96..ed99907f 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -8,7 +8,7 @@ import { generateAuthenticationOptions } from './authentication/generateAuthenti import { verifyAuthenticationResponse } from './authentication/verifyAuthenticationResponse'; import { MetadataService } from './services/metadataService'; import { SettingsService } from './services/settingsService'; -import { verifyDpkSignature } from './extensions/devicePublicKey/verifyDpkSignature'; +import { verifyDevicePublicKeySignature } from './extensions/devicePublicKey/verifyDevicePublicKeySignature'; import { verifyDevicePublicKey } from './extensions/devicePublicKey/verifyDevicePublicKey'; import { DevicePublicKeyAuthenticatorOutput } from './helpers/decodeAuthenticatorExtensions'; @@ -19,7 +19,7 @@ export { verifyAuthenticationResponse, MetadataService, SettingsService, - verifyDpkSignature, + verifyDevicePublicKeySignature as verifyDpkSignature, verifyDevicePublicKey, }; From 9f0ea58ff4a8be6192d78c2c6de0b3e6a8e9c60b Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Fri, 26 Aug 2022 19:09:31 +0900 Subject: [PATCH 14/37] Update DPK logic - DPK verification steps as part of registration and authentication - Align with the latest spec --- .../verifyAuthenticationResponse.ts | 38 ++++++- ...Key.test.ts => isRecognizedDevice.test.ts} | 2 +- .../devicePublicKey/isRecognizedDevice.ts | 102 ++++++++++++++++++ .../devicePublicKey/verifyDevicePublicKey.ts | 69 ------------ .../verifyDevicePublicKeyAttestation.ts | 35 ++++++ packages/server/src/index.ts | 6 +- .../verifyRegistrationResponse.ts | 39 ++++++- 7 files changed, 214 insertions(+), 77 deletions(-) rename packages/server/src/extensions/devicePublicKey/{verifyDevicePublicKey.test.ts => isRecognizedDevice.test.ts} (60%) create mode 100644 packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts delete mode 100644 packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.ts create mode 100644 packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.ts b/packages/server/src/authentication/verifyAuthenticationResponse.ts index 6bb6e98f..4b360fd1 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.ts @@ -12,7 +12,9 @@ import { verifySignature } from '../helpers/verifySignature'; import { parseAuthenticatorData } from '../helpers/parseAuthenticatorData'; import { isBase64URLString } from '../helpers/isBase64URLString'; import { parseBackupFlags } from '../helpers/parseBackupFlags'; -import { AuthenticationExtensionsAuthenticatorOutputs } from '../helpers/decodeAuthenticatorExtensions'; +import { AuthenticationExtensionsAuthenticatorOutputs, DevicePublicKeyAuthenticatorOutput } from '../helpers/decodeAuthenticatorExtensions'; +import { verifyDevicePublicKeySignature, VerifyDevicePublicKeySignatureOpts } from '../extensions/devicePublicKey/verifyDevicePublicKeySignature'; +import { isRecognizedDevice } from '../extensions/devicePublicKey/isRecognizedDevice'; export type VerifyAuthenticationResponseOpts = { credential: AuthenticationCredentialJSON; @@ -24,6 +26,7 @@ export type VerifyAuthenticationResponseOpts = { advancedFIDOConfig?: { userVerification?: UserVerificationRequirement; }; + userDevicePublicKey?: DevicePublicKeyAuthenticatorOutput[]; }; /** @@ -56,8 +59,9 @@ export async function verifyAuthenticationResponse( authenticator, requireUserVerification, advancedFIDOConfig, + userDevicePublicKey, } = options; - const { id, rawId, type: credentialType, response } = credential; + const { id, rawId, type: credentialType, response, clientExtensionResults } = credential; // Ensure credential specified an ID if (!id) { @@ -193,6 +197,36 @@ export async function verifyAuthenticationResponse( } } + if (flags.ed) { + if (!extensionsData && !clientExtensionResults) { + throw new Error('Extension results are not included despite the flag.'); + } + + // TODO: Find a good way to check that returned extension outputs match what + // was requested in extension inputs. See 7.1 step 18 in the spec. + + // DevicePublicKey sample currently provides the data through authenticator + // extension results. + if (extensionsData?.devicePubKey) { + const { devicePubKey } = extensionsData; + const { sig: signature } = devicePubKey; + + if (!signature) { + throw new Error('DevicePublicKey signature is missing.'); + } + const dpkOptions: VerifyDevicePublicKeySignatureOpts = { + credential, + devicePubKey, + signature, + }; + const result = await verifyDevicePublicKeySignature(dpkOptions); + if (!result) { + throw new Error('Verifying DevicePublicKey signature failed.'); + } + await isRecognizedDevice(devicePubKey, userDevicePublicKey); + } + } + const clientDataHash = toHash(base64url.toBuffer(response.clientDataJSON)); const signatureBase = Buffer.concat([authDataBuffer, clientDataHash]); diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.test.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts similarity index 60% rename from packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.test.ts rename to packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts index d48322f5..35dbd3a9 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.test.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts @@ -1,4 +1,4 @@ it("should verify device public key", async () => { - // TODO: Implement a test for `verifyDevicePublicKey` + // TODO: Implement a test for `isRecognizedDevice` expect(true).toEqual(true); }); diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts new file mode 100644 index 00000000..0faa4d2a --- /dev/null +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts @@ -0,0 +1,102 @@ +import { DevicePublicKeyAuthenticatorOutput } from "../../helpers/decodeAuthenticatorExtensions"; +import { verifyDevicePublicKeyAttestation } from "./verifyDevicePublicKeyAttestation"; + +/** + * + * @param responseDevicePublicKey + * @param knownDevicePublicKeys + * @returns DevicePublicKeyAuthenticatorOutput | undefined + */ +export async function isRecognizedDevice( + responseDevicePublicKey: DevicePublicKeyAuthenticatorOutput, + userDevicePublicKeys?: DevicePublicKeyAuthenticatorOutput[] +): Promise { + if (userDevicePublicKeys && userDevicePublicKeys.length > 0) { + // If the Relying Party's user account mapped to the credential.id in play + // (i.e., for the user being authenticated) holds aaguid, dpk and scope + // values corresponding to the extracted attObjForDevicePublicKey fields, + // then perform binary equality checks between the corresponding stored + // values and the extracted field values. The Relying Party MAY have more + // than one set of {aaguid, dpk, scope} values mapped to the user account + // and credential.id pair and each set MUST be checked. + const matchedDPKs = userDevicePublicKeys.filter(userDPK => { + if (!responseDevicePublicKey.aaguid.equals(userDPK.aaguid)) { + return false; + } + if (!responseDevicePublicKey.dpk.equals(userDPK.dpk)) { + return false; + } + if (!responseDevicePublicKey.scope.equals(userDPK.scope)) { + return false; + } + return true; + }); + + // more than one match + if (matchedDPKs.length > 1) { + throw new Error('It is undetermined whether this is a known device.'); + } + + // exactly one match + if (matchedDPKs.length === 1) { + // This is likely a known device. + + // If fmt’s value is "none" then there + // is no attestation signature to verify and this is a known device public + // key with a valid signature and thus a known device. Terminate these + // verification steps. + if (!responseDevicePublicKey.fmt || responseDevicePublicKey.fmt === 'none') { + return; + } else { + // Perform a binary equality check of `attStmt`. + // TODO: if equality check succeeds, + if (!equalityCheck()) { + // This authenticator is not generating a fresh per-response random nonce. + return; + } else { + // Otherwise, verify attestation + const isValidDPKAttestation = await verifyDevicePublicKeyAttestation(responseDevicePublicKey); + if (!isValidDPKAttestation) { + throw new Error('Device Public Key attestation is invalid.'); + } + } + // This is a valid and a known device. + return; + } + } + + // zero matches + if (matchedDPKs.length === 0) { + // This is possibly a new device. + + const index = userDevicePublicKeys.findIndex(userDPK => { + return responseDevicePublicKey.dpk.equals(userDPK.dpk) + }); + if (index === -1) { + // If `attObjForDevicePublicKey.dpk` did not match any of the Relying + // Party's stored dpk values for this user account and `credential.id` + // pair then: + const isValidDPKAttestation = await verifyDevicePublicKeyAttestation(responseDevicePublicKey); + if (!isValidDPKAttestation) { + throw new Error('Device public key attestation is invalid.'); + } + return responseDevicePublicKey; + } else { + // Otherwise there is some form of error: we recieved a known dpk + // value, but one or more of the accompanying aaguid, scope values + // did not match what the Relying Party has stored along with that + // dpk value. Terminate these verification steps. + throw new Error('It is undetermined whether this is a known device.'); + } + } + } else { + // Otherwise, the Relying Party does not have `attObjForDevicePublicKey` + // fields presently mapped to this user account and credential.id pair: + const isValidDPKAttestation = await verifyDevicePublicKeyAttestation(responseDevicePublicKey); + if (!isValidDPKAttestation) { + throw new Error('Device Public Key attestation is invalid.'); + } + return responseDevicePublicKey; + } + return; +} \ No newline at end of file diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.ts deleted file mode 100644 index 157e17ef..00000000 --- a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKey.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { DevicePublicKeyAuthenticatorOutput } from "../../helpers/decodeAuthenticatorExtensions"; - -/** - * https://pr-preview.s3.amazonaws.com/w3c/webauthn/pull/1663.html#sctn-device-publickey-extension-verification-get - * 4. If the Relying Party's user account mapped to the *credential*.id in play - * (i.e., for the user being authenticated) holds `aaguid`, `dpk`, `scope`, - * `fmt`, and `attStmt` values corresponding to the extracted - * *attObjForDevicePublicKey* fields, then perform binary equality checks - * between the corresponding stored values and the extracted field values. - * @param devicePubKey - * @param expectedDPK - * @returns boolean - */ -export function verifyDevicePublicKey( - devicePubKey: DevicePublicKeyAuthenticatorOutput, - expectedDPK: DevicePublicKeyAuthenticatorOutput -): boolean { - if (!devicePubKey.aaguid.equals(expectedDPK.aaguid)) { - return false; - } - if (!devicePubKey.dpk.equals(expectedDPK.dpk)) { - return false; - } - if (!devicePubKey.scope.equals(expectedDPK.scope)) { - return false; - } - if (devicePubKey.fmt !== expectedDPK.fmt) { - return false; - } - if (devicePubKey.attStmt && expectedDPK.attStmt) { - const { attStmt } = devicePubKey; - const expectedAttStmt = expectedDPK.attStmt; - - if (!attStmt.sig || !expectedAttStmt.sig || !attStmt.sig.equals(expectedAttStmt.sig)) { - return false; - } - if (!attStmt.x5c || !expectedAttStmt.x5c) { - return false; - } - if (attStmt.x5c.length !== expectedAttStmt.x5c.length) { - return false; - } - for (let i = 0; i < attStmt.x5c.length; i++) { - if (!attStmt.x5c[i].equals(expectedAttStmt.x5c[i])) { - return false; - } - } - if (!attStmt.response || !expectedAttStmt.response || !attStmt.response.equals(expectedAttStmt.response)) { - return false; - } - if (attStmt.alg !== expectedAttStmt.alg) { - return false; - } - if (attStmt.ver !== expectedAttStmt.ver) { - return false; - } - if (!attStmt.certInfo || !expectedAttStmt.certInfo || !attStmt.certInfo.equals(expectedAttStmt.certInfo)) { - return false; - } - if (!attStmt.pubArea || !expectedAttStmt.pubArea || !attStmt.pubArea.equals(expectedAttStmt.pubArea)) { - return false; - } - } else { - // `attStmt` is required field, though at the moment, as the test attestation - // omits it. Ignore this case intentionally. - // return false; - } - return true; -} \ No newline at end of file diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts new file mode 100644 index 00000000..0c0660ee --- /dev/null +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts @@ -0,0 +1,35 @@ +import { DevicePublicKeyAuthenticatorOutput } from "../../helpers/decodeAuthenticatorExtensions"; +import { + AuthenticationCredentialJSON, + RegistrationCredentialJSON, +} from "@simplewebauthn/typescript-types"; + +export type VerifyDevicePublicKeySignatureOpts = { + credential: RegistrationCredentialJSON | AuthenticationCredentialJSON + devicePubKey: DevicePublicKeyAuthenticatorOutput; + signature: Buffer; +}; + +/** + * https://pr-preview.s3.amazonaws.com/w3c/webauthn/pull/1663.html#sctn-device-publickey-extension-verification-create + * 3. Verify that `signature` is a valid signature over the assertion signature + * input by the device public key *dpk*. (The signature algorithm is the same + * as for the user credential.) + * @param options + * @returns Promise + */ +export async function verifyDevicePublicKeyAttestation( + devicePubKey: DevicePublicKeyAuthenticatorOutput +): Promise { + const { fmt } = devicePubKey; + if (fmt === undefined || fmt === 'none') { + return true; + } + + // TODO: Implement the attestation verification logic. + // const prefix = Buffer.from('64657669636520626f756e64206b6579206174746573746174696f6e2073696700ffffffff', 'hex'); + // const authData = Buffer.concat([prefix, aaguid]); + // const clientDataHash = Buffer.concat([dpk, nonce || Buffer.from('')]); + + return true; +} diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index ed99907f..59a68c8a 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -8,8 +8,7 @@ import { generateAuthenticationOptions } from './authentication/generateAuthenti import { verifyAuthenticationResponse } from './authentication/verifyAuthenticationResponse'; import { MetadataService } from './services/metadataService'; import { SettingsService } from './services/settingsService'; -import { verifyDevicePublicKeySignature } from './extensions/devicePublicKey/verifyDevicePublicKeySignature'; -import { verifyDevicePublicKey } from './extensions/devicePublicKey/verifyDevicePublicKey'; +import { isRecognizedDevice } from './extensions/devicePublicKey/isRecognizedDevice'; import { DevicePublicKeyAuthenticatorOutput } from './helpers/decodeAuthenticatorExtensions'; export { @@ -19,8 +18,7 @@ export { verifyAuthenticationResponse, MetadataService, SettingsService, - verifyDevicePublicKeySignature as verifyDpkSignature, - verifyDevicePublicKey, + isRecognizedDevice, }; import type { GenerateRegistrationOptionsOpts } from './registration/generateRegistrationOptions'; diff --git a/packages/server/src/registration/verifyRegistrationResponse.ts b/packages/server/src/registration/verifyRegistrationResponse.ts index 14c2110b..c58ea274 100644 --- a/packages/server/src/registration/verifyRegistrationResponse.ts +++ b/packages/server/src/registration/verifyRegistrationResponse.ts @@ -27,6 +27,8 @@ import { verifyAttestationAndroidSafetyNet } from './verifications/verifyAttesta import { verifyAttestationTPM } from './verifications/tpm/verifyAttestationTPM'; import { verifyAttestationAndroidKey } from './verifications/verifyAttestationAndroidKey'; import { verifyAttestationApple } from './verifications/verifyAttestationApple'; +import { verifyDevicePublicKeySignature, VerifyDevicePublicKeySignatureOpts } from '../extensions/devicePublicKey/verifyDevicePublicKeySignature'; +import { verifyDevicePublicKeyAttestation } from 'extensions/devicePublicKey/verifyDevicePublicKeyAttestation'; export type VerifyRegistrationResponseOpts = { credential: RegistrationCredentialJSON; @@ -63,7 +65,7 @@ export async function verifyRegistrationResponse( requireUserVerification = false, supportedAlgorithmIDs = supportedCOSEAlgorithmIdentifiers, } = options; - const { id, rawId, type: credentialType, response } = credential; + const { id, rawId, type: credentialType, response, clientExtensionResults } = credential; // Ensure credential specified an ID if (!id) { @@ -192,6 +194,41 @@ export async function verifyRegistrationResponse( throw new Error(`Unexpected public key alg "${alg}", expected one of "${supported}"`); } + if (flags.ed) { + if (!extensionsData && !clientExtensionResults) { + throw new Error('Extension results are not included despite the flag.'); + } + + // TODO: Find a good way to check that returned extension outputs match what + // was requested in extension inputs. See 7.1 step 18 in the spec. + + // Device public key sample currently provides the data through + // authenticator extension results. + if (extensionsData?.devicePubKey) { + const { devicePubKey } = extensionsData; + const signature = devicePubKey.sig; + if (!signature) { + throw new Error('DevicePublicKey signature is missing.'); + } + const dpkOptions: VerifyDevicePublicKeySignatureOpts = { + credential, + devicePubKey, + signature, + }; + const sigResult = await verifyDevicePublicKeySignature(dpkOptions); + if (!sigResult) { + throw new Error('Invalid device public key signature.'); + } + + // Optionally verify device public key attestation here as per + // 10.2.2.3.1. step 4 in the spec. + const attResult = await verifyDevicePublicKeyAttestation(devicePubKey); + if (!attResult) { + throw new Error('Invalid device public key attestation.'); + } + } + } + const clientDataHash = toHash(base64url.toBuffer(response.clientDataJSON)); const rootCertificates = SettingsService.getRootCertificates({ identifier: fmt }); From d5745b68c0c82b7610c4ee92f710974dbd8e87b1 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Fri, 26 Aug 2022 19:22:59 +0900 Subject: [PATCH 15/37] Attestation binary equality check --- .../devicePublicKey/isRecognizedDevice.ts | 95 +++++++++++++------ 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts index 0faa4d2a..ed80ee3e 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts @@ -1,3 +1,4 @@ +import { AttestationStatement } from "helpers"; import { DevicePublicKeyAuthenticatorOutput } from "../../helpers/decodeAuthenticatorExtensions"; import { verifyDevicePublicKeyAttestation } from "./verifyDevicePublicKeyAttestation"; @@ -37,34 +38,6 @@ export async function isRecognizedDevice( throw new Error('It is undetermined whether this is a known device.'); } - // exactly one match - if (matchedDPKs.length === 1) { - // This is likely a known device. - - // If fmt’s value is "none" then there - // is no attestation signature to verify and this is a known device public - // key with a valid signature and thus a known device. Terminate these - // verification steps. - if (!responseDevicePublicKey.fmt || responseDevicePublicKey.fmt === 'none') { - return; - } else { - // Perform a binary equality check of `attStmt`. - // TODO: if equality check succeeds, - if (!equalityCheck()) { - // This authenticator is not generating a fresh per-response random nonce. - return; - } else { - // Otherwise, verify attestation - const isValidDPKAttestation = await verifyDevicePublicKeyAttestation(responseDevicePublicKey); - if (!isValidDPKAttestation) { - throw new Error('Device Public Key attestation is invalid.'); - } - } - // This is a valid and a known device. - return; - } - } - // zero matches if (matchedDPKs.length === 0) { // This is possibly a new device. @@ -89,6 +62,28 @@ export async function isRecognizedDevice( throw new Error('It is undetermined whether this is a known device.'); } } + + // Everything else is exactly one match + // This is likely a known device. + + // If fmt’s value is "none" then there + // is no attestation signature to verify and this is a known device public + // key with a valid signature and thus a known device. Terminate these + // verification steps. + if (responseDevicePublicKey.fmt && responseDevicePublicKey.fmt !== 'none') { + // Perform a binary equality check of `attStmt`. + const knownAttStmt = matchedDPKs[0].attStmt; + if (!checkAttStmtBinaryEquality(responseDevicePublicKey.attStmt, knownAttStmt)) { + // Otherwise, verify attestation + const isValidDPKAttestation = await verifyDevicePublicKeyAttestation(responseDevicePublicKey); + if (!isValidDPKAttestation) { + throw new Error('Device Public Key attestation is invalid.'); + } + } + } + // This is a valid and a known device. + return; + } else { // Otherwise, the Relying Party does not have `attObjForDevicePublicKey` // fields presently mapped to this user account and credential.id pair: @@ -98,5 +93,45 @@ export async function isRecognizedDevice( } return responseDevicePublicKey; } - return; -} \ No newline at end of file +} + +function checkAttStmtBinaryEquality( + responseAttStmt?: AttestationStatement, + knownAttStmt?: AttestationStatement +): boolean { + // `attStmt` in device public key is not optional, but for an interim solution: + if (!responseAttStmt || ! knownAttStmt) { + return false; + } + + if (!responseAttStmt.sig || !knownAttStmt.sig || !responseAttStmt.sig.equals(knownAttStmt.sig)) { + return false; + } + if (!responseAttStmt.x5c || !knownAttStmt.x5c) { + return false; + } + if (responseAttStmt.x5c.length !== knownAttStmt.x5c.length) { + return false; + } + for (let i = 0; i < responseAttStmt.x5c.length; i++) { + if (!responseAttStmt.x5c[i].equals(knownAttStmt.x5c[i])) { + return false; + } + } + if (!responseAttStmt.response || !knownAttStmt.response || !responseAttStmt.response.equals(knownAttStmt.response)) { + return false; + } + if (responseAttStmt.alg !== knownAttStmt.alg) { + return false; + } + if (responseAttStmt.ver !== knownAttStmt.ver) { + return false; + } + if (!responseAttStmt.certInfo || !knownAttStmt.certInfo || !responseAttStmt.certInfo.equals(knownAttStmt.certInfo)) { + return false; + } + if (!responseAttStmt.pubArea || !knownAttStmt.pubArea || !responseAttStmt.pubArea.equals(knownAttStmt.pubArea)) { + return false; + } + return true; +} From 000c9b42100085df104c83cb394ddd35924b2aa7 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Fri, 26 Aug 2022 19:27:18 +0900 Subject: [PATCH 16/37] Add comment --- .../src/extensions/devicePublicKey/isRecognizedDevice.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts index ed80ee3e..688a4237 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts @@ -3,7 +3,10 @@ import { DevicePublicKeyAuthenticatorOutput } from "../../helpers/decodeAuthenti import { verifyDevicePublicKeyAttestation } from "./verifyDevicePublicKeyAttestation"; /** - * + * Checks if the device public key matches one of stored DPKs as per described + * at 10.2.2.3.2 of the spec. If it's a known device, returns undefined. If it's + * a new but valid device, returns the device public key so that the RP can + * store it. Throws when it's an invalid device or any unexpected issue occurs. * @param responseDevicePublicKey * @param knownDevicePublicKeys * @returns DevicePublicKeyAuthenticatorOutput | undefined From 76153ff81192ee710d96b1bd5ba61f7abbd54dce Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Fri, 26 Aug 2022 19:37:25 +0900 Subject: [PATCH 17/37] Return device public key to RP --- .../verifyAuthenticationResponse.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.ts b/packages/server/src/authentication/verifyAuthenticationResponse.ts index 4b360fd1..44c31ef6 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.ts @@ -12,7 +12,7 @@ import { verifySignature } from '../helpers/verifySignature'; import { parseAuthenticatorData } from '../helpers/parseAuthenticatorData'; import { isBase64URLString } from '../helpers/isBase64URLString'; import { parseBackupFlags } from '../helpers/parseBackupFlags'; -import { AuthenticationExtensionsAuthenticatorOutputs, DevicePublicKeyAuthenticatorOutput } from '../helpers/decodeAuthenticatorExtensions'; +import { DevicePublicKeyAuthenticatorOutput } from '../helpers/decodeAuthenticatorExtensions'; import { verifyDevicePublicKeySignature, VerifyDevicePublicKeySignatureOpts } from '../extensions/devicePublicKey/verifyDevicePublicKeySignature'; import { isRecognizedDevice } from '../extensions/devicePublicKey/isRecognizedDevice'; @@ -197,6 +197,8 @@ export async function verifyAuthenticationResponse( } } + const extensionOutputs: ExtensionOutputs = {}; + if (flags.ed) { if (!extensionsData && !clientExtensionResults) { throw new Error('Extension results are not included despite the flag.'); @@ -223,7 +225,8 @@ export async function verifyAuthenticationResponse( if (!result) { throw new Error('Verifying DevicePublicKey signature failed.'); } - await isRecognizedDevice(devicePubKey, userDevicePublicKey); + const devicePubKeyToStore = await isRecognizedDevice(devicePubKey, userDevicePublicKey); + extensionOutputs.devicePubKeyToStore = devicePubKeyToStore; } } @@ -256,8 +259,8 @@ export async function verifyAuthenticationResponse( userVerified: flags.uv, credentialDeviceType, credentialBackedUp, - authenticatorExtensionResults: extensionsData, }, + extensionOutputs, }; return toReturn; @@ -289,6 +292,10 @@ export type VerifiedAuthenticationResponse = { userVerified: boolean; credentialDeviceType: CredentialDeviceType; credentialBackedUp: boolean; - authenticatorExtensionResults?: AuthenticationExtensionsAuthenticatorOutputs; }; + extensionOutputs: ExtensionOutputs; }; + +export type ExtensionOutputs = { + devicePubKeyToStore?: DevicePublicKeyAuthenticatorOutput; +} From 2228dd324cf69479e68688aeb2299b59fbe435c4 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Sat, 27 Aug 2022 19:00:39 +0900 Subject: [PATCH 18/37] Successful test cases added --- .../verifyAuthenticationResponse.test.ts | 104 +++++++++++------- .../isRecognizedDevice.test.ts | 43 +++++++- .../devicePublicKey/isRecognizedDevice.ts | 2 +- .../verifyRegistrationResponse.ts | 2 +- 4 files changed, 108 insertions(+), 43 deletions(-) diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts index 3b8e7b66..b5418169 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts @@ -8,6 +8,7 @@ import { AuthenticatorDevice, AuthenticationCredentialJSON, } from '@simplewebauthn/typescript-types'; +import { DevicePublicKeyAuthenticatorOutput } from '../helpers/decodeAuthenticatorExtensions'; let mockDecodeClientData: jest.SpyInstance; let mockParseAuthData: jest.SpyInstance; @@ -311,52 +312,79 @@ test('should fail verification if custom challenge verifier returns false', asyn ).rejects.toThrow(/custom challenge verifier returned false/i); }); -test('should return authenticator extension output', async () => { - const verification = await verifyAuthenticationResponse({ - credential: { - response: { - clientDataJSON: - 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiaVpzVkN6dHJEVzdEMlVfR0hDSWxZS0x3VjJiQ3NCVFJxVlFVbkpYbjlUayIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', - authenticatorData: - 'DXX8xWP9p3nbLjQ-6kiYiHWLeFSdSTpP2-oc2WqjHMSFAAAAAKFvZGV2aWNlUHVibGljS2V5pWNkcGtYTaUBAgMmIAEhWCCZGqvtneQnGp7erYgG-dyW1tzNDEdiU6VRBInsg3m-WyJYIKCXPP3tu3nif-9O50gWc_szElBN3KVDTP0jQx1q0p7aY3NpZ1hHMEUCIElSbNKK72tOYhp9WTbStQSVL8CuIxOk8DV6r_-uqWR0AiEAnVE6yu-wsyx2Wq5v66jClGhe_2P_HL8R7PIQevT-uPhlbm9uY2VAZXNjb3BlQQBmYWFndWlkULk_2WHy5kYvsSKCACJH3ng=', - signature: - 'MEYCIQDlRuxY7cYre0sb3T6TovQdfYIUb72cRZYOQv_zS9wN_wIhAOvN-fwjtyIhWRceqJV4SX74-z6oALERbC7ohk8EdVPO', - userHandle: 'b2FPajFxcmM4MWo3QkFFel9RN2lEakh5RVNlU2RLNDF0Sl92eHpQYWV5UQ==', - }, - id: 'E_Pko4wN1BXE23S0ftN3eQ', - rawId: 'E_Pko4wN1BXE23S0ftN3eQ', - type: 'public-key', - clientExtensionResults: {}, +const devicePubKey: DevicePublicKeyAuthenticatorOutput = { + "dpk": Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'), + "sig": Buffer.from('3045022100BC6DD9AF5E47BB3AB82731299EAE82A779189E4E416E3A0E37A3BA64C38F991202205671EFAC0E8CD6DE1D3640CE7E4E89D3A97E0517B603D8AC28F23E4E1F74E639', 'hex'), + "nonce": Buffer.from('', 'hex'), + "scope": Buffer.from('00', 'hex'), + "aaguid": Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), +}; +const sameDevicePubKey = devicePubKey; +const differentDevicePubKey: DevicePublicKeyAuthenticatorOutput = { + "dpk": Buffer.from('A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', 'hex'), + "sig": Buffer.from('3045022049526CD28AEF6B4E621A7D5936D2B504952FC0AE2313A4F0357AAFFFAEA964740221009D513ACAEFB0B32C765AAE6FEBA8C294685EFF63FF1CBF11ECF2107AF4FEB8F8', 'hex'), + "nonce": Buffer.from('', 'hex'), + "scope": Buffer.from('00', 'hex'), + "aaguid": Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), +}; +const authenticationCredentialWithDevicePublicKey: AuthenticationCredentialJSON = { + response: { + "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoicTh1SVR0d0czMkhUU3RmdlVxVTcwWXNGNFJfS1A4WnZEYkVESVpZekNDdyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9", + "authenticatorData": "DXX8xWP9p3nbLjQ-6kiYiHWLeFSdSTpP2-oc2WqjHMSFAAAAAKFsZGV2aWNlUHViS2V5pWNkcGtYTaUBAgMmIAEhWCDt6tP9NXacI9NA3cGDCn_yDnNV8p0cdaoNwrasGC6n0yJYIDRR3JmSr5RoJbRBlF_J0TThe3OqX-qVgDUefJP102UTY3NpZ1hHMEUCIQC8bdmvXke7OrgnMSmeroKneRieTkFuOg43o7pkw4-ZEgIgVnHvrA6M1t4dNkDOfk6J06l-BRe2A9isKPI-Th905jllbm9uY2VAZXNjb3BlQQBmYWFndWlkULk_2WHy5kYvsSKCACJH3ng=", + "signature": "MEUCIEXJbR9-0cpcUdGAJi25Qf3z22lnCidx3box2b0bWKhwAiEAkp5zCbVbN2CEtIyezQEa9SOG62xm8YHdE1G5qov64j8=", + "userHandle": "b2FPajFxcmM4MWo3QkFFel9RN2lEakh5RVNlU2RLNDF0Sl92eHpQYWV5UQ==" + }, + id: "cxjDB1h5nG6jpQW3EeeZNA", + rawId: "cxjDB1h5nG6jpQW3EeeZNA", + type: "public-key", + clientExtensionResults: {} +}; +const credentialID = base64url.toBuffer('cxjDB1h5nG6jpQW3EeeZNA'); +const credentialPublicKey = base64url.toBuffer('pQECAyYgASFYIIukb9t-EtGUOa2t6YiJEAgz7GyqBN4DFTCzkcMiUGqIIlggmm6GzBPSzP9IYJnX-89R_zmKl6-qQSeQ2qomEC6Cr30'); + +test('should throw if multiple device public key matches', async () => { + await expect(verifyAuthenticationResponse({ + credential: authenticationCredentialWithDevicePublicKey, + expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', + expectedRPID: 'try-webauthn.appspot.com', + expectedChallenge: 'q8uITtwG32HTStfvUqU70YsF4R_KP8ZvDbEDIZYzCCw', + authenticator: { + credentialID, + credentialPublicKey, + counter: 0, }, + userDevicePublicKey: [sameDevicePubKey, sameDevicePubKey], + })).rejects.toThrowError(new Error('It is undetermined whether this is a known device.')); +}); + +test('should return the new device public key when no device public key matches', async () => { + await expect(verifyAuthenticationResponse({ + credential: authenticationCredentialWithDevicePublicKey, expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', expectedRPID: 'try-webauthn.appspot.com', - expectedChallenge: 'iZsVCztrDW7D2U_GHCIlYKLwV2bCsBTRqVQUnJXn9Tk', + expectedChallenge: 'q8uITtwG32HTStfvUqU70YsF4R_KP8ZvDbEDIZYzCCw', authenticator: { - credentialID: base64url.toBuffer( - 'AaIBxnYfL2pDWJmIii6CYgHBruhVvFGHheWamphVioG_TnEXxKA9MW4FWnJh21zsbmRpRJso9i2JmAtWOtXfVd4oXTgYVusXwhWWsA', - ), - credentialPublicKey: base64url.toBuffer( - 'pQECAyYgASFYILTrxTUQv3X4DRM6L_pk65FSMebenhCx3RMsTKoBm-AxIlggEf3qk5552QLNSh1T1oQs7_2C2qysDwN4r4fCp52Hsqs', - ), + credentialID, + credentialPublicKey, counter: 0, }, - }); + userDevicePublicKey: [differentDevicePubKey, differentDevicePubKey], + }).then(verification => verification.extensionOutputs?.devicePubKeyToStore)).resolves.toMatchObject(devicePubKey); +}); - expect(verification.authenticationInfo?.authenticatorExtensionResults).toMatchObject({ - devicePublicKey: { - dpk: Buffer.from( - 'A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', - 'hex', - ), - sig: Buffer.from( - '3045022049526CD28AEF6B4E621A7D5936D2B504952FC0AE2313A4F0357AAFFFAEA964740221009D513ACAEFB0B32C765AAE6FEBA8C294685EFF63FF1CBF11ECF2107AF4FEB8F8', - 'hex', - ), - nonce: Buffer.from('', 'hex'), - scope: Buffer.from('00', 'hex'), - aaguid: Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), +test('should return undefined when one device public key matches', async () => { + await expect(verifyAuthenticationResponse({ + credential: authenticationCredentialWithDevicePublicKey, + expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', + expectedRPID: 'try-webauthn.appspot.com', + expectedChallenge: 'q8uITtwG32HTStfvUqU70YsF4R_KP8ZvDbEDIZYzCCw', + authenticator: { + credentialID, + credentialPublicKey, + counter: 0, }, - }); + userDevicePublicKey: [sameDevicePubKey, differentDevicePubKey] + }).then(verification => verification.extensionOutputs?.devicePubKeyToStore)).resolves.toBeUndefined(); }); test('should return credential backup info', async () => { diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts index 35dbd3a9..88993dd2 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts @@ -1,4 +1,41 @@ -it("should verify device public key", async () => { - // TODO: Implement a test for `isRecognizedDevice` - expect(true).toEqual(true); +import { checkAttStmtBinaryEquality, isRecognizedDevice } from './isRecognizedDevice'; +import { AttestationStatement } from "../../helpers/decodeAttestationObject"; +import { DevicePublicKeyAuthenticatorOutput } from '../../helpers/decodeAuthenticatorExtensions'; + +const devicePubKey: DevicePublicKeyAuthenticatorOutput = { + "dpk": Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'), + "sig": Buffer.from('3045022100BC6DD9AF5E47BB3AB82731299EAE82A779189E4E416E3A0E37A3BA64C38F991202205671EFAC0E8CD6DE1D3640CE7E4E89D3A97E0517B603D8AC28F23E4E1F74E639', 'hex'), + "nonce": Buffer.from('', 'hex'), + "scope": Buffer.from('00', 'hex'), + "aaguid": Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), +} + +const sameDevicePubKey = devicePubKey; +const differentDevicePubKey: DevicePublicKeyAuthenticatorOutput = { + "dpk": Buffer.from('A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', 'hex'), + "sig": Buffer.from('3045022049526CD28AEF6B4E621A7D5936D2B504952FC0AE2313A4F0357AAFFFAEA964740221009D513ACAEFB0B32C765AAE6FEBA8C294685EFF63FF1CBF11ECF2107AF4FEB8F8', 'hex'), + "nonce": Buffer.from('', 'hex'), + "scope": Buffer.from('00', 'hex'), + "aaguid": Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), +}; + +it("should throw when more than two device public key matches", async () => { + expect(isRecognizedDevice(devicePubKey, [sameDevicePubKey, sameDevicePubKey])).rejects.toThrowError(new Error('It is undetermined whether this is a known device.')); }); + +it("should return the new device public key when no device public key matches", async () => { + expect(isRecognizedDevice(devicePubKey, [differentDevicePubKey, differentDevicePubKey])).resolves.toMatchObject(sameDevicePubKey); +}); + +it("should return undefined when one device public key matches", async () => { + expect(isRecognizedDevice(devicePubKey, [sameDevicePubKey, differentDevicePubKey])).resolves.toBeUndefined(); +}); + +// Needs test data +// it("should return true on equal attestation statement", () => { +// const responseAttStmt: AttestationStatement = {}; +// const expectedAttStmt: AttestationStatement = {}; + +// const result = checkAttStmtBinaryEquality(responseAttStmt, expectedAttStmt); +// expect(result).toEqual(true); +// }); diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts index 688a4237..201516b1 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts @@ -98,7 +98,7 @@ export async function isRecognizedDevice( } } -function checkAttStmtBinaryEquality( +export function checkAttStmtBinaryEquality( responseAttStmt?: AttestationStatement, knownAttStmt?: AttestationStatement ): boolean { diff --git a/packages/server/src/registration/verifyRegistrationResponse.ts b/packages/server/src/registration/verifyRegistrationResponse.ts index c58ea274..f2a83f50 100644 --- a/packages/server/src/registration/verifyRegistrationResponse.ts +++ b/packages/server/src/registration/verifyRegistrationResponse.ts @@ -28,7 +28,7 @@ import { verifyAttestationTPM } from './verifications/tpm/verifyAttestationTPM'; import { verifyAttestationAndroidKey } from './verifications/verifyAttestationAndroidKey'; import { verifyAttestationApple } from './verifications/verifyAttestationApple'; import { verifyDevicePublicKeySignature, VerifyDevicePublicKeySignatureOpts } from '../extensions/devicePublicKey/verifyDevicePublicKeySignature'; -import { verifyDevicePublicKeyAttestation } from 'extensions/devicePublicKey/verifyDevicePublicKeyAttestation'; +import { verifyDevicePublicKeyAttestation } from '../extensions/devicePublicKey/verifyDevicePublicKeyAttestation'; export type VerifyRegistrationResponseOpts = { credential: RegistrationCredentialJSON; From ac5413ef1a0146231f89b63ddf2ae103f216ec36 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Mon, 29 Aug 2022 13:56:43 +0900 Subject: [PATCH 19/37] Reflect feedback --- .../verifyAuthenticationResponse.test.ts | 10 +-- .../verifyAuthenticationResponse.ts | 25 +++---- .../devicePublicKey/isRecognizedDevice.ts | 67 +++++++++++-------- packages/server/src/index.ts | 2 - 4 files changed, 57 insertions(+), 47 deletions(-) diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts index b5418169..30fb09ad 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts @@ -353,7 +353,7 @@ test('should throw if multiple device public key matches', async () => { credentialPublicKey, counter: 0, }, - userDevicePublicKey: [sameDevicePubKey, sameDevicePubKey], + userDevicePublicKeys: [sameDevicePubKey, sameDevicePubKey], })).rejects.toThrowError(new Error('It is undetermined whether this is a known device.')); }); @@ -368,8 +368,8 @@ test('should return the new device public key when no device public key matches' credentialPublicKey, counter: 0, }, - userDevicePublicKey: [differentDevicePubKey, differentDevicePubKey], - }).then(verification => verification.extensionOutputs?.devicePubKeyToStore)).resolves.toMatchObject(devicePubKey); + userDevicePublicKeys: [differentDevicePubKey, differentDevicePubKey], + }).then(verification => verification.authenticationInfo.extensionOutputs?.devicePubKeyToStore)).resolves.toMatchObject(devicePubKey); }); test('should return undefined when one device public key matches', async () => { @@ -383,8 +383,8 @@ test('should return undefined when one device public key matches', async () => { credentialPublicKey, counter: 0, }, - userDevicePublicKey: [sameDevicePubKey, differentDevicePubKey] - }).then(verification => verification.extensionOutputs?.devicePubKeyToStore)).resolves.toBeUndefined(); + userDevicePublicKeys: [sameDevicePubKey, differentDevicePubKey] + }).then(verification => verification.authenticationInfo.extensionOutputs?.devicePubKeyToStore)).resolves.toBeUndefined(); }); test('should return credential backup info', async () => { diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.ts b/packages/server/src/authentication/verifyAuthenticationResponse.ts index 44c31ef6..80155819 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.ts @@ -26,7 +26,7 @@ export type VerifyAuthenticationResponseOpts = { advancedFIDOConfig?: { userVerification?: UserVerificationRequirement; }; - userDevicePublicKey?: DevicePublicKeyAuthenticatorOutput[]; + userDevicePublicKeys?: DevicePublicKeyAuthenticatorOutput[]; }; /** @@ -59,7 +59,7 @@ export async function verifyAuthenticationResponse( authenticator, requireUserVerification, advancedFIDOConfig, - userDevicePublicKey, + userDevicePublicKeys, } = options; const { id, rawId, type: credentialType, response, clientExtensionResults } = credential; @@ -201,31 +201,32 @@ export async function verifyAuthenticationResponse( if (flags.ed) { if (!extensionsData && !clientExtensionResults) { - throw new Error('Extension results are not included despite the flag.'); + throw new Error('Authenticator data indicated extension data was present,'+ + ' but no client or authenticator extension data were found'); } // TODO: Find a good way to check that returned extension outputs match what // was requested in extension inputs. See 7.1 step 18 in the spec. // DevicePublicKey sample currently provides the data through authenticator - // extension results. + // extension results. if (extensionsData?.devicePubKey) { const { devicePubKey } = extensionsData; - const { sig: signature } = devicePubKey; + const { sig: dpkSig } = devicePubKey; - if (!signature) { - throw new Error('DevicePublicKey signature is missing.'); + if (!dpkSig) { + throw new Error('DevicePublicKey was missing signature.'); } const dpkOptions: VerifyDevicePublicKeySignatureOpts = { credential, devicePubKey, - signature, + signature: dpkSig, }; const result = await verifyDevicePublicKeySignature(dpkOptions); if (!result) { - throw new Error('Verifying DevicePublicKey signature failed.'); + throw new Error('DevicePublicKey signature could not be verified'); } - const devicePubKeyToStore = await isRecognizedDevice(devicePubKey, userDevicePublicKey); + const devicePubKeyToStore = await isRecognizedDevice(devicePubKey, userDevicePublicKeys); extensionOutputs.devicePubKeyToStore = devicePubKeyToStore; } } @@ -259,8 +260,8 @@ export async function verifyAuthenticationResponse( userVerified: flags.uv, credentialDeviceType, credentialBackedUp, + extensionOutputs, }, - extensionOutputs, }; return toReturn; @@ -292,8 +293,8 @@ export type VerifiedAuthenticationResponse = { userVerified: boolean; credentialDeviceType: CredentialDeviceType; credentialBackedUp: boolean; + extensionOutputs: ExtensionOutputs; }; - extensionOutputs: ExtensionOutputs; }; export type ExtensionOutputs = { diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts index 201516b1..4ffa520f 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts @@ -54,8 +54,9 @@ export async function isRecognizedDevice( // pair then: const isValidDPKAttestation = await verifyDevicePublicKeyAttestation(responseDevicePublicKey); if (!isValidDPKAttestation) { - throw new Error('Device public key attestation is invalid.'); + throw new Error('DevicePublicKey attestation could not be verified'); } + // When `fmt` is `none` or the device public key attestation is valid, store the DPK. return responseDevicePublicKey; } else { // Otherwise there is some form of error: we recieved a known dpk @@ -75,14 +76,23 @@ export async function isRecognizedDevice( // verification steps. if (responseDevicePublicKey.fmt && responseDevicePublicKey.fmt !== 'none') { // Perform a binary equality check of `attStmt`. - const knownAttStmt = matchedDPKs[0].attStmt; - if (!checkAttStmtBinaryEquality(responseDevicePublicKey.attStmt, knownAttStmt)) { + const recognizedDPKAttStmt = matchedDPKs[0].attStmt; + let dpksAreBinaryEqual = false; + try { + dpksAreBinaryEqual = checkAttStmtBinaryEquality(responseDevicePublicKey.attStmt, recognizedDPKAttStmt); + } catch (err) { + // const _err = err as Error; + // How do we message the error cause? + // throw new Error(`DevicePublicKey attStmt's were not equal: ${_err.message}`); // Otherwise, verify attestation const isValidDPKAttestation = await verifyDevicePublicKeyAttestation(responseDevicePublicKey); if (!isValidDPKAttestation) { - throw new Error('Device Public Key attestation is invalid.'); + throw new Error('DevicePublicKey attestation could not be verified.'); } } + + if (!dpksAreBinaryEqual) { + } } // This is a valid and a known device. return; @@ -92,49 +102,50 @@ export async function isRecognizedDevice( // fields presently mapped to this user account and credential.id pair: const isValidDPKAttestation = await verifyDevicePublicKeyAttestation(responseDevicePublicKey); if (!isValidDPKAttestation) { - throw new Error('Device Public Key attestation is invalid.'); + throw new Error('DevicePublicKey attestation could not be verified'); } + // When `fmt` is `none` or the device public key attestation is valid, store the DPK. return responseDevicePublicKey; } } export function checkAttStmtBinaryEquality( - responseAttStmt?: AttestationStatement, - knownAttStmt?: AttestationStatement + responseDPKAttStmt?: AttestationStatement, + recognizedDPKAttStmt?: AttestationStatement ): boolean { // `attStmt` in device public key is not optional, but for an interim solution: - if (!responseAttStmt || ! knownAttStmt) { - return false; + if (!responseDPKAttStmt || ! recognizedDPKAttStmt) { + throw new Error('attStmt in a DevicePublicKey is missing.'); } - if (!responseAttStmt.sig || !knownAttStmt.sig || !responseAttStmt.sig.equals(knownAttStmt.sig)) { - return false; + if (!responseDPKAttStmt.sig || !recognizedDPKAttStmt.sig || !responseDPKAttStmt.sig.equals(recognizedDPKAttStmt.sig)) { + throw new Error("Response DPK sig and recognized DPK sig did not match.") } - if (!responseAttStmt.x5c || !knownAttStmt.x5c) { - return false; + if (!responseDPKAttStmt.x5c || !recognizedDPKAttStmt.x5c) { + throw new Error("Response DPK x5c and recognized DPK x5c did not match.") } - if (responseAttStmt.x5c.length !== knownAttStmt.x5c.length) { - return false; + if (responseDPKAttStmt.x5c.length !== recognizedDPKAttStmt.x5c.length) { + throw new Error("Response DPK x5c length and recognized DPK x5c length did not match.") } - for (let i = 0; i < responseAttStmt.x5c.length; i++) { - if (!responseAttStmt.x5c[i].equals(knownAttStmt.x5c[i])) { - return false; + for (let i = 0; i < responseDPKAttStmt.x5c.length; i++) { + if (!responseDPKAttStmt.x5c[i].equals(recognizedDPKAttStmt.x5c[i])) { + throw new Error("Response DPK x5c length and recognized DPK x5c length did not match.") } } - if (!responseAttStmt.response || !knownAttStmt.response || !responseAttStmt.response.equals(knownAttStmt.response)) { - return false; + if (!responseDPKAttStmt.response || !recognizedDPKAttStmt.response || !responseDPKAttStmt.response.equals(recognizedDPKAttStmt.response)) { + throw new Error("Response DPK response and recognized DPK response did not match.") } - if (responseAttStmt.alg !== knownAttStmt.alg) { - return false; + if (responseDPKAttStmt.alg !== recognizedDPKAttStmt.alg) { + throw new Error("Response DPK alg and recognized DPK alg did not match.") } - if (responseAttStmt.ver !== knownAttStmt.ver) { - return false; + if (responseDPKAttStmt.ver !== recognizedDPKAttStmt.ver) { + throw new Error("Response DPK ver and recognized DPK ver did not match.") } - if (!responseAttStmt.certInfo || !knownAttStmt.certInfo || !responseAttStmt.certInfo.equals(knownAttStmt.certInfo)) { - return false; + if (!responseDPKAttStmt.certInfo || !recognizedDPKAttStmt.certInfo || !responseDPKAttStmt.certInfo.equals(recognizedDPKAttStmt.certInfo)) { + throw new Error("Response DPK certInfo and recognized DPK certInfo did not match.") } - if (!responseAttStmt.pubArea || !knownAttStmt.pubArea || !responseAttStmt.pubArea.equals(knownAttStmt.pubArea)) { - return false; + if (!responseDPKAttStmt.pubArea || !recognizedDPKAttStmt.pubArea || !responseDPKAttStmt.pubArea.equals(recognizedDPKAttStmt.pubArea)) { + throw new Error("Response DPK pubArea and recognized DPK pubArea did not match.") } return true; } diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 59a68c8a..a7cb4139 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -8,7 +8,6 @@ import { generateAuthenticationOptions } from './authentication/generateAuthenti import { verifyAuthenticationResponse } from './authentication/verifyAuthenticationResponse'; import { MetadataService } from './services/metadataService'; import { SettingsService } from './services/settingsService'; -import { isRecognizedDevice } from './extensions/devicePublicKey/isRecognizedDevice'; import { DevicePublicKeyAuthenticatorOutput } from './helpers/decodeAuthenticatorExtensions'; export { @@ -18,7 +17,6 @@ export { verifyAuthenticationResponse, MetadataService, SettingsService, - isRecognizedDevice, }; import type { GenerateRegistrationOptionsOpts } from './registration/generateRegistrationOptions'; From a20cade17eac05f90debc2f842c301b82aabda44 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Wed, 28 Sep 2022 22:07:24 -0700 Subject: [PATCH 20/37] chore(release): publish v6.3.0-alpha.0 --- lerna.json | 2 +- packages/server/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lerna.json b/lerna.json index 9e4ff683..4089e083 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "6.2.1", + "version": "6.3.0-alpha.0", "npmClient": "npm", "useNx": true, "command": { diff --git a/packages/server/package.json b/packages/server/package.json index 6fd7930c..0a7b5cb7 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@simplewebauthn/server", - "version": "6.2.1", + "version": "6.3.0-alpha.0", "description": "SimpleWebAuthn for Servers", "main": "dist/index.js", "types": "dist/index.d.ts", From 4ca4a978ddcd0ef7f364b101b38dfece03949c31 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Fri, 2 Sep 2022 16:31:29 +0900 Subject: [PATCH 21/37] Align DPK registration with DPK authentication --- .../verifyAuthenticationResponse.ts | 6 ++-- .../verifyRegistrationResponse.test.ts | 2 +- .../verifyRegistrationResponse.ts | 36 ++++++++++++------- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.ts b/packages/server/src/authentication/verifyAuthenticationResponse.ts index 80155819..4d465581 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.ts @@ -197,7 +197,7 @@ export async function verifyAuthenticationResponse( } } - const extensionOutputs: ExtensionOutputs = {}; + const extensionOutputs: AuthenticationExtensionOutputs = {}; if (flags.ed) { if (!extensionsData && !clientExtensionResults) { @@ -293,10 +293,10 @@ export type VerifiedAuthenticationResponse = { userVerified: boolean; credentialDeviceType: CredentialDeviceType; credentialBackedUp: boolean; - extensionOutputs: ExtensionOutputs; + extensionOutputs: AuthenticationExtensionOutputs; }; }; -export type ExtensionOutputs = { +export type AuthenticationExtensionOutputs = { devicePubKeyToStore?: DevicePublicKeyAuthenticatorOutput; } diff --git a/packages/server/src/registration/verifyRegistrationResponse.test.ts b/packages/server/src/registration/verifyRegistrationResponse.test.ts index 21562bf5..bf0f1061 100644 --- a/packages/server/src/registration/verifyRegistrationResponse.test.ts +++ b/packages/server/src/registration/verifyRegistrationResponse.test.ts @@ -602,7 +602,7 @@ test('should return authenticator extension output', async () => { expectedRPID: 'try-webauthn.appspot.com', }); - expect(verification.registrationInfo?.authenticatorExtensionResults).toMatchObject({ + expect(verification.registrationInfo?.extensionOutputs).toMatchObject({ devicePubKey: { dpk: Buffer.from( 'A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', diff --git a/packages/server/src/registration/verifyRegistrationResponse.ts b/packages/server/src/registration/verifyRegistrationResponse.ts index f2a83f50..051491e0 100644 --- a/packages/server/src/registration/verifyRegistrationResponse.ts +++ b/packages/server/src/registration/verifyRegistrationResponse.ts @@ -10,7 +10,7 @@ import { AttestationStatement, decodeAttestationObject, } from '../helpers/decodeAttestationObject'; -import { AuthenticationExtensionsAuthenticatorOutputs } from '../helpers/decodeAuthenticatorExtensions'; +import { DevicePublicKeyAuthenticatorOutput } from '../helpers/decodeAuthenticatorExtensions'; import { decodeClientDataJSON } from '../helpers/decodeClientDataJSON'; import { parseAuthenticatorData } from '../helpers/parseAuthenticatorData'; import { toHash } from '../helpers/toHash'; @@ -194,30 +194,34 @@ export async function verifyRegistrationResponse( throw new Error(`Unexpected public key alg "${alg}", expected one of "${supported}"`); } + const extensionOutputs: RegistrationExtensionOutputs = {}; + if (flags.ed) { if (!extensionsData && !clientExtensionResults) { - throw new Error('Extension results are not included despite the flag.'); + throw new Error('Authenticator data indicated extension data was present,'+ + ' but no client or authenticator extension data were found'); } // TODO: Find a good way to check that returned extension outputs match what // was requested in extension inputs. See 7.1 step 18 in the spec. - // Device public key sample currently provides the data through - // authenticator extension results. + // DevicePublicKey sample currently provides the data through authenticator + // extension results. if (extensionsData?.devicePubKey) { const { devicePubKey } = extensionsData; - const signature = devicePubKey.sig; - if (!signature) { - throw new Error('DevicePublicKey signature is missing.'); + const { sig: dpkSig } = devicePubKey; + + if (!dpkSig) { + throw new Error('DevicePublicKey was missing signature.'); } const dpkOptions: VerifyDevicePublicKeySignatureOpts = { credential, devicePubKey, - signature, + signature: dpkSig, }; - const sigResult = await verifyDevicePublicKeySignature(dpkOptions); - if (!sigResult) { - throw new Error('Invalid device public key signature.'); + const result = await verifyDevicePublicKeySignature(dpkOptions); + if (!result) { + throw new Error('DevicePublicKey signature could not be verified'); } // Optionally verify device public key attestation here as per @@ -226,6 +230,8 @@ export async function verifyRegistrationResponse( if (!attResult) { throw new Error('Invalid device public key attestation.'); } + + extensionOutputs.devicePubKeyToStore = devicePubKey; } } @@ -288,7 +294,7 @@ export async function verifyRegistrationResponse( userVerified: flags.uv, credentialDeviceType, credentialBackedUp, - authenticatorExtensionResults: extensionsData, + extensionOutputs, }; } @@ -331,7 +337,7 @@ export type VerifiedRegistrationResponse = { userVerified: boolean; credentialDeviceType: CredentialDeviceType; credentialBackedUp: boolean; - authenticatorExtensionResults?: AuthenticationExtensionsAuthenticatorOutputs; + extensionOutputs?: RegistrationExtensionOutputs; }; }; @@ -349,3 +355,7 @@ export type AttestationFormatVerifierOpts = { rpIdHash: Buffer; verifyTimestampMS?: boolean; }; + +export type RegistrationExtensionOutputs = { + devicePubKeyToStore?: DevicePublicKeyAuthenticatorOutput; +} From bf719c491c76530f1b40c35b2da57d64194e8df7 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Tue, 6 Sep 2022 21:10:33 +0900 Subject: [PATCH 22/37] Some progress aligning with the latest DPK spec --- .../verifyAuthenticationResponse.ts | 35 ++++++---- .../devicePublicKey/decodeDevicePubKey.ts | 45 ++++++++++++ .../verifyDevicePublicKeyAttestation.ts | 14 ++-- .../verifyDevicePublicKeySignature.ts | 70 ++----------------- .../helpers/decodeAuthenticatorExtensions.ts | 1 - .../verifyRegistrationResponse.ts | 36 ++++++---- packages/typescript-types/src/index.ts | 26 +++++-- 7 files changed, 125 insertions(+), 102 deletions(-) create mode 100644 packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.ts b/packages/server/src/authentication/verifyAuthenticationResponse.ts index 4d465581..6c76e535 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.ts @@ -15,6 +15,7 @@ import { parseBackupFlags } from '../helpers/parseBackupFlags'; import { DevicePublicKeyAuthenticatorOutput } from '../helpers/decodeAuthenticatorExtensions'; import { verifyDevicePublicKeySignature, VerifyDevicePublicKeySignatureOpts } from '../extensions/devicePublicKey/verifyDevicePublicKeySignature'; import { isRecognizedDevice } from '../extensions/devicePublicKey/isRecognizedDevice'; +import { decodeDevicePubKey, decodeDevicePubKeyAuthenticatorOutput } from 'extensions/devicePublicKey/decodeDevicePubKey'; export type VerifyAuthenticationResponseOpts = { credential: AuthenticationCredentialJSON; @@ -148,7 +149,7 @@ export async function verifyAuthenticationResponse( const authDataBuffer = base64url.toBuffer(response.authenticatorData); const parsedAuthData = parseAuthenticatorData(authDataBuffer); - const { rpIdHash, flags, counter, extensionsData } = parsedAuthData; + const { rpIdHash, flags, counter } = parsedAuthData; // Make sure the response's RP ID is ours if (typeof expectedRPID === 'string') { @@ -200,32 +201,42 @@ export async function verifyAuthenticationResponse( const extensionOutputs: AuthenticationExtensionOutputs = {}; if (flags.ed) { - if (!extensionsData && !clientExtensionResults) { + if (!clientExtensionResults) { throw new Error('Authenticator data indicated extension data was present,'+ - ' but no client or authenticator extension data were found'); + ' but no client extension data were found'); } // TODO: Find a good way to check that returned extension outputs match what // was requested in extension inputs. See 7.1 step 18 in the spec. // DevicePublicKey sample currently provides the data through authenticator - // extension results. - if (extensionsData?.devicePubKey) { - const { devicePubKey } = extensionsData; - const { sig: dpkSig } = devicePubKey; + // extension results. + if (clientExtensionResults.devicePubKey) { + const { devicePubKey: encodedDevicePubKey } = clientExtensionResults; + const devicePubKey = decodeDevicePubKey(encodedDevicePubKey); + if (!devicePubKey) { + throw new Error('No device public key was provided in the client extension results.'); + } + const { authenticatorOutput: encodedAuthenticatorOutput, signature } = devicePubKey; + if (!signature) { + throw new Error('Device public key signature is missing.'); + } - if (!dpkSig) { - throw new Error('DevicePublicKey was missing signature.'); + const authenticatorOutput = decodeDevicePubKeyAuthenticatorOutput(encodedAuthenticatorOutput); + if (!authenticatorOutput) { + throw new Error('Device public key authenticator output is corrupt.'); } + const dpkOptions: VerifyDevicePublicKeySignatureOpts = { credential, - devicePubKey, - signature: dpkSig, + authenticatorOutput, + signature, }; const result = await verifyDevicePublicKeySignature(dpkOptions); if (!result) { - throw new Error('DevicePublicKey signature could not be verified'); + throw new Error('Invalid device public key signature.'); } + const devicePubKeyToStore = await isRecognizedDevice(devicePubKey, userDevicePublicKeys); extensionOutputs.devicePubKeyToStore = devicePubKeyToStore; } diff --git a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts new file mode 100644 index 00000000..b015ffa5 --- /dev/null +++ b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts @@ -0,0 +1,45 @@ +import { decodeCborFirst } from '../../helpers/decodeCbor'; +import { Base64URLString, AuthenticationExtensionsDevicePublicKeyOutputs } from '@simplewebauthn/typescript-types'; +import { AttestationFormat, AttestationStatement } from '../../helpers/decodeAttestationObject'; +import base64url from 'base64url'; + +/** + * Convert device public key client extension data buffer to a proper object + * + * @param devicePubKey Client Extension's device public key data buffer + */ +export function decodeDevicePubKey( + devicePubKey: Base64URLString, +): AuthenticationExtensionsDevicePublicKeyOutputs | undefined { + let toCBOR: AuthenticationExtensionsDevicePublicKeyOutputs | undefined; + try { + const base64DevicePubKey = base64url.toBuffer(devicePubKey); + toCBOR = decodeCborFirst(base64DevicePubKey); + } catch (err) { + const _err = err as Error; + throw new Error(`Error decoding device public key: ${_err.message}`); + } + return toCBOR; +} + +export function decodeDevicePubKeyAuthenticatorOutput( + authenticatorOutput: Buffer, +): DevicePublicKeyAuthenticatorOutput | undefined { + let toCBOR: DevicePublicKeyAuthenticatorOutput | undefined; + try { + toCBOR = decodeCborFirst(authenticatorOutput); + } catch (err) { + const _err = err as Error; + throw new Error(`Error decoding device public key authenticator output: ${_err.message}`); + } + return toCBOR; +} + +export type DevicePublicKeyAuthenticatorOutput = { + aaguid: Buffer; + dpk: Buffer; + scope: Buffer; + nonce?: Buffer; + fmt?: AttestationFormat; + attStmt?: AttestationStatement; +}; diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts index 0c0660ee..cdf7c135 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts @@ -24,12 +24,12 @@ export async function verifyDevicePublicKeyAttestation( const { fmt } = devicePubKey; if (fmt === undefined || fmt === 'none') { return true; - } - - // TODO: Implement the attestation verification logic. - // const prefix = Buffer.from('64657669636520626f756e64206b6579206174746573746174696f6e2073696700ffffffff', 'hex'); - // const authData = Buffer.concat([prefix, aaguid]); - // const clientDataHash = Buffer.concat([dpk, nonce || Buffer.from('')]); + } else { + throw new Error('Attestation verification on a device public key is not implemented yet.'); - return true; + // TODO: Implement the attestation verification logic. + // const prefix = Buffer.from('64657669636520626f756e64206b6579206174746573746174696f6e2073696700ffffffff', 'hex'); + // const authData = Buffer.concat([prefix, aaguid]); + // const clientDataHash = Buffer.concat([dpk, nonce || Buffer.from('')]); + } } diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts index 7fe17ff0..9a857028 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts @@ -2,15 +2,6 @@ import base64url from "base64url"; import { toHash } from "../../helpers/toHash"; import { verifySignature } from "../../helpers/verifySignature"; import { DevicePublicKeyAuthenticatorOutput } from "../../helpers/decodeAuthenticatorExtensions"; -import { SettingsService } from "../../services/settingsService"; -import { AttestationFormatVerifierOpts } from "../../registration/verifyRegistrationResponse"; -import { parseAuthenticatorData } from "../../helpers/parseAuthenticatorData"; -import { verifyAttestationFIDOU2F } from '../../registration/verifications/verifyAttestationFIDOU2F'; -import { verifyAttestationPacked } from '../../registration/verifications/verifyAttestationPacked'; -import { verifyAttestationAndroidSafetyNet } from '../../registration/verifications/verifyAttestationAndroidSafetyNet'; -import { verifyAttestationTPM } from '../../registration/verifications/tpm/verifyAttestationTPM'; -import { verifyAttestationAndroidKey } from '../../registration/verifications/verifyAttestationAndroidKey'; -import { verifyAttestationApple } from '../../registration/verifications/verifyAttestationApple'; import { AuthenticationCredentialJSON, AuthenticatorAssertionResponseJSON, @@ -21,7 +12,7 @@ import { decodeAttestationObject } from "../../helpers/decodeAttestationObject"; export type VerifyDevicePublicKeySignatureOpts = { credential: RegistrationCredentialJSON | AuthenticationCredentialJSON - devicePubKey: DevicePublicKeyAuthenticatorOutput; + authenticatorOutput: DevicePublicKeyAuthenticatorOutput; signature: Buffer; }; @@ -36,7 +27,7 @@ export type VerifyDevicePublicKeySignatureOpts = { export async function verifyDevicePublicKeySignature( options: VerifyDevicePublicKeySignatureOpts ): Promise { - const { credential, devicePubKey, signature } = options; + const { credential, authenticatorOutput, signature } = options; let authData; if (isAuthenticationResponse(credential)) { @@ -53,63 +44,12 @@ export async function verifyDevicePublicKeySignature( const { clientDataJSON } = credential.response; const clientDataHash = toHash(base64url.toBuffer(clientDataJSON)); - const credentialID = base64url.toBuffer(credential.id); - const { rpIdHash } = parseAuthenticatorData(authData); - const nonce = devicePubKey.nonce ? devicePubKey.nonce : Buffer.from(''); - // According to the spec, `authData` and `clientDataHash` are concatenated as - // the signature base, but this is an interim implementation. - const signatureBase = Buffer.concat([credentialID, clientDataHash, nonce]); + const nonce = authenticatorOutput.nonce ? authenticatorOutput.nonce : Buffer.from(''); + const signatureBase = Buffer.concat([authData, clientDataHash, nonce]); // It's a device public key and not a credential public key, but to align with // the `verifySinature` signature, we name it `credentialPublicKey`. - const credentialPublicKey = devicePubKey.dpk; - - if (devicePubKey.fmt && devicePubKey.attStmt) { - const rootCertificates = SettingsService.getRootCertificates({ identifier: devicePubKey.fmt }); - - // Prepare arguments to pass to the relevant verification method - const verifierOpts: AttestationFormatVerifierOpts = { - aaguid: devicePubKey.aaguid, - attStmt: devicePubKey.attStmt, - authData, - clientDataHash, - credentialID, - credentialPublicKey, - rootCertificates, - rpIdHash, - }; - - // TODO: Implement logics to verify attestation signatures - let verified = false; - if (devicePubKey.fmt === 'fido-u2f') { - verified = await verifyAttestationFIDOU2F(verifierOpts); - } else if (devicePubKey.fmt === 'packed') { - verified = await verifyAttestationPacked(verifierOpts); - } else if (devicePubKey.fmt === 'android-safetynet') { - verified = await verifyAttestationAndroidSafetyNet(verifierOpts); - } else if (devicePubKey.fmt === 'android-key') { - verified = await verifyAttestationAndroidKey(verifierOpts); - } else if (devicePubKey.fmt === 'tpm') { - verified = await verifyAttestationTPM(verifierOpts); - } else if (devicePubKey.fmt === 'apple') { - verified = await verifyAttestationApple(verifierOpts); - } else if (devicePubKey.fmt === 'none') { - if (Object.keys(devicePubKey.attStmt).length > 0) { - throw new Error('None attestation had unexpected attestation statement'); - } - // This is the weaker of the attestations, so there's nothing else to really check - verified = true; - } else { - throw new Error(`Unsupported Attestation Format: ${devicePubKey.fmt}`); - } - if (!verified) { - return false; - } - } else { - // `fmt` and `attStmt` are required fields, though at the moment, as the test - // attestation omits it. Ignore this case intentionally. - // return false; - } + const credentialPublicKey = authenticatorOutput.dpk; return verifySignature({ signature, signatureBase, credentialPublicKey }); } diff --git a/packages/server/src/helpers/decodeAuthenticatorExtensions.ts b/packages/server/src/helpers/decodeAuthenticatorExtensions.ts index 7ac357f7..7a77a211 100644 --- a/packages/server/src/helpers/decodeAuthenticatorExtensions.ts +++ b/packages/server/src/helpers/decodeAuthenticatorExtensions.ts @@ -31,7 +31,6 @@ export type DevicePublicKeyAuthenticatorOutput = { nonce?: Buffer; fmt?: AttestationFormat; attStmt?: AttestationStatement; - sig?: Buffer; }; // TODO: Need to verify this format diff --git a/packages/server/src/registration/verifyRegistrationResponse.ts b/packages/server/src/registration/verifyRegistrationResponse.ts index 051491e0..b06179a6 100644 --- a/packages/server/src/registration/verifyRegistrationResponse.ts +++ b/packages/server/src/registration/verifyRegistrationResponse.ts @@ -29,6 +29,7 @@ import { verifyAttestationAndroidKey } from './verifications/verifyAttestationAn import { verifyAttestationApple } from './verifications/verifyAttestationApple'; import { verifyDevicePublicKeySignature, VerifyDevicePublicKeySignatureOpts } from '../extensions/devicePublicKey/verifyDevicePublicKeySignature'; import { verifyDevicePublicKeyAttestation } from '../extensions/devicePublicKey/verifyDevicePublicKeyAttestation'; +import { decodeDevicePubKey, decodeDevicePubKeyAuthenticatorOutput } from '../extensions/devicePublicKey/decodeDevicePubKey'; export type VerifyRegistrationResponseOpts = { credential: RegistrationCredentialJSON; @@ -136,7 +137,7 @@ export async function verifyRegistrationResponse( const { fmt, authData, attStmt } = decodedAttestationObject; const parsedAuthData = parseAuthenticatorData(authData); - const { aaguid, rpIdHash, flags, credentialID, counter, credentialPublicKey, extensionsData } = + const { aaguid, rpIdHash, flags, credentialID, counter, credentialPublicKey } = parsedAuthData; // Make sure the response's RP ID is ours @@ -197,27 +198,36 @@ export async function verifyRegistrationResponse( const extensionOutputs: RegistrationExtensionOutputs = {}; if (flags.ed) { - if (!extensionsData && !clientExtensionResults) { + if (!clientExtensionResults) { throw new Error('Authenticator data indicated extension data was present,'+ - ' but no client or authenticator extension data were found'); + ' but no client extension data were found'); } // TODO: Find a good way to check that returned extension outputs match what // was requested in extension inputs. See 7.1 step 18 in the spec. - // DevicePublicKey sample currently provides the data through authenticator - // extension results. - if (extensionsData?.devicePubKey) { - const { devicePubKey } = extensionsData; - const { sig: dpkSig } = devicePubKey; + // Device public key sample currently provides the data through + // authenticator extension results. + if (clientExtensionResults.devicePubKey) { + const { devicePubKey: encodedDevicePubKey } = clientExtensionResults; + const devicePubKey = decodeDevicePubKey(encodedDevicePubKey); + if (!devicePubKey) { + throw new Error('No device public key was provided in the client extension results.'); + } + const { authenticatorOutput: encodedAuthenticatorOutput, signature } = devicePubKey; + if (!signature) { + throw new Error('Device public key signature is missing.'); + } - if (!dpkSig) { - throw new Error('DevicePublicKey was missing signature.'); + const authenticatorOutput = decodeDevicePubKeyAuthenticatorOutput(encodedAuthenticatorOutput); + if (!authenticatorOutput) { + throw new Error('Device public key authenticator output is corrupt.'); } + const dpkOptions: VerifyDevicePublicKeySignatureOpts = { credential, - devicePubKey, - signature: dpkSig, + authenticatorOutput, + signature, }; const result = await verifyDevicePublicKeySignature(dpkOptions); if (!result) { @@ -226,7 +236,7 @@ export async function verifyRegistrationResponse( // Optionally verify device public key attestation here as per // 10.2.2.3.1. step 4 in the spec. - const attResult = await verifyDevicePublicKeyAttestation(devicePubKey); + const attResult = await verifyDevicePublicKeyAttestation(encodedDevicePubKey); if (!attResult) { throw new Error('Invalid device public key attestation.'); } diff --git a/packages/typescript-types/src/index.ts b/packages/typescript-types/src/index.ts index 75135558..b82c1e1e 100644 --- a/packages/typescript-types/src/index.ts +++ b/packages/typescript-types/src/index.ts @@ -28,7 +28,7 @@ export interface PublicKeyCredentialCreationOptionsJSON user: PublicKeyCredentialUserEntityJSON; challenge: Base64URLString; excludeCredentials: PublicKeyCredentialDescriptorJSON[]; - extensions?: AuthenticationExtensionsClientInputs; + extensions?: AuthenticationExtensionsClientInputsFuture; } /** @@ -39,7 +39,7 @@ export interface PublicKeyCredentialRequestOptionsJSON extends Omit { challenge: Base64URLString; allowCredentials?: PublicKeyCredentialDescriptorJSON[]; - extensions?: AuthenticationExtensionsClientInputs; + extensions?: AuthenticationExtensionsClientInputsFuture; } export interface PublicKeyCredentialDescriptorJSON @@ -68,7 +68,7 @@ export interface RegistrationCredentialJSON extends Omit { rawId: Base64URLString; response: AuthenticatorAttestationResponseJSON; - clientExtensionResults: AuthenticationExtensionsClientOutputs; + clientExtensionResults: AuthenticationExtensionsClientOutputsFuture; transports?: AuthenticatorTransportFuture[]; } @@ -87,7 +87,25 @@ export interface AuthenticationCredentialJSON extends Omit { rawId: Base64URLString; response: AuthenticatorAssertionResponseJSON; - clientExtensionResults: AuthenticationExtensionsClientOutputs; + clientExtensionResults: AuthenticationExtensionsClientOutputsFuture; +} + +export interface AuthenticationExtensionsDevicePublicKeyInputs { + attestation: string; + attestationFormats: string[]; +} + +export interface AuthenticationExtensionsClientInputsFuture extends AuthenticationExtensionsClientInputs { + devicePubKey: AuthenticationExtensionsDevicePublicKeyInputs; +} + +export interface AuthenticationExtensionsDevicePublicKeyOutputs { + authenticatorOutput: Buffer; + signature: Buffer; +} + +export interface AuthenticationExtensionsClientOutputsFuture extends AuthenticationExtensionsClientOutputs { + devicePubKey: AuthenticationExtensionsDevicePublicKeyOutputs } /** From 501b6c3660020b90ee9580733be91f98d0a92ec8 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Fri, 9 Sep 2022 18:01:50 +0900 Subject: [PATCH 23/37] All tests succeed now --- package-lock.json | 1087 ++++++++++++++--- packages/server/package-lock.json | 695 +++++++++++ .../generateAuthenticationOptions.ts | 4 +- .../verifyAuthenticationResponse.test.ts | 66 +- .../verifyAuthenticationResponse.ts | 33 +- .../devicePublicKey/decodeDevicePubKey.ts | 39 +- .../isRecognizedDevice.test.ts | 11 +- .../devicePublicKey/isRecognizedDevice.ts | 7 +- .../verifyDevicePublicKeyAttestation.ts | 2 +- .../verifyDevicePublicKeySignature.test.ts | 86 +- .../verifyDevicePublicKeySignature.ts | 2 +- .../helpers/decodeAuthenticatorExtensions.ts | 11 +- packages/server/src/index.ts | 2 - .../verifyRegistrationResponse.test.ts | 35 +- .../verifyRegistrationResponse.ts | 36 +- packages/typescript-types/package-lock.json | 13 + packages/typescript-types/src/index.ts | 17 +- 17 files changed, 1827 insertions(+), 319 deletions(-) create mode 100644 packages/server/package-lock.json create mode 100644 packages/typescript-types/package-lock.json diff --git a/package-lock.json b/package-lock.json index 15096cd4..64e95a65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,28 @@ "packages": { "": { "name": "simplewebauthn-monorepo", + "dependencies": { + "@noble/ed25519": "^1.6.1", + "@peculiar/asn1-android": "^2.1.7", + "@peculiar/asn1-schema": "^2.1.7", + "@peculiar/asn1-x509": "^2.1.7", + "@rollup/plugin-node-resolve": "^13.0.0", + "@rollup/plugin-typescript": "^8.2.1", + "@types/cbor": "^5.0.1", + "@types/debug": "^4.1.7", + "@types/jsrsasign": "^8.0.13", + "@types/jwk-to-pem": "^2.0.1", + "@types/node-fetch": "^2.5.12", + "base64url": "^3.0.1", + "cbor": "^5.1.0", + "debug": "^4.3.2", + "jsrsasign": "^10.4.0", + "jwk-to-pem": "^2.0.4", + "node-fetch": "^2.6.0", + "rollup": "^2.52.1", + "rollup-plugin-terser": "^7.0.2", + "rollup-plugin-version-injector": "^1.3.3" + }, "devDependencies": { "@types/express": "^4.17.9", "@types/jest": "^27.0.1", @@ -45,7 +67,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, "dependencies": { "@babel/highlight": "^7.10.4" } @@ -276,7 +297,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -308,7 +328,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", @@ -322,7 +341,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -334,7 +352,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -348,7 +365,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -356,14 +372,12 @@ "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -372,7 +386,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, "engines": { "node": ">=4" } @@ -381,7 +394,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -1034,7 +1046,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -1043,7 +1054,28 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, "engines": { "node": ">=6.0.0" } @@ -1051,14 +1083,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.15", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -2083,6 +2113,17 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/@noble/ed25519": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.0.tgz", + "integrity": "sha512-LeAxFK0+181zQOhOUuKE8Jnd3duzYhDNd3iCLxpmzA5K+e4I1FdbrK3Ot0ZHBwZMeRD/6EojyUfTbpHZ+hkQHg==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2584,6 +2625,95 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@peculiar/asn1-android": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.3.0.tgz", + "integrity": "sha512-ooQ6zRxSXcJ7IW6y7rd3DztgGwzJ3Esq28ideiVwj1hmkPHwqhoRvgHoeddOUQds9GHiwDN5uM/fufnTOxrG2A==", + "dependencies": { + "@peculiar/asn1-schema": "^2.3.0", + "asn1js": "^3.0.5", + "tslib": "^2.4.0" + } + }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.0.tgz", + "integrity": "sha512-DtNLAG4vmDrdSJFPe7rypkcj597chNQL7u+2dBtYo5mh7VW2+im6ke+O0NVr8W1f4re4C3F71LhoMb0Yxqa48Q==", + "dependencies": { + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@peculiar/asn1-x509": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.3.0.tgz", + "integrity": "sha512-iDRNPHAx/HLwR9wN5xaHDPifpdSW/bquu+zo/kQXurnxg6KQ1jcZw+4a63uTvrzyGU/hHzDqjalG/sQvV02lAw==", + "dependencies": { + "@peculiar/asn1-schema": "^2.3.0", + "asn1js": "^3.0.5", + "ipaddr.js": "^2.0.1", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz", + "integrity": "sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^2.42.0" + } + }, + "node_modules/@rollup/plugin-typescript": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.5.0.tgz", + "integrity": "sha512-wMv1/scv0m/rXx21wD2IsBbJFba8wGF3ErJIr6IKRfRj49S85Lszbxb4DCo8iILpluTjk2GAAu9CoZt4G3ppgQ==", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "resolve": "^1.17.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0", + "tslib": "*", + "typescript": ">=3.7.0" + }, + "peerDependenciesMeta": { + "tslib": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, "node_modules/@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -2698,6 +2828,14 @@ "@types/node": "*" } }, + "node_modules/@types/cbor": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/cbor/-/cbor-5.0.1.tgz", + "integrity": "sha512-zVqJy2KzusZPLOgyGJDnOIbu3DxIGGqxYbEwtEEe4Z+la8jwIhOyb+GMrlHafs5tvKruwf8f8qOYP6zTvse/pw==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -2707,6 +2845,19 @@ "@types/node": "*" } }, + "node_modules/@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + }, "node_modules/@types/express": { "version": "4.17.13", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", @@ -2785,6 +2936,16 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/jsrsasign": { + "version": "8.0.13", + "resolved": "https://registry.npmjs.org/@types/jsrsasign/-/jsrsasign-8.0.13.tgz", + "integrity": "sha512-+0Ij59D6NXP48KkeLhPXeQKOyLjvA9CD7zacc0Svy2IWHdl62BmDeTvGSIwKaGZSoamLJOo+on1AG/wPRLsd7A==" + }, + "node_modules/@types/jwk-to-pem": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/jwk-to-pem/-/jwk-to-pem-2.0.1.tgz", + "integrity": "sha512-QXmRPhR/LPzvXBHTPfG2BBfMTkNLUD7NyRcPft8m5xFCeANa1BZyLgT0Gw+OxdWx6i1WCpT27EqyggP4UUHMrA==" + }, "node_modules/@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", @@ -2803,11 +2964,24 @@ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, + "node_modules/@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, "node_modules/@types/node": { "version": "18.7.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz", - "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==", - "dev": true + "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==" + }, + "node_modules/@types/node-fetch": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", + "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -2839,6 +3013,14 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", @@ -3253,7 +3435,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -3350,6 +3531,30 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "dev": true }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1js": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", + "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", + "dependencies": { + "pvtsutils": "^1.3.2", + "pvutils": "^1.1.3", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -3362,8 +3567,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/at-least-node": { "version": "1.0.0", @@ -3492,12 +3696,28 @@ } ] }, + "node_modules/base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/before-after-hook": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==", "dev": true }, + "node_modules/bignumber.js": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.0.tgz", + "integrity": "sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A==", + "engines": { + "node": "*" + } + }, "node_modules/bin-links": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-3.0.3.tgz", @@ -3557,6 +3777,11 @@ "readable-stream": "^3.4.0" } }, + "node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3579,6 +3804,11 @@ "node": ">=8" } }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, "node_modules/browser-process-hrtime": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", @@ -3661,8 +3891,18 @@ "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/builtins": { "version": "5.0.1", @@ -3802,11 +4042,22 @@ } ] }, + "node_modules/cbor": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", + "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", + "dependencies": { + "bignumber.js": "^9.0.1", + "nofilter": "^1.0.4" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -4023,7 +4274,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -4034,8 +4284,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/color-support": { "version": "1.1.3", @@ -4069,7 +4318,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -4396,7 +4644,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -4471,7 +4718,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4498,7 +4744,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -4651,6 +4896,20 @@ "integrity": "sha512-gEM2awN5HZknWdLbngk4uQCVfhucFAfFzuchP3wM3NN6eow1eDU0dFy2kts43FB20ZfhVFF0jmFSTb1h5OhyIg==", "dev": true }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "node_modules/emittery": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", @@ -4673,7 +4932,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -4683,7 +4941,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -5087,6 +5344,11 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -5308,7 +5570,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -5361,7 +5622,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -5374,8 +5634,7 @@ "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "node_modules/functional-red-black-tree": { "version": "1.0.1", @@ -5712,7 +5971,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "dependencies": { "function-bind": "^1.1.1" }, @@ -5724,7 +5982,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -5735,6 +5992,25 @@ "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", "dev": true }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "node_modules/hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -5989,8 +6265,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { "version": "1.3.8", @@ -6075,6 +6350,14 @@ "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", "dev": true }, + "node_modules/ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", + "engines": { + "node": ">= 10" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -6093,6 +6376,20 @@ "node": ">=8" } }, + "node_modules/is-builtin-module": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", + "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-ci": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", @@ -6115,7 +6412,6 @@ "version": "2.10.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, "dependencies": { "has": "^1.0.3" }, @@ -6192,6 +6488,11 @@ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "dev": true }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -7030,8 +7331,7 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "3.14.1", @@ -7210,6 +7510,14 @@ "node": "*" } }, + "node_modules/jsrsasign": { + "version": "10.5.27", + "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.5.27.tgz", + "integrity": "sha512-1F4LmDeJZHYwoVvB44jEo2uZL3XuwYNzXCDOu53Ui6vqofGQ/gCYDmaxfVZtN0TGd92UKXr/BONcfrPonUIcQQ==", + "funding": { + "url": "https://github.com/kjur/jsrsasign#donations" + } + }, "node_modules/just-diff": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-5.1.1.tgz", @@ -7222,6 +7530,16 @@ "integrity": "sha512-AAV5Jw7tsniWwih8Ly3fXxEZ06y+6p5TwQMsw0dzZ/wPKilzyDgdAnL0Ug4NNIquPUOh1vfFWEHbmXUqM5+o8g==", "dev": true }, + "node_modules/jwk-to-pem": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz", + "integrity": "sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==", + "dependencies": { + "asn1.js": "^5.3.0", + "elliptic": "^6.5.4", + "safe-buffer": "^5.0.1" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -7517,8 +7835,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.ismatch": { "version": "4.4.0", @@ -7854,8 +8171,7 @@ "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, "node_modules/merge2": { "version": "1.4.1", @@ -7883,7 +8199,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -7892,7 +8207,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -7918,6 +8232,16 @@ "node": ">=4" } }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -8088,8 +8412,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/multimatch": { "version": "5.0.0", @@ -8156,7 +8479,6 @@ "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -8175,20 +8497,17 @@ "node_modules/node-fetch/node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/node-fetch/node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/node-fetch/node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -8241,6 +8560,14 @@ "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", "dev": true }, + "node_modules/nofilter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz", + "integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==", + "engines": { + "node": ">=8" + } + }, "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -9174,8 +9501,7 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-type": { "version": "4.0.0", @@ -9196,7 +9522,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -9406,6 +9731,22 @@ "node": ">=6" } }, + "node_modules/pvtsutils": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.2.tgz", + "integrity": "sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/pvutils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", + "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -9445,6 +9786,14 @@ "node": ">=8" } }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -9840,7 +10189,6 @@ "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, "dependencies": { "is-core-module": "^2.9.0", "path-parse": "^1.0.7", @@ -9945,6 +10293,65 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rollup": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.0.tgz", + "integrity": "sha512-x4KsrCgwQ7ZJPcFA/SUu6QVcYlO7uRLfLAy0DSA4NS2eG8japdbpM50ToH7z4iObodRYOJ0soneF0iaQRJ6zhA==", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0" + } + }, + "node_modules/rollup-plugin-terser/node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/rollup-plugin-version-injector": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-version-injector/-/rollup-plugin-version-injector-1.3.3.tgz", + "integrity": "sha512-+Rrf0xIFHkwFGuMfphVlAOtd9FlhHFh3vrDwamJ6+YR3IxebRHGVT879qwWzZ1CpWMCLlngb2MmHW5wC5EJqvg==", + "dependencies": { + "chalk": "^4.1.0", + "dateformat": "^4.2.1", + "lodash": "^4.17.20" + } + }, + "node_modules/rollup-plugin-version-injector/node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "engines": { + "node": "*" + } + }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -9989,14 +10396,12 @@ "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/saxes": { "version": "5.0.1", @@ -10043,6 +10448,14 @@ "node": ">=10" } }, + "node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -10194,7 +10607,6 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -10203,7 +10615,6 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -10464,7 +10875,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -10489,7 +10899,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -10616,6 +11025,39 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/terser": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz", + "integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==", + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -10911,8 +11353,7 @@ "node_modules/tslib": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -11058,7 +11499,6 @@ "version": "4.7.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", - "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -11655,7 +12095,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, "requires": { "@babel/highlight": "^7.10.4" } @@ -11833,8 +12272,7 @@ "@babel/helper-validator-identifier": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", - "dev": true + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" }, "@babel/helper-validator-option": { "version": "7.18.6", @@ -11857,7 +12295,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", @@ -11868,7 +12305,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -11877,7 +12313,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -11888,7 +12323,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -11896,26 +12330,22 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -12431,26 +12861,43 @@ "@jridgewell/resolve-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" }, "@jridgewell/set-array": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } }, "@jridgewell/sourcemap-codec": { "version": "1.4.14", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "@jridgewell/trace-mapping": { "version": "0.3.15", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", - "dev": true, "requires": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -13293,6 +13740,11 @@ } } }, + "@noble/ed25519": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.0.tgz", + "integrity": "sha512-LeAxFK0+181zQOhOUuKE8Jnd3duzYhDNd3iCLxpmzA5K+e4I1FdbrK3Ot0ZHBwZMeRD/6EojyUfTbpHZ+hkQHg==" + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -13689,6 +14141,70 @@ "node-gyp-build": "^4.3.0" } }, + "@peculiar/asn1-android": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.3.0.tgz", + "integrity": "sha512-ooQ6zRxSXcJ7IW6y7rd3DztgGwzJ3Esq28ideiVwj1hmkPHwqhoRvgHoeddOUQds9GHiwDN5uM/fufnTOxrG2A==", + "requires": { + "@peculiar/asn1-schema": "^2.3.0", + "asn1js": "^3.0.5", + "tslib": "^2.4.0" + } + }, + "@peculiar/asn1-schema": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.0.tgz", + "integrity": "sha512-DtNLAG4vmDrdSJFPe7rypkcj597chNQL7u+2dBtYo5mh7VW2+im6ke+O0NVr8W1f4re4C3F71LhoMb0Yxqa48Q==", + "requires": { + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, + "@peculiar/asn1-x509": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.3.0.tgz", + "integrity": "sha512-iDRNPHAx/HLwR9wN5xaHDPifpdSW/bquu+zo/kQXurnxg6KQ1jcZw+4a63uTvrzyGU/hHzDqjalG/sQvV02lAw==", + "requires": { + "@peculiar/asn1-schema": "^2.3.0", + "asn1js": "^3.0.5", + "ipaddr.js": "^2.0.1", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, + "@rollup/plugin-node-resolve": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz", + "integrity": "sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==", + "requires": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + } + }, + "@rollup/plugin-typescript": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.5.0.tgz", + "integrity": "sha512-wMv1/scv0m/rXx21wD2IsBbJFba8wGF3ErJIr6IKRfRj49S85Lszbxb4DCo8iILpluTjk2GAAu9CoZt4G3ppgQ==", + "requires": { + "@rollup/pluginutils": "^3.1.0", + "resolve": "^1.17.0" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + } + }, "@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -13800,6 +14316,14 @@ "@types/node": "*" } }, + "@types/cbor": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/cbor/-/cbor-5.0.1.tgz", + "integrity": "sha512-zVqJy2KzusZPLOgyGJDnOIbu3DxIGGqxYbEwtEEe4Z+la8jwIhOyb+GMrlHafs5tvKruwf8f8qOYP6zTvse/pw==", + "requires": { + "@types/node": "*" + } + }, "@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -13809,6 +14333,19 @@ "@types/node": "*" } }, + "@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "requires": { + "@types/ms": "*" + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + }, "@types/express": { "version": "4.17.13", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", @@ -13887,6 +14424,16 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "@types/jsrsasign": { + "version": "8.0.13", + "resolved": "https://registry.npmjs.org/@types/jsrsasign/-/jsrsasign-8.0.13.tgz", + "integrity": "sha512-+0Ij59D6NXP48KkeLhPXeQKOyLjvA9CD7zacc0Svy2IWHdl62BmDeTvGSIwKaGZSoamLJOo+on1AG/wPRLsd7A==" + }, + "@types/jwk-to-pem": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/jwk-to-pem/-/jwk-to-pem-2.0.1.tgz", + "integrity": "sha512-QXmRPhR/LPzvXBHTPfG2BBfMTkNLUD7NyRcPft8m5xFCeANa1BZyLgT0Gw+OxdWx6i1WCpT27EqyggP4UUHMrA==" + }, "@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", @@ -13905,11 +14452,24 @@ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, + "@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, "@types/node": { "version": "18.7.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz", - "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==", - "dev": true + "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==" + }, + "@types/node-fetch": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", + "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + } }, "@types/normalize-package-data": { "version": "2.4.1", @@ -13941,6 +14501,14 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "requires": { + "@types/node": "*" + } + }, "@types/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", @@ -14222,7 +14790,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -14298,6 +14865,27 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "dev": true }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "asn1js": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", + "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", + "requires": { + "pvtsutils": "^1.3.2", + "pvutils": "^1.1.3", + "tslib": "^2.4.0" + } + }, "astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -14307,8 +14895,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "at-least-node": { "version": "1.0.0", @@ -14399,12 +14986,22 @@ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true }, + "base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" + }, "before-after-hook": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==", "dev": true }, + "bignumber.js": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.0.tgz", + "integrity": "sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A==" + }, "bin-links": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-3.0.3.tgz", @@ -14454,6 +15051,11 @@ "readable-stream": "^3.4.0" } }, + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -14473,6 +15075,11 @@ "fill-range": "^7.0.1" } }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, "browser-process-hrtime": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", @@ -14522,8 +15129,12 @@ "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==" }, "builtins": { "version": "5.0.1", @@ -14628,11 +15239,19 @@ "integrity": "sha512-I5XeHI1x/mRSGl96LFOaSk528LA/yZG3m3iQgImGujjO8gotd/DL8QaI1R1h1dg5ATeI2jqPblMpKq4Tr5iKfQ==", "dev": true }, + "cbor": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", + "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", + "requires": { + "bignumber.js": "^9.0.1", + "nofilter": "^1.0.4" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -14791,7 +15410,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } @@ -14799,8 +15417,7 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "color-support": { "version": "1.1.3", @@ -14828,7 +15445,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -15098,7 +15714,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -15154,8 +15769,7 @@ "deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" }, "defaults": { "version": "1.0.3", @@ -15175,8 +15789,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, "delegates": { "version": "1.0.0", @@ -15292,6 +15905,20 @@ "integrity": "sha512-gEM2awN5HZknWdLbngk4uQCVfhucFAfFzuchP3wM3NN6eow1eDU0dFy2kts43FB20ZfhVFF0jmFSTb1h5OhyIg==", "dev": true }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "emittery": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", @@ -15308,7 +15935,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "optional": true, "requires": { "iconv-lite": "^0.6.2" @@ -15318,7 +15944,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -15620,6 +16245,11 @@ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -15798,7 +16428,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -15842,14 +16471,12 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "optional": true }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -16109,7 +16736,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -16117,8 +16743,7 @@ "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "has-unicode": { "version": "2.0.1", @@ -16126,6 +16751,25 @@ "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", "dev": true }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -16310,8 +16954,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { "version": "1.3.8", @@ -16386,6 +17029,11 @@ "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", "dev": true }, + "ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==" + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -16401,6 +17049,14 @@ "binary-extensions": "^2.0.0" } }, + "is-builtin-module": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", + "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", + "requires": { + "builtin-modules": "^3.3.0" + } + }, "is-ci": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", @@ -16422,7 +17078,6 @@ "version": "2.10.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, "requires": { "has": "^1.0.3" } @@ -16472,6 +17127,11 @@ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "dev": true }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -17123,8 +17783,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.14.1", @@ -17259,6 +17918,11 @@ "through": ">=2.2.7 <3" } }, + "jsrsasign": { + "version": "10.5.27", + "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.5.27.tgz", + "integrity": "sha512-1F4LmDeJZHYwoVvB44jEo2uZL3XuwYNzXCDOu53Ui6vqofGQ/gCYDmaxfVZtN0TGd92UKXr/BONcfrPonUIcQQ==" + }, "just-diff": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-5.1.1.tgz", @@ -17271,6 +17935,16 @@ "integrity": "sha512-AAV5Jw7tsniWwih8Ly3fXxEZ06y+6p5TwQMsw0dzZ/wPKilzyDgdAnL0Ug4NNIquPUOh1vfFWEHbmXUqM5+o8g==", "dev": true }, + "jwk-to-pem": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz", + "integrity": "sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==", + "requires": { + "asn1.js": "^5.3.0", + "elliptic": "^6.5.4", + "safe-buffer": "^5.0.1" + } + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -17505,8 +18179,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.ismatch": { "version": "4.4.0", @@ -17770,8 +18443,7 @@ "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, "merge2": { "version": "1.4.1", @@ -17792,14 +18464,12 @@ "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "requires": { "mime-db": "1.52.0" } @@ -17816,6 +18486,16 @@ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -17945,8 +18625,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "multimatch": { "version": "5.0.0", @@ -18003,7 +18682,6 @@ "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, "requires": { "whatwg-url": "^5.0.0" }, @@ -18011,20 +18689,17 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -18068,6 +18743,11 @@ "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", "dev": true }, + "nofilter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz", + "integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==" + }, "nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -18781,8 +19461,7 @@ "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "path-type": { "version": "4.0.0", @@ -18799,8 +19478,7 @@ "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "pify": { "version": "5.0.0", @@ -18952,6 +19630,19 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "pvtsutils": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.2.tgz", + "integrity": "sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==", + "requires": { + "tslib": "^2.4.0" + } + }, + "pvutils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", + "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==" + }, "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -18970,6 +19661,14 @@ "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -19278,7 +19977,6 @@ "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, "requires": { "is-core-module": "^2.9.0", "path-parse": "^1.0.7", @@ -19351,6 +20049,54 @@ "glob": "^7.1.3" } }, + "rollup": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.0.tgz", + "integrity": "sha512-x4KsrCgwQ7ZJPcFA/SUu6QVcYlO7uRLfLAy0DSA4NS2eG8japdbpM50ToH7z4iObodRYOJ0soneF0iaQRJ6zhA==", + "requires": { + "fsevents": "~2.3.2" + } + }, + "rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "requires": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + }, + "dependencies": { + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + } + } + }, + "rollup-plugin-version-injector": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-version-injector/-/rollup-plugin-version-injector-1.3.3.tgz", + "integrity": "sha512-+Rrf0xIFHkwFGuMfphVlAOtd9FlhHFh3vrDwamJ6+YR3IxebRHGVT879qwWzZ1CpWMCLlngb2MmHW5wC5EJqvg==", + "requires": { + "chalk": "^4.1.0", + "dateformat": "^4.2.1", + "lodash": "^4.17.20" + }, + "dependencies": { + "dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==" + } + } + }, "run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -19378,14 +20124,12 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "saxes": { "version": "5.0.1", @@ -19422,6 +20166,14 @@ "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", "dev": true }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "requires": { + "randombytes": "^2.1.0" + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -19539,14 +20291,12 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -19748,7 +20498,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -19766,8 +20515,7 @@ "supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, "symbol-tree": { "version": "3.2.4", @@ -19862,6 +20610,29 @@ "supports-hyperlinks": "^2.0.0" } }, + "terser": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz", + "integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==", + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==" + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + } + } + }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -20069,8 +20840,7 @@ "tslib": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "tsutils": { "version": "3.21.0", @@ -20181,8 +20951,7 @@ "typescript": { "version": "4.7.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", - "dev": true + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==" }, "uglify-js": { "version": "3.17.2", diff --git a/packages/server/package-lock.json b/packages/server/package-lock.json new file mode 100644 index 00000000..4cda2751 --- /dev/null +++ b/packages/server/package-lock.json @@ -0,0 +1,695 @@ +{ + "name": "@simplewebauthn/server", + "version": "6.3.0-alpha.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@simplewebauthn/server", + "version": "6.3.0-alpha.0", + "license": "MIT", + "dependencies": { + "@noble/ed25519": "^1.6.1", + "@peculiar/asn1-android": "^2.1.7", + "@peculiar/asn1-schema": "^2.1.7", + "@peculiar/asn1-x509": "^2.1.7", + "@simplewebauthn/typescript-types": "^6.0.0", + "base64url": "^3.0.1", + "cbor": "^5.1.0", + "debug": "^4.3.2", + "jsrsasign": "^10.4.0", + "jwk-to-pem": "^2.0.4", + "node-fetch": "^2.6.0" + }, + "devDependencies": { + "@types/cbor": "^5.0.1", + "@types/debug": "^4.1.7", + "@types/jsrsasign": "^8.0.13", + "@types/jwk-to-pem": "^2.0.1", + "@types/node-fetch": "^2.5.12" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "../typescript-types": { + "name": "@simplewebauthn/typescript-types", + "version": "6.0.0", + "license": "MIT" + }, + "node_modules/@noble/ed25519": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.0.tgz", + "integrity": "sha512-LeAxFK0+181zQOhOUuKE8Jnd3duzYhDNd3iCLxpmzA5K+e4I1FdbrK3Ot0ZHBwZMeRD/6EojyUfTbpHZ+hkQHg==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@peculiar/asn1-android": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.3.0.tgz", + "integrity": "sha512-ooQ6zRxSXcJ7IW6y7rd3DztgGwzJ3Esq28ideiVwj1hmkPHwqhoRvgHoeddOUQds9GHiwDN5uM/fufnTOxrG2A==", + "dependencies": { + "@peculiar/asn1-schema": "^2.3.0", + "asn1js": "^3.0.5", + "tslib": "^2.4.0" + } + }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.0.tgz", + "integrity": "sha512-DtNLAG4vmDrdSJFPe7rypkcj597chNQL7u+2dBtYo5mh7VW2+im6ke+O0NVr8W1f4re4C3F71LhoMb0Yxqa48Q==", + "dependencies": { + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@peculiar/asn1-x509": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.3.0.tgz", + "integrity": "sha512-iDRNPHAx/HLwR9wN5xaHDPifpdSW/bquu+zo/kQXurnxg6KQ1jcZw+4a63uTvrzyGU/hHzDqjalG/sQvV02lAw==", + "dependencies": { + "@peculiar/asn1-schema": "^2.3.0", + "asn1js": "^3.0.5", + "ipaddr.js": "^2.0.1", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@simplewebauthn/typescript-types": { + "resolved": "../typescript-types", + "link": true + }, + "node_modules/@types/cbor": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/cbor/-/cbor-5.0.1.tgz", + "integrity": "sha512-zVqJy2KzusZPLOgyGJDnOIbu3DxIGGqxYbEwtEEe4Z+la8jwIhOyb+GMrlHafs5tvKruwf8f8qOYP6zTvse/pw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "dev": true, + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/jsrsasign": { + "version": "8.0.13", + "resolved": "https://registry.npmjs.org/@types/jsrsasign/-/jsrsasign-8.0.13.tgz", + "integrity": "sha512-+0Ij59D6NXP48KkeLhPXeQKOyLjvA9CD7zacc0Svy2IWHdl62BmDeTvGSIwKaGZSoamLJOo+on1AG/wPRLsd7A==", + "dev": true + }, + "node_modules/@types/jwk-to-pem": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/jwk-to-pem/-/jwk-to-pem-2.0.1.tgz", + "integrity": "sha512-QXmRPhR/LPzvXBHTPfG2BBfMTkNLUD7NyRcPft8m5xFCeANa1BZyLgT0Gw+OxdWx6i1WCpT27EqyggP4UUHMrA==", + "dev": true + }, + "node_modules/@types/ms": { + "version": "0.7.31", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "17.0.34", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node-fetch": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", + "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1js": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", + "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", + "dependencies": { + "pvtsutils": "^1.3.2", + "pvutils": "^1.1.3", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/bignumber.js": { + "version": "9.0.2", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/bn.js": { + "version": "4.12.0", + "license": "MIT" + }, + "node_modules/brorand": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/cbor": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", + "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", + "dependencies": { + "bignumber.js": "^9.0.1", + "nofilter": "^1.0.4" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/elliptic": { + "version": "6.5.4", + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "2.0.1", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/jsrsasign": { + "version": "10.5.27", + "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.5.27.tgz", + "integrity": "sha512-1F4LmDeJZHYwoVvB44jEo2uZL3XuwYNzXCDOu53Ui6vqofGQ/gCYDmaxfVZtN0TGd92UKXr/BONcfrPonUIcQQ==", + "funding": { + "url": "https://github.com/kjur/jsrsasign#donations" + } + }, + "node_modules/jwk-to-pem": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz", + "integrity": "sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==", + "dependencies": { + "asn1.js": "^5.3.0", + "elliptic": "^6.5.4", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/nofilter": { + "version": "1.0.4", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pvtsutils": { + "version": "1.3.2", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/pvutils": { + "version": "1.1.3", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/tr46": { + "version": "0.0.3", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.4.0", + "license": "0BSD" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + }, + "dependencies": { + "@noble/ed25519": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.0.tgz", + "integrity": "sha512-LeAxFK0+181zQOhOUuKE8Jnd3duzYhDNd3iCLxpmzA5K+e4I1FdbrK3Ot0ZHBwZMeRD/6EojyUfTbpHZ+hkQHg==" + }, + "@peculiar/asn1-android": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.3.0.tgz", + "integrity": "sha512-ooQ6zRxSXcJ7IW6y7rd3DztgGwzJ3Esq28ideiVwj1hmkPHwqhoRvgHoeddOUQds9GHiwDN5uM/fufnTOxrG2A==", + "requires": { + "@peculiar/asn1-schema": "^2.3.0", + "asn1js": "^3.0.5", + "tslib": "^2.4.0" + } + }, + "@peculiar/asn1-schema": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.0.tgz", + "integrity": "sha512-DtNLAG4vmDrdSJFPe7rypkcj597chNQL7u+2dBtYo5mh7VW2+im6ke+O0NVr8W1f4re4C3F71LhoMb0Yxqa48Q==", + "requires": { + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, + "@peculiar/asn1-x509": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.3.0.tgz", + "integrity": "sha512-iDRNPHAx/HLwR9wN5xaHDPifpdSW/bquu+zo/kQXurnxg6KQ1jcZw+4a63uTvrzyGU/hHzDqjalG/sQvV02lAw==", + "requires": { + "@peculiar/asn1-schema": "^2.3.0", + "asn1js": "^3.0.5", + "ipaddr.js": "^2.0.1", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, + "@simplewebauthn/typescript-types": { + "version": "file:../typescript-types" + }, + "@types/cbor": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/cbor/-/cbor-5.0.1.tgz", + "integrity": "sha512-zVqJy2KzusZPLOgyGJDnOIbu3DxIGGqxYbEwtEEe4Z+la8jwIhOyb+GMrlHafs5tvKruwf8f8qOYP6zTvse/pw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "dev": true, + "requires": { + "@types/ms": "*" + } + }, + "@types/jsrsasign": { + "version": "8.0.13", + "resolved": "https://registry.npmjs.org/@types/jsrsasign/-/jsrsasign-8.0.13.tgz", + "integrity": "sha512-+0Ij59D6NXP48KkeLhPXeQKOyLjvA9CD7zacc0Svy2IWHdl62BmDeTvGSIwKaGZSoamLJOo+on1AG/wPRLsd7A==", + "dev": true + }, + "@types/jwk-to-pem": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/jwk-to-pem/-/jwk-to-pem-2.0.1.tgz", + "integrity": "sha512-QXmRPhR/LPzvXBHTPfG2BBfMTkNLUD7NyRcPft8m5xFCeANa1BZyLgT0Gw+OxdWx6i1WCpT27EqyggP4UUHMrA==", + "dev": true + }, + "@types/ms": { + "version": "0.7.31", + "dev": true + }, + "@types/node": { + "version": "17.0.34", + "dev": true + }, + "@types/node-fetch": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", + "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", + "dev": true, + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "asn1.js": { + "version": "5.4.1", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "asn1js": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", + "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", + "requires": { + "pvtsutils": "^1.3.2", + "pvutils": "^1.1.3", + "tslib": "^2.4.0" + } + }, + "asynckit": { + "version": "0.4.0", + "dev": true + }, + "base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" + }, + "bignumber.js": { + "version": "9.0.2" + }, + "bn.js": { + "version": "4.12.0" + }, + "brorand": { + "version": "1.1.0" + }, + "cbor": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", + "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", + "requires": { + "bignumber.js": "^9.0.1", + "nofilter": "^1.0.4" + } + }, + "combined-stream": { + "version": "1.0.8", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "delayed-stream": { + "version": "1.0.0", + "dev": true + }, + "elliptic": { + "version": "6.5.4", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "form-data": { + "version": "3.0.1", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "hash.js": { + "version": "1.1.7", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "inherits": { + "version": "2.0.4" + }, + "ipaddr.js": { + "version": "2.0.1" + }, + "jsrsasign": { + "version": "10.5.27", + "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.5.27.tgz", + "integrity": "sha512-1F4LmDeJZHYwoVvB44jEo2uZL3XuwYNzXCDOu53Ui6vqofGQ/gCYDmaxfVZtN0TGd92UKXr/BONcfrPonUIcQQ==" + }, + "jwk-to-pem": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz", + "integrity": "sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==", + "requires": { + "asn1.js": "^5.3.0", + "elliptic": "^6.5.4", + "safe-buffer": "^5.0.1" + } + }, + "mime-db": { + "version": "1.52.0", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1" + }, + "ms": { + "version": "2.1.2" + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "nofilter": { + "version": "1.0.4" + }, + "pvtsutils": { + "version": "1.3.2", + "requires": { + "tslib": "^2.4.0" + } + }, + "pvutils": { + "version": "1.1.3" + }, + "safe-buffer": { + "version": "5.2.1" + }, + "safer-buffer": { + "version": "2.1.2" + }, + "tr46": { + "version": "0.0.3" + }, + "tslib": { + "version": "2.4.0" + }, + "webidl-conversions": { + "version": "3.0.1" + }, + "whatwg-url": { + "version": "5.0.0", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } +} diff --git a/packages/server/src/authentication/generateAuthenticationOptions.ts b/packages/server/src/authentication/generateAuthenticationOptions.ts index b80473ea..54275f7a 100644 --- a/packages/server/src/authentication/generateAuthenticationOptions.ts +++ b/packages/server/src/authentication/generateAuthenticationOptions.ts @@ -1,5 +1,5 @@ import type { - AuthenticationExtensionsClientInputs, + AuthenticationExtensionsClientInputsFuture, PublicKeyCredentialRequestOptionsJSON, PublicKeyCredentialDescriptorFuture, UserVerificationRequirement, @@ -13,7 +13,7 @@ export type GenerateAuthenticationOptionsOpts = { challenge?: string | Buffer; timeout?: number; userVerification?: UserVerificationRequirement; - extensions?: AuthenticationExtensionsClientInputs; + extensions?: AuthenticationExtensionsClientInputsFuture; rpID?: string; }; diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts index 30fb09ad..c883d652 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts @@ -8,7 +8,11 @@ import { AuthenticatorDevice, AuthenticationCredentialJSON, } from '@simplewebauthn/typescript-types'; -import { DevicePublicKeyAuthenticatorOutput } from '../helpers/decodeAuthenticatorExtensions'; +import { + DevicePublicKeyAuthenticatorOutput, + decodeDevicePubKey, + decodeDevicePubKeyAuthenticatorOutput +} from '../extensions/devicePublicKey/decodeDevicePubKey'; let mockDecodeClientData: jest.SpyInstance; let mockParseAuthData: jest.SpyInstance; @@ -312,42 +316,46 @@ test('should fail verification if custom challenge verifier returns false', asyn ).rejects.toThrow(/custom challenge verifier returned false/i); }); -const devicePubKey: DevicePublicKeyAuthenticatorOutput = { - "dpk": Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'), - "sig": Buffer.from('3045022100BC6DD9AF5E47BB3AB82731299EAE82A779189E4E416E3A0E37A3BA64C38F991202205671EFAC0E8CD6DE1D3640CE7E4E89D3A97E0517B603D8AC28F23E4E1F74E639', 'hex'), - "nonce": Buffer.from('', 'hex'), - "scope": Buffer.from('00', 'hex'), - "aaguid": Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), +const authenticationCredentialWithDevicePublicKey: AuthenticationCredentialJSON = { + response: { + clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiS05aUmtPRU5KY1dCTzZHX0VjcE1GS2FWRDlham1xNExsZDZJMllJc1c3QSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', + authenticatorData: 'DXX8xWP9p3nbLjQ-6kiYiHWLeFSdSTpP2-oc2WqjHMSdAAAAAKFsZGV2aWNlUHViS2V5WIymY2Rwa1hNpQECAyYgASFYIE3BmJ0MLxBA0B9-wVrFQrFNtUvF6l1X7X9rOD67T6uwIlggW2G32XUvyDaGpA6jyiacF319GPZvInOfUlCqenX2hVtjZm10ZG5vbmVlbm9uY2VAZXNjb3BlAGZhYWd1aWRQAAAAAAAAAAAAAAAAAAAAAGdhdHRTdG10oA==', + signature: 'MEUCIF1LvdGHiW5aq25ZrNVUeZOm7pcS_9a172pkO2C6ILE1AiEA8NYg-ZzOgt1pN0Bqv02t7lWCSMn_IPpvKHdT5Mjv75E=', + userHandle: 'b2FPajFxcmM4MWo3QkFFel9RN2lEakh5RVNlU2RLNDF0Sl92eHpQYWV5UQ==', + }, + id: 'BxYpj3rs5WGW8UVnXsmMzg', + rawId: 'BxYpj3rs5WGW8UVnXsmMzg', + type: 'public-key', + clientExtensionResults: { + devicePubKey: { + 'authenticatorOutput': 'pmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=', + 'signature': 'MEQCIAdwrIjLt7ULTU5OzpnhzvbWJ3srVLoOCYs72Hlw6ugoAiAFl4_jfJJv89cM5qSx8lI_pIXLRIy6lO9N3O8SUjyNKQ==', + } + } }; -const sameDevicePubKey = devicePubKey; + +if (!authenticationCredentialWithDevicePublicKey?.clientExtensionResults?.devicePubKey) { + throw new Error('This exception will not happen.'); +} + + +const encodedDevicePubKey = decodeDevicePubKey(authenticationCredentialWithDevicePublicKey.clientExtensionResults.devicePubKey); +const sameDevicePubKey = decodeDevicePubKeyAuthenticatorOutput(encodedDevicePubKey.authenticatorOutput); const differentDevicePubKey: DevicePublicKeyAuthenticatorOutput = { "dpk": Buffer.from('A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', 'hex'), - "sig": Buffer.from('3045022049526CD28AEF6B4E621A7D5936D2B504952FC0AE2313A4F0357AAFFFAEA964740221009D513ACAEFB0B32C765AAE6FEBA8C294685EFF63FF1CBF11ECF2107AF4FEB8F8', 'hex'), "nonce": Buffer.from('', 'hex'), - "scope": Buffer.from('00', 'hex'), - "aaguid": Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), -}; -const authenticationCredentialWithDevicePublicKey: AuthenticationCredentialJSON = { - response: { - "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoicTh1SVR0d0czMkhUU3RmdlVxVTcwWXNGNFJfS1A4WnZEYkVESVpZekNDdyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9", - "authenticatorData": "DXX8xWP9p3nbLjQ-6kiYiHWLeFSdSTpP2-oc2WqjHMSFAAAAAKFsZGV2aWNlUHViS2V5pWNkcGtYTaUBAgMmIAEhWCDt6tP9NXacI9NA3cGDCn_yDnNV8p0cdaoNwrasGC6n0yJYIDRR3JmSr5RoJbRBlF_J0TThe3OqX-qVgDUefJP102UTY3NpZ1hHMEUCIQC8bdmvXke7OrgnMSmeroKneRieTkFuOg43o7pkw4-ZEgIgVnHvrA6M1t4dNkDOfk6J06l-BRe2A9isKPI-Th905jllbm9uY2VAZXNjb3BlQQBmYWFndWlkULk_2WHy5kYvsSKCACJH3ng=", - "signature": "MEUCIEXJbR9-0cpcUdGAJi25Qf3z22lnCidx3box2b0bWKhwAiEAkp5zCbVbN2CEtIyezQEa9SOG62xm8YHdE1G5qov64j8=", - "userHandle": "b2FPajFxcmM4MWo3QkFFel9RN2lEakh5RVNlU2RLNDF0Sl92eHpQYWV5UQ==" - }, - id: "cxjDB1h5nG6jpQW3EeeZNA", - rawId: "cxjDB1h5nG6jpQW3EeeZNA", - type: "public-key", - clientExtensionResults: {} + "scope": 0, + "aaguid": Buffer.from('00000000000000000000000000000000', 'hex'), }; -const credentialID = base64url.toBuffer('cxjDB1h5nG6jpQW3EeeZNA'); -const credentialPublicKey = base64url.toBuffer('pQECAyYgASFYIIukb9t-EtGUOa2t6YiJEAgz7GyqBN4DFTCzkcMiUGqIIlggmm6GzBPSzP9IYJnX-89R_zmKl6-qQSeQ2qomEC6Cr30'); +const credentialID = base64url.toBuffer('BxYpj3rs5WGW8UVnXsmMzg'); +const credentialPublicKey = base64url.toBuffer('pQECAyYgASFYIPLEylOIRiI7z7q6zuYjWB9TcOj9yNwmawogQJ4ZKpNAIlggd9ZqIjd30p1tIU6A8ue5wEZl9q/AsKR/leaHFZ/bwWk='); test('should throw if multiple device public key matches', async () => { await expect(verifyAuthenticationResponse({ credential: authenticationCredentialWithDevicePublicKey, expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', expectedRPID: 'try-webauthn.appspot.com', - expectedChallenge: 'q8uITtwG32HTStfvUqU70YsF4R_KP8ZvDbEDIZYzCCw', + expectedChallenge: 'KNZRkOENJcWBO6G_EcpMFKaVD9ajmq4Lld6I2YIsW7A', authenticator: { credentialID, credentialPublicKey, @@ -362,14 +370,14 @@ test('should return the new device public key when no device public key matches' credential: authenticationCredentialWithDevicePublicKey, expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', expectedRPID: 'try-webauthn.appspot.com', - expectedChallenge: 'q8uITtwG32HTStfvUqU70YsF4R_KP8ZvDbEDIZYzCCw', + expectedChallenge: 'KNZRkOENJcWBO6G_EcpMFKaVD9ajmq4Lld6I2YIsW7A', authenticator: { credentialID, credentialPublicKey, counter: 0, }, userDevicePublicKeys: [differentDevicePubKey, differentDevicePubKey], - }).then(verification => verification.authenticationInfo.extensionOutputs?.devicePubKeyToStore)).resolves.toMatchObject(devicePubKey); + }).then(verification => verification.authenticationInfo.extensionOutputs?.devicePubKeyToStore)).resolves.toMatchObject(sameDevicePubKey); }); test('should return undefined when one device public key matches', async () => { @@ -377,7 +385,7 @@ test('should return undefined when one device public key matches', async () => { credential: authenticationCredentialWithDevicePublicKey, expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', expectedRPID: 'try-webauthn.appspot.com', - expectedChallenge: 'q8uITtwG32HTStfvUqU70YsF4R_KP8ZvDbEDIZYzCCw', + expectedChallenge: 'KNZRkOENJcWBO6G_EcpMFKaVD9ajmq4Lld6I2YIsW7A', authenticator: { credentialID, credentialPublicKey, diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.ts b/packages/server/src/authentication/verifyAuthenticationResponse.ts index 6c76e535..124ae114 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.ts @@ -12,10 +12,16 @@ import { verifySignature } from '../helpers/verifySignature'; import { parseAuthenticatorData } from '../helpers/parseAuthenticatorData'; import { isBase64URLString } from '../helpers/isBase64URLString'; import { parseBackupFlags } from '../helpers/parseBackupFlags'; -import { DevicePublicKeyAuthenticatorOutput } from '../helpers/decodeAuthenticatorExtensions'; -import { verifyDevicePublicKeySignature, VerifyDevicePublicKeySignatureOpts } from '../extensions/devicePublicKey/verifyDevicePublicKeySignature'; +import { + verifyDevicePublicKeySignature, + VerifyDevicePublicKeySignatureOpts +} from '../extensions/devicePublicKey/verifyDevicePublicKeySignature'; +import { + DevicePublicKeyAuthenticatorOutput, + decodeDevicePubKey, + decodeDevicePubKeyAuthenticatorOutput +} from '../extensions/devicePublicKey/decodeDevicePubKey'; import { isRecognizedDevice } from '../extensions/devicePublicKey/isRecognizedDevice'; -import { decodeDevicePubKey, decodeDevicePubKeyAuthenticatorOutput } from 'extensions/devicePublicKey/decodeDevicePubKey'; export type VerifyAuthenticationResponseOpts = { credential: AuthenticationCredentialJSON; @@ -212,32 +218,21 @@ export async function verifyAuthenticationResponse( // DevicePublicKey sample currently provides the data through authenticator // extension results. if (clientExtensionResults.devicePubKey) { - const { devicePubKey: encodedDevicePubKey } = clientExtensionResults; - const devicePubKey = decodeDevicePubKey(encodedDevicePubKey); - if (!devicePubKey) { - throw new Error('No device public key was provided in the client extension results.'); - } + const devicePubKey = decodeDevicePubKey(clientExtensionResults.devicePubKey); const { authenticatorOutput: encodedAuthenticatorOutput, signature } = devicePubKey; - if (!signature) { - throw new Error('Device public key signature is missing.'); - } - - const authenticatorOutput = decodeDevicePubKeyAuthenticatorOutput(encodedAuthenticatorOutput); - if (!authenticatorOutput) { - throw new Error('Device public key authenticator output is corrupt.'); - } + const dpkAuthOutput = decodeDevicePubKeyAuthenticatorOutput(encodedAuthenticatorOutput); const dpkOptions: VerifyDevicePublicKeySignatureOpts = { credential, - authenticatorOutput, + authenticatorOutput: dpkAuthOutput, signature, - }; + } const result = await verifyDevicePublicKeySignature(dpkOptions); if (!result) { throw new Error('Invalid device public key signature.'); } - const devicePubKeyToStore = await isRecognizedDevice(devicePubKey, userDevicePublicKeys); + const devicePubKeyToStore = await isRecognizedDevice(dpkAuthOutput, userDevicePublicKeys); extensionOutputs.devicePubKeyToStore = devicePubKeyToStore; } } diff --git a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts index b015ffa5..759afd7f 100644 --- a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts +++ b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts @@ -1,5 +1,5 @@ import { decodeCborFirst } from '../../helpers/decodeCbor'; -import { Base64URLString, AuthenticationExtensionsDevicePublicKeyOutputs } from '@simplewebauthn/typescript-types'; +import { AuthenticationExtensionsDevicePublicKeyOutputs, AuthenticationExtensionsDevicePublicKeyOutputsJSON } from '@simplewebauthn/typescript-types'; import { AttestationFormat, AttestationStatement } from '../../helpers/decodeAttestationObject'; import base64url from 'base64url'; @@ -9,23 +9,42 @@ import base64url from 'base64url'; * @param devicePubKey Client Extension's device public key data buffer */ export function decodeDevicePubKey( - devicePubKey: Base64URLString, -): AuthenticationExtensionsDevicePublicKeyOutputs | undefined { - let toCBOR: AuthenticationExtensionsDevicePublicKeyOutputs | undefined; + devicePubKeyJSON: AuthenticationExtensionsDevicePublicKeyOutputsJSON, +): AuthenticationExtensionsDevicePublicKeyOutputs { + const { + authenticatorOutput: base64AuthenticatorOutput, + signature: base64Signature, + } = devicePubKeyJSON; + + let authenticatorOutput: Buffer | undefined; + let signature: Buffer | undefined; + try { - const base64DevicePubKey = base64url.toBuffer(devicePubKey); - toCBOR = decodeCborFirst(base64DevicePubKey); + authenticatorOutput = base64url.toBuffer(base64AuthenticatorOutput); + if (!authenticatorOutput) { + throw new Error ('authenticatorOutput is missing'); + } + + signature = base64url.toBuffer(base64Signature); + if (!signature) { + throw new Error('signature is missing'); + } } catch (err) { const _err = err as Error; throw new Error(`Error decoding device public key: ${_err.message}`); } - return toCBOR; + + const devicePubKey: AuthenticationExtensionsDevicePublicKeyOutputs = { + authenticatorOutput, + signature, + } + return devicePubKey; } export function decodeDevicePubKeyAuthenticatorOutput( authenticatorOutput: Buffer, -): DevicePublicKeyAuthenticatorOutput | undefined { - let toCBOR: DevicePublicKeyAuthenticatorOutput | undefined; +): DevicePublicKeyAuthenticatorOutput { + let toCBOR: DevicePublicKeyAuthenticatorOutput; try { toCBOR = decodeCborFirst(authenticatorOutput); } catch (err) { @@ -38,7 +57,7 @@ export function decodeDevicePubKeyAuthenticatorOutput( export type DevicePublicKeyAuthenticatorOutput = { aaguid: Buffer; dpk: Buffer; - scope: Buffer; + scope: number; nonce?: Buffer; fmt?: AttestationFormat; attStmt?: AttestationStatement; diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts index 88993dd2..e661364d 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts @@ -1,21 +1,18 @@ -import { checkAttStmtBinaryEquality, isRecognizedDevice } from './isRecognizedDevice'; -import { AttestationStatement } from "../../helpers/decodeAttestationObject"; -import { DevicePublicKeyAuthenticatorOutput } from '../../helpers/decodeAuthenticatorExtensions'; +import { isRecognizedDevice } from './isRecognizedDevice'; +import { DevicePublicKeyAuthenticatorOutput } from './decodeDevicePubKey'; const devicePubKey: DevicePublicKeyAuthenticatorOutput = { "dpk": Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'), - "sig": Buffer.from('3045022100BC6DD9AF5E47BB3AB82731299EAE82A779189E4E416E3A0E37A3BA64C38F991202205671EFAC0E8CD6DE1D3640CE7E4E89D3A97E0517B603D8AC28F23E4E1F74E639', 'hex'), "nonce": Buffer.from('', 'hex'), - "scope": Buffer.from('00', 'hex'), + "scope": 0, "aaguid": Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), } const sameDevicePubKey = devicePubKey; const differentDevicePubKey: DevicePublicKeyAuthenticatorOutput = { "dpk": Buffer.from('A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', 'hex'), - "sig": Buffer.from('3045022049526CD28AEF6B4E621A7D5936D2B504952FC0AE2313A4F0357AAFFFAEA964740221009D513ACAEFB0B32C765AAE6FEBA8C294685EFF63FF1CBF11ECF2107AF4FEB8F8', 'hex'), "nonce": Buffer.from('', 'hex'), - "scope": Buffer.from('00', 'hex'), + "scope": 0, "aaguid": Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), }; diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts index 4ffa520f..9bcaec30 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts @@ -1,5 +1,5 @@ -import { AttestationStatement } from "helpers"; -import { DevicePublicKeyAuthenticatorOutput } from "../../helpers/decodeAuthenticatorExtensions"; +import { AttestationStatement } from "../../helpers/decodeAttestationObject"; +import { DevicePublicKeyAuthenticatorOutput } from './decodeDevicePubKey'; import { verifyDevicePublicKeyAttestation } from "./verifyDevicePublicKeyAttestation"; /** @@ -30,7 +30,7 @@ export async function isRecognizedDevice( if (!responseDevicePublicKey.dpk.equals(userDPK.dpk)) { return false; } - if (!responseDevicePublicKey.scope.equals(userDPK.scope)) { + if (responseDevicePublicKey.scope !== userDPK.scope) { return false; } return true; @@ -92,6 +92,7 @@ export async function isRecognizedDevice( } if (!dpksAreBinaryEqual) { + // TODO: } } // This is a valid and a known device. diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts index cdf7c135..ae268350 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts @@ -1,4 +1,4 @@ -import { DevicePublicKeyAuthenticatorOutput } from "../../helpers/decodeAuthenticatorExtensions"; +import { DevicePublicKeyAuthenticatorOutput } from "./decodeDevicePubKey"; import { AuthenticationCredentialJSON, RegistrationCredentialJSON, diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.test.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.test.ts index 9e5b3d3a..9bb30dad 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.test.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.test.ts @@ -1,54 +1,74 @@ -import { AuthenticationCredentialJSON, AuthenticatorAssertionResponseJSON, AuthenticatorAttestationResponseJSON, RegistrationCredentialJSON } from '@simplewebauthn/typescript-types'; -import { verifyDevicePublicKeySignature } from './verifyDevicePublicKeySignature'; +import { AuthenticationCredentialJSON, RegistrationCredentialJSON } from '@simplewebauthn/typescript-types'; +import { decodeDevicePubKey, decodeDevicePubKeyAuthenticatorOutput } from './decodeDevicePubKey'; +import { verifyDevicePublicKeySignature, VerifyDevicePublicKeySignatureOpts } from './verifyDevicePublicKeySignature'; it("should verify a registration response's device public key signature", async () => { const credential: RegistrationCredentialJSON = { response: { - clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiNFF3dmdUVjhlaTF5TzYyaDF2bVFNWFM2SDZ3UGc0YWt2eDNKcF9VakF3cyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', - attestationObject: 'o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVkBaQ11_MVj_ad52y40PupImIh1i3hUnUk6T9vqHNlqoxzExQAAAAAAAAAAAAAAAAAAAAAAAAAAABBzGMMHWHmcbqOlBbcR55k0pQECAyYgASFYIIukb9t-EtGUOa2t6YiJEAgz7GyqBN4DFTCzkcMiUGqIIlggmm6GzBPSzP9IYJnX-89R_zmKl6-qQSeQ2qomEC6Cr32hbGRldmljZVB1YktleaVjZHBrWE2lAQIDJiABIVgg7erT_TV2nCPTQN3Bgwp_8g5zVfKdHHWqDcK2rBgup9MiWCA0UdyZkq-UaCW0QZRfydE04Xtzql_qlYA1HnyT9dNlE2NzaWdYRjBEAiALHwldj84eCsg9f0fHD9hylpUK8N_TGOBKBQPoNvfWjQIgChIUfdbO1HBavxbZGQxIt4v23FqFLB2nzwip-avJ6etlbm9uY2VAZXNjb3BlQQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAAA=', + clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiNkM0QUptNmJyTVJwSF9JZVhDVmtHTTUydnVwTy14Y1huNldlcWIyVjJtTSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', + attestationObject: 'o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVkBMA11_MVj_ad52y40PupImIh1i3hUnUk6T9vqHNlqoxzE3QAAAAAAAAAAAAAAAAAAAAAAAAAAABAHFimPeuzlYZbxRWdeyYzOpQECAyYgASFYIPLEylOIRiI7z7q6zuYjWB9TcOj9yNwmawogQJ4ZKpNAIlggd9ZqIjd30p1tIU6A8ue5wEZl9q_AsKR_leaHFZ_bwWmhbGRldmljZVB1YktleViMpmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=', }, - id: 'cxjDB1h5nG6jpQW3EeeZNA', - rawId: 'cxjDB1h5nG6jpQW3EeeZNA', + id: 'BxYpj3rs5WGW8UVnXsmMzg', + rawId: 'BxYpj3rs5WGW8UVnXsmMzg', type: 'public-key', transports: [], - clientExtensionResults: {} + clientExtensionResults: { + devicePubKey: { + authenticatorOutput: 'pmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=', + signature: 'MEUCIQDTf2ImngEOi3qHws6gxf6CpquI97oDIl8m_4T2xQO-YwIgdWN7elqNuU-yMZtGpy8hQtL_E-qmZ1_rM2u2nhXYw7A=', + } + } }; - const devicePubKey = { - aaguid: Buffer.from('00000000000000000000000000000000', 'hex'), - dpk: Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'), - sig: Buffer.from('304402200B1F095D8FCE1E0AC83D7F47C70FD87296950AF0DFD318E04A0503E836F7D68D02200A12147DD6CED4705ABF16D9190C48B78BF6DC5A852C1DA7CF08A9F9ABC9E9EB', 'hex'), - nonce: Buffer.from('', 'hex'), - scope: Buffer.from('00', 'hex') + if (!credential.clientExtensionResults.devicePubKey) { + throw new Error('This exception will not happen.'); } - const signature = devicePubKey.sig; - - const result = await verifyDevicePublicKeySignature({ credential, devicePubKey, signature }); + + const devicePubKey = decodeDevicePubKey(credential.clientExtensionResults.devicePubKey); + const { authenticatorOutput: encodedAuthenticatorOutput, signature } = devicePubKey; + const dpkAuthOutput = decodeDevicePubKeyAuthenticatorOutput(encodedAuthenticatorOutput); + + const dpkOpts: VerifyDevicePublicKeySignatureOpts = { + credential, + authenticatorOutput: dpkAuthOutput, + signature, + } + const result = await verifyDevicePublicKeySignature(dpkOpts); expect(result).toEqual(true); }); it("should verify an authentication response's device public key signature", async () => { - const credential = { + const credential: AuthenticationCredentialJSON = { response: { - clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoicTh1SVR0d0czMkhUU3RmdlVxVTcwWXNGNFJfS1A4WnZEYkVESVpZekNDdyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', - authenticatorData: 'DXX8xWP9p3nbLjQ-6kiYiHWLeFSdSTpP2-oc2WqjHMSFAAAAAKFsZGV2aWNlUHViS2V5pWNkcGtYTaUBAgMmIAEhWCDt6tP9NXacI9NA3cGDCn_yDnNV8p0cdaoNwrasGC6n0yJYIDRR3JmSr5RoJbRBlF_J0TThe3OqX-qVgDUefJP102UTY3NpZ1hHMEUCIQC8bdmvXke7OrgnMSmeroKneRieTkFuOg43o7pkw4-ZEgIgVnHvrA6M1t4dNkDOfk6J06l-BRe2A9isKPI-Th905jllbm9uY2VAZXNjb3BlQQBmYWFndWlkULk_2WHy5kYvsSKCACJH3ng=', - signature: 'MEUCIEXJbR9-0cpcUdGAJi25Qf3z22lnCidx3box2b0bWKhwAiEAkp5zCbVbN2CEtIyezQEa9SOG62xm8YHdE1G5qov64j8=', + clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiS05aUmtPRU5KY1dCTzZHX0VjcE1GS2FWRDlham1xNExsZDZJMllJc1c3QSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', + authenticatorData: 'DXX8xWP9p3nbLjQ-6kiYiHWLeFSdSTpP2-oc2WqjHMSdAAAAAKFsZGV2aWNlUHViS2V5WIymY2Rwa1hNpQECAyYgASFYIE3BmJ0MLxBA0B9-wVrFQrFNtUvF6l1X7X9rOD67T6uwIlggW2G32XUvyDaGpA6jyiacF319GPZvInOfUlCqenX2hVtjZm10ZG5vbmVlbm9uY2VAZXNjb3BlAGZhYWd1aWRQAAAAAAAAAAAAAAAAAAAAAGdhdHRTdG10oA==', + signature: 'MEUCIF1LvdGHiW5aq25ZrNVUeZOm7pcS_9a172pkO2C6ILE1AiEA8NYg-ZzOgt1pN0Bqv02t7lWCSMn_IPpvKHdT5Mjv75E=, userHandle=b2FPajFxcmM4MWo3QkFFel9RN2lEakh5RVNlU2RLNDF0Sl92eHpQYWV5UQ==', userHandle: 'b2FPajFxcmM4MWo3QkFFel9RN2lEakh5RVNlU2RLNDF0Sl92eHpQYWV5UQ==', }, - id: 'cxjDB1h5nG6jpQW3EeeZNA', - rawId: 'cxjDB1h5nG6jpQW3EeeZNA', + id: 'BxYpj3rs5WGW8UVnXsmMzg', + rawId: 'BxYpj3rs5WGW8UVnXsmMzg', type: 'public-key', - } as AuthenticationCredentialJSON; - - const devicePubKey = { - aaguid: Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), - dpk: Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'), - sig: Buffer.from('3045022100BC6DD9AF5E47BB3AB82731299EAE82A779189E4E416E3A0E37A3BA64C38F991202205671EFAC0E8CD6DE1D3640CE7E4E89D3A97E0517B603D8AC28F23E4E1F74E639', 'hex'), - nonce: Buffer.from('', 'hex'), - scope: Buffer.from('00', 'hex') + clientExtensionResults: { + devicePubKey: { + 'authenticatorOutput': 'pmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=', + 'signature': 'MEQCIAdwrIjLt7ULTU5OzpnhzvbWJ3srVLoOCYs72Hlw6ugoAiAFl4_jfJJv89cM5qSx8lI_pIXLRIy6lO9N3O8SUjyNKQ==', + } + } + }; + + if (!credential.clientExtensionResults.devicePubKey) { + throw new Error('This exception will not happen.'); + } + + const devicePubKey = decodeDevicePubKey(credential.clientExtensionResults.devicePubKey); + const {authenticatorOutput: encodedAuthenticatorOutput, signature } = devicePubKey; + const dpkAuthOutput = decodeDevicePubKeyAuthenticatorOutput(encodedAuthenticatorOutput); + + const dpkOpts: VerifyDevicePublicKeySignatureOpts = { + credential, + authenticatorOutput: dpkAuthOutput, + signature, } - const signature = devicePubKey.sig; - - const result = await verifyDevicePublicKeySignature({ credential, devicePubKey, signature }); + const result = await verifyDevicePublicKeySignature(dpkOpts); expect(result).toEqual(true); }); diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts index 9a857028..ad40b694 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts @@ -1,7 +1,6 @@ import base64url from "base64url"; import { toHash } from "../../helpers/toHash"; import { verifySignature } from "../../helpers/verifySignature"; -import { DevicePublicKeyAuthenticatorOutput } from "../../helpers/decodeAuthenticatorExtensions"; import { AuthenticationCredentialJSON, AuthenticatorAssertionResponseJSON, @@ -9,6 +8,7 @@ import { AuthenticatorAttestationResponseJSON } from "@simplewebauthn/typescript-types"; import { decodeAttestationObject } from "../../helpers/decodeAttestationObject"; +import { DevicePublicKeyAuthenticatorOutput } from "./decodeDevicePubKey"; export type VerifyDevicePublicKeySignatureOpts = { credential: RegistrationCredentialJSON | AuthenticationCredentialJSON diff --git a/packages/server/src/helpers/decodeAuthenticatorExtensions.ts b/packages/server/src/helpers/decodeAuthenticatorExtensions.ts index 7a77a211..aa9cb318 100644 --- a/packages/server/src/helpers/decodeAuthenticatorExtensions.ts +++ b/packages/server/src/helpers/decodeAuthenticatorExtensions.ts @@ -1,5 +1,5 @@ import cbor from 'cbor'; -import { AttestationFormat, AttestationStatement } from './decodeAttestationObject'; +import { DevicePublicKeyAuthenticatorOutput } from '../extensions/devicePublicKey/decodeDevicePubKey'; /** * Convert authenticator extension data buffer to a proper object @@ -24,15 +24,6 @@ export type AuthenticationExtensionsAuthenticatorOutputs = { uvm?: UVMAuthenticatorOutput; }; -export type DevicePublicKeyAuthenticatorOutput = { - aaguid: Buffer; - dpk: Buffer; - scope: Buffer; - nonce?: Buffer; - fmt?: AttestationFormat; - attStmt?: AttestationStatement; -}; - // TODO: Need to verify this format // https://w3c.github.io/webauthn/#sctn-uvm-extension. export type UVMAuthenticatorOutput = { diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index a7cb4139..e15054ad 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -8,7 +8,6 @@ import { generateAuthenticationOptions } from './authentication/generateAuthenti import { verifyAuthenticationResponse } from './authentication/verifyAuthenticationResponse'; import { MetadataService } from './services/metadataService'; import { SettingsService } from './services/settingsService'; -import { DevicePublicKeyAuthenticatorOutput } from './helpers/decodeAuthenticatorExtensions'; export { generateRegistrationOptions, @@ -39,5 +38,4 @@ export type { VerifyAuthenticationResponseOpts, VerifiedRegistrationResponse, VerifiedAuthenticationResponse, - DevicePublicKeyAuthenticatorOutput, }; diff --git a/packages/server/src/registration/verifyRegistrationResponse.test.ts b/packages/server/src/registration/verifyRegistrationResponse.test.ts index bf0f1061..6f69780f 100644 --- a/packages/server/src/registration/verifyRegistrationResponse.test.ts +++ b/packages/server/src/registration/verifyRegistrationResponse.test.ts @@ -583,38 +583,37 @@ test('should return credential backup info', async () => { test('should return authenticator extension output', async () => { const verification = await verifyRegistrationResponse({ credential: { - id: 'E_Pko4wN1BXE23S0ftN3eQ', - rawId: 'E_Pko4wN1BXE23S0ftN3eQ', response: { - attestationObject: - 'o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVkBag11_MVj_ad52y40PupImIh1i3hUnUk6T9vqHNlqoxzExQAAAAAAAAAAAAAAAAAAAAAAAAAAABAT8-SjjA3UFcTbdLR-03d5pQECAyYgASFYIJIkX8fs9wjKUv5HWBUop--6ig4Szsxj8gBgJJmaX-_5IlggJ5XVdjUfCMlVlUZuHJRxCLFLzZCeK8Fg3l6OLfAIHnKhbGRldmljZVB1YktleaVjZHBrWE2lAQIDJiABIVggmRqr7Z3kJxqe3q2IBvncltbczQxHYlOlUQSJ7IN5vlsiWCCglzz97bt54n_vTudIFnP7MxJQTdylQ0z9I0MdatKe2mNzaWdYRzBFAiEA77OAdL0VuMgs8J-H-8b7PHFp6k8YBrfpCTc3QwI0W3oCICtxEwQHMaDnJ9M41IVChjzmWICqeeXqdArIzNlDR5iOZW5vbmNlQGVzY29wZUEAZmFhZ3VpZFAAAAAAAAAAAAAAAAAAAAAA', - clientDataJSON: - 'eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiQXJrcmxfRnhfTXZjSl9lSXFDVFE3LXRiRVNJ' + - 'U1IxNC1weVBSaDBLLTFBOCIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5' + - 'ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxl' + - 'LmZpZG8yYXBpZXhhbXBsZSJ9', + clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiNkM0QUptNmJyTVJwSF9JZVhDVmtHTTUydnVwTy14Y1huNldlcWIyVjJtTSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', + attestationObject: 'o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVkBMA11_MVj_ad52y40PupImIh1i3hUnUk6T9vqHNlqoxzE3QAAAAAAAAAAAAAAAAAAAAAAAAAAABAHFimPeuzlYZbxRWdeyYzOpQECAyYgASFYIPLEylOIRiI7z7q6zuYjWB9TcOj9yNwmawogQJ4ZKpNAIlggd9ZqIjd30p1tIU6A8ue5wEZl9q_AsKR_leaHFZ_bwWmhbGRldmljZVB1YktleViMpmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=', }, - clientExtensionResults: {}, + id: 'BxYpj3rs5WGW8UVnXsmMzg', + rawId: 'BxYpj3rs5WGW8UVnXsmMzg', type: 'public-key', + transports: [], + clientExtensionResults: { + devicePubKey: { + authenticatorOutput: 'pmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=', + signature: 'MEUCIQDTf2ImngEOi3qHws6gxf6CpquI97oDIl8m_4T2xQO-YwIgdWN7elqNuU-yMZtGpy8hQtL_E-qmZ1_rM2u2nhXYw7A=', + } + } }, - expectedChallenge: 'Arkrl_Fx_MvcJ_eIqCTQ7-tbESISR14-pyPRh0K-1A8', + expectedChallenge: '6C4AJm6brMRpH_IeXCVkGM52vupO-xcXn6Weqb2V2mM', expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', expectedRPID: 'try-webauthn.appspot.com', }); expect(verification.registrationInfo?.extensionOutputs).toMatchObject({ - devicePubKey: { + devicePubKeyToStore: { dpk: Buffer.from( - 'A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', - 'hex', - ), - sig: Buffer.from( - '3045022100EFB38074BD15B8C82CF09F87FBC6FB3C7169EA4F1806B7E90937374302345B7A02202B7113040731A0E727D338D48542863CE65880AA79E5EA740AC8CCD94347988E', + 'A50102032620012158204DC1989D0C2F1040D01F7EC15AC542B14DB54BC5EA5D57ED7F6B383EBB4FABB02258205B61B7D9752FC83686A40EA3CA269C177D7D18F66F22739F5250AA7A75F6855B', 'hex', ), nonce: Buffer.from('', 'hex'), - scope: Buffer.from('00', 'hex'), + scope: 0, aaguid: Buffer.from('00000000000000000000000000000000', 'hex'), + fmt: 'none', + attStmt: {} }, }); }); diff --git a/packages/server/src/registration/verifyRegistrationResponse.ts b/packages/server/src/registration/verifyRegistrationResponse.ts index b06179a6..bb884bd0 100644 --- a/packages/server/src/registration/verifyRegistrationResponse.ts +++ b/packages/server/src/registration/verifyRegistrationResponse.ts @@ -10,7 +10,6 @@ import { AttestationStatement, decodeAttestationObject, } from '../helpers/decodeAttestationObject'; -import { DevicePublicKeyAuthenticatorOutput } from '../helpers/decodeAuthenticatorExtensions'; import { decodeClientDataJSON } from '../helpers/decodeClientDataJSON'; import { parseAuthenticatorData } from '../helpers/parseAuthenticatorData'; import { toHash } from '../helpers/toHash'; @@ -29,7 +28,11 @@ import { verifyAttestationAndroidKey } from './verifications/verifyAttestationAn import { verifyAttestationApple } from './verifications/verifyAttestationApple'; import { verifyDevicePublicKeySignature, VerifyDevicePublicKeySignatureOpts } from '../extensions/devicePublicKey/verifyDevicePublicKeySignature'; import { verifyDevicePublicKeyAttestation } from '../extensions/devicePublicKey/verifyDevicePublicKeyAttestation'; -import { decodeDevicePubKey, decodeDevicePubKeyAuthenticatorOutput } from '../extensions/devicePublicKey/decodeDevicePubKey'; +import { + DevicePublicKeyAuthenticatorOutput, + decodeDevicePubKey, + decodeDevicePubKeyAuthenticatorOutput +} from '../extensions/devicePublicKey/decodeDevicePubKey'; export type VerifyRegistrationResponseOpts = { credential: RegistrationCredentialJSON; @@ -209,39 +212,30 @@ export async function verifyRegistrationResponse( // Device public key sample currently provides the data through // authenticator extension results. if (clientExtensionResults.devicePubKey) { - const { devicePubKey: encodedDevicePubKey } = clientExtensionResults; - const devicePubKey = decodeDevicePubKey(encodedDevicePubKey); - if (!devicePubKey) { - throw new Error('No device public key was provided in the client extension results.'); - } + const devicePubKey = decodeDevicePubKey(clientExtensionResults.devicePubKey); const { authenticatorOutput: encodedAuthenticatorOutput, signature } = devicePubKey; - if (!signature) { - throw new Error('Device public key signature is missing.'); - } + const dpkAuthOutput = decodeDevicePubKeyAuthenticatorOutput(encodedAuthenticatorOutput); - const authenticatorOutput = decodeDevicePubKeyAuthenticatorOutput(encodedAuthenticatorOutput); - if (!authenticatorOutput) { - throw new Error('Device public key authenticator output is corrupt.'); + const dpkOpts: VerifyDevicePublicKeySignatureOpts = { + credential, + authenticatorOutput: dpkAuthOutput, + signature } - const dpkOptions: VerifyDevicePublicKeySignatureOpts = { - credential, - authenticatorOutput, - signature, - }; - const result = await verifyDevicePublicKeySignature(dpkOptions); + const result = await verifyDevicePublicKeySignature(dpkOpts); + if (!result) { throw new Error('DevicePublicKey signature could not be verified'); } // Optionally verify device public key attestation here as per // 10.2.2.3.1. step 4 in the spec. - const attResult = await verifyDevicePublicKeyAttestation(encodedDevicePubKey); + const attResult = await verifyDevicePublicKeyAttestation(dpkAuthOutput); if (!attResult) { throw new Error('Invalid device public key attestation.'); } - extensionOutputs.devicePubKeyToStore = devicePubKey; + extensionOutputs.devicePubKeyToStore = dpkAuthOutput; } } diff --git a/packages/typescript-types/package-lock.json b/packages/typescript-types/package-lock.json new file mode 100644 index 00000000..2aa0dac4 --- /dev/null +++ b/packages/typescript-types/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "@simplewebauthn/typescript-types", + "version": "6.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@simplewebauthn/typescript-types", + "version": "6.0.0", + "license": "MIT" + } + } +} diff --git a/packages/typescript-types/src/index.ts b/packages/typescript-types/src/index.ts index b82c1e1e..1252077e 100644 --- a/packages/typescript-types/src/index.ts +++ b/packages/typescript-types/src/index.ts @@ -68,7 +68,7 @@ export interface RegistrationCredentialJSON extends Omit { rawId: Base64URLString; response: AuthenticatorAttestationResponseJSON; - clientExtensionResults: AuthenticationExtensionsClientOutputsFuture; + clientExtensionResults: AuthenticationExtensionsClientOutputsJSON; transports?: AuthenticatorTransportFuture[]; } @@ -87,7 +87,7 @@ export interface AuthenticationCredentialJSON extends Omit { rawId: Base64URLString; response: AuthenticatorAssertionResponseJSON; - clientExtensionResults: AuthenticationExtensionsClientOutputsFuture; + clientExtensionResults: AuthenticationExtensionsClientOutputsJSON; } export interface AuthenticationExtensionsDevicePublicKeyInputs { @@ -96,7 +96,7 @@ export interface AuthenticationExtensionsDevicePublicKeyInputs { } export interface AuthenticationExtensionsClientInputsFuture extends AuthenticationExtensionsClientInputs { - devicePubKey: AuthenticationExtensionsDevicePublicKeyInputs; + devicePubKey?: AuthenticationExtensionsDevicePublicKeyInputs; } export interface AuthenticationExtensionsDevicePublicKeyOutputs { @@ -105,7 +105,16 @@ export interface AuthenticationExtensionsDevicePublicKeyOutputs { } export interface AuthenticationExtensionsClientOutputsFuture extends AuthenticationExtensionsClientOutputs { - devicePubKey: AuthenticationExtensionsDevicePublicKeyOutputs + devicePubKey?: AuthenticationExtensionsDevicePublicKeyOutputs +} + +export interface AuthenticationExtensionsDevicePublicKeyOutputsJSON { + authenticatorOutput: Base64URLString; + signature: Base64URLString; +} + +export interface AuthenticationExtensionsClientOutputsJSON extends AuthenticationExtensionsClientOutputs { + devicePubKey?: AuthenticationExtensionsDevicePublicKeyOutputsJSON } /** From 41ba0e6bae49c150620d7cd55733322522243a6e Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Sat, 10 Sep 2022 15:01:38 +0900 Subject: [PATCH 24/37] Better test coverage --- .../verifyAuthenticationResponse.test.ts | 63 ++++++++----------- .../decodeDevicePubKey.test.ts | 32 ++++++++++ .../devicePublicKey/decodeDevicePubKey.ts | 15 +++-- .../isRecognizedDevice.test.ts | 20 +++--- .../devicePublicKey/isRecognizedDevice.ts | 10 +-- .../verifyDevicePublicKeyAttestation.ts | 12 +--- .../verifyDevicePublicKeySignature.ts | 3 +- .../verifyRegistrationResponse.test.ts | 58 +++++++++-------- 8 files changed, 116 insertions(+), 97 deletions(-) create mode 100644 packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.test.ts diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts index c883d652..bfe50f98 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts @@ -1,5 +1,5 @@ import base64url from 'base64url'; -import { verifyAuthenticationResponse } from './verifyAuthenticationResponse'; +import { verifyAuthenticationResponse, VerifyAuthenticationResponseOpts } from './verifyAuthenticationResponse'; import * as esmDecodeClientDataJSON from '../helpers/decodeClientDataJSON'; import * as esmParseAuthenticatorData from '../helpers/parseAuthenticatorData'; @@ -316,7 +316,7 @@ test('should fail verification if custom challenge verifier returns false', asyn ).rejects.toThrow(/custom challenge verifier returned false/i); }); -const authenticationCredentialWithDevicePublicKey: AuthenticationCredentialJSON = { +const DpkAuthCred: AuthenticationCredentialJSON = { response: { clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiS05aUmtPRU5KY1dCTzZHX0VjcE1GS2FWRDlham1xNExsZDZJMllJc1c3QSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', authenticatorData: 'DXX8xWP9p3nbLjQ-6kiYiHWLeFSdSTpP2-oc2WqjHMSdAAAAAKFsZGV2aWNlUHViS2V5WIymY2Rwa1hNpQECAyYgASFYIE3BmJ0MLxBA0B9-wVrFQrFNtUvF6l1X7X9rOD67T6uwIlggW2G32XUvyDaGpA6jyiacF319GPZvInOfUlCqenX2hVtjZm10ZG5vbmVlbm9uY2VAZXNjb3BlAGZhYWd1aWRQAAAAAAAAAAAAAAAAAAAAAGdhdHRTdG10oA==', @@ -334,63 +334,50 @@ const authenticationCredentialWithDevicePublicKey: AuthenticationCredentialJSON } }; -if (!authenticationCredentialWithDevicePublicKey?.clientExtensionResults?.devicePubKey) { - throw new Error('This exception will not happen.'); +const DpkVerifyAuthRespOpts: VerifyAuthenticationResponseOpts = { + credential: DpkAuthCred, + expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', + expectedRPID: 'try-webauthn.appspot.com', + expectedChallenge: 'KNZRkOENJcWBO6G_EcpMFKaVD9ajmq4Lld6I2YIsW7A', + authenticator: { + credentialID: base64url.toBuffer('BxYpj3rs5WGW8UVnXsmMzg'), + credentialPublicKey: base64url.toBuffer('pQECAyYgASFYIPLEylOIRiI7z7q6zuYjWB9TcOj9yNwmawogQJ4ZKpNAIlggd9ZqIjd30p1tIU6A8ue5wEZl9q/AsKR/leaHFZ/bwWk='), + counter: 0, + }, } +if (!DpkAuthCred?.clientExtensionResults?.devicePubKey) { + throw new Error('This exception will not happen.'); +} -const encodedDevicePubKey = decodeDevicePubKey(authenticationCredentialWithDevicePublicKey.clientExtensionResults.devicePubKey); +const encodedDevicePubKey = decodeDevicePubKey(DpkAuthCred.clientExtensionResults.devicePubKey); const sameDevicePubKey = decodeDevicePubKeyAuthenticatorOutput(encodedDevicePubKey.authenticatorOutput); const differentDevicePubKey: DevicePublicKeyAuthenticatorOutput = { - "dpk": Buffer.from('A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', 'hex'), - "nonce": Buffer.from('', 'hex'), - "scope": 0, - "aaguid": Buffer.from('00000000000000000000000000000000', 'hex'), + dpk: Buffer.from('A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', 'hex'), + nonce: Buffer.from('', 'hex'), + scope: 0, + aaguid: Buffer.from('00000000000000000000000000000000', 'hex'), + fmt: 'none', + attStmt: {}, }; -const credentialID = base64url.toBuffer('BxYpj3rs5WGW8UVnXsmMzg'); -const credentialPublicKey = base64url.toBuffer('pQECAyYgASFYIPLEylOIRiI7z7q6zuYjWB9TcOj9yNwmawogQJ4ZKpNAIlggd9ZqIjd30p1tIU6A8ue5wEZl9q/AsKR/leaHFZ/bwWk='); test('should throw if multiple device public key matches', async () => { await expect(verifyAuthenticationResponse({ - credential: authenticationCredentialWithDevicePublicKey, - expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', - expectedRPID: 'try-webauthn.appspot.com', - expectedChallenge: 'KNZRkOENJcWBO6G_EcpMFKaVD9ajmq4Lld6I2YIsW7A', - authenticator: { - credentialID, - credentialPublicKey, - counter: 0, - }, + ...DpkVerifyAuthRespOpts, userDevicePublicKeys: [sameDevicePubKey, sameDevicePubKey], })).rejects.toThrowError(new Error('It is undetermined whether this is a known device.')); }); test('should return the new device public key when no device public key matches', async () => { await expect(verifyAuthenticationResponse({ - credential: authenticationCredentialWithDevicePublicKey, - expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', - expectedRPID: 'try-webauthn.appspot.com', - expectedChallenge: 'KNZRkOENJcWBO6G_EcpMFKaVD9ajmq4Lld6I2YIsW7A', - authenticator: { - credentialID, - credentialPublicKey, - counter: 0, - }, + ...DpkVerifyAuthRespOpts, userDevicePublicKeys: [differentDevicePubKey, differentDevicePubKey], }).then(verification => verification.authenticationInfo.extensionOutputs?.devicePubKeyToStore)).resolves.toMatchObject(sameDevicePubKey); }); test('should return undefined when one device public key matches', async () => { await expect(verifyAuthenticationResponse({ - credential: authenticationCredentialWithDevicePublicKey, - expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', - expectedRPID: 'try-webauthn.appspot.com', - expectedChallenge: 'KNZRkOENJcWBO6G_EcpMFKaVD9ajmq4Lld6I2YIsW7A', - authenticator: { - credentialID, - credentialPublicKey, - counter: 0, - }, + ...DpkVerifyAuthRespOpts, userDevicePublicKeys: [sameDevicePubKey, differentDevicePubKey] }).then(verification => verification.authenticationInfo.extensionOutputs?.devicePubKeyToStore)).resolves.toBeUndefined(); }); diff --git a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.test.ts b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.test.ts new file mode 100644 index 00000000..633d8b8c --- /dev/null +++ b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.test.ts @@ -0,0 +1,32 @@ +import { AuthenticationExtensionsDevicePublicKeyOutputs, AuthenticationExtensionsDevicePublicKeyOutputsJSON } from "@simplewebauthn/typescript-types"; +import { decodeDevicePubKey, decodeDevicePubKeyAuthenticatorOutput } from "./decodeDevicePubKey"; + +it("should decode device public key client extension output", () => { + const devicePubKeyJSON: AuthenticationExtensionsDevicePublicKeyOutputsJSON = { + authenticatorOutput: 'pmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=', + signature: 'MEUCIQDTf2ImngEOi3qHws6gxf6CpquI97oDIl8m_4T2xQO-YwIgdWN7elqNuU-yMZtGpy8hQtL_E-qmZ1_rM2u2nhXYw7A=', + } + + const result = decodeDevicePubKey(devicePubKeyJSON); + expect(result).toMatchObject({ + authenticatorOutput: Buffer.from('A66364706B584DA50102032620012158204DC1989D0C2F1040D01F7EC15AC542B14DB54BC5EA5D57ED7F6B383EBB4FABB02258205B61B7D9752FC83686A40EA3CA269C177D7D18F66F22739F5250AA7A75F6855B63666D74646E6F6E65656E6F6E6365406573636F7065006661616775696450000000000000000000000000000000006761747453746D74A0', 'hex'), + signature: Buffer.from('3045022100d37f62269e010e8b7a87c2cea0c5fe82a6ab88f7ba03225f26ff84f6c503be63022075637b7a5a8db94fb2319b46a72f2142d2ff13eaa6675feb336bb69e15d8c3b0', 'hex'), + }); +}); + +it("should decode device public key authenticator output", () => { + const devicePubKey: AuthenticationExtensionsDevicePublicKeyOutputs = { + authenticatorOutput: Buffer.from('A66364706B584DA50102032620012158204DC1989D0C2F1040D01F7EC15AC542B14DB54BC5EA5D57ED7F6B383EBB4FABB02258205B61B7D9752FC83686A40EA3CA269C177D7D18F66F22739F5250AA7A75F6855B63666D74646E6F6E65656E6F6E6365406573636F7065006661616775696450000000000000000000000000000000006761747453746D74A0', 'hex'), + signature: Buffer.from('3045022100d37f62269e010e8b7a87c2cea0c5fe82a6ab88f7ba03225f26ff84f6c503be63022075637b7a5a8db94fb2319b46a72f2142d2ff13eaa6675feb336bb69e15d8c3b0', 'hex'), + } + + const result = decodeDevicePubKeyAuthenticatorOutput(devicePubKey.authenticatorOutput); + expect(result).toMatchObject({ + dpk: Buffer.from('A50102032620012158204DC1989D0C2F1040D01F7EC15AC542B14DB54BC5EA5D57ED7F6B383EBB4FABB02258205B61B7D9752FC83686A40EA3CA269C177D7D18F66F22739F5250AA7A75F6855B', 'hex'), + fmt: "none", + nonce: Buffer.from('', 'hex'), + scope: 0, + aaguid: Buffer.from('00000000000000000000000000000000', 'hex'), + attStmt: {}, + }); +}) diff --git a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts index 759afd7f..14d0f732 100644 --- a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts +++ b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts @@ -4,9 +4,10 @@ import { AttestationFormat, AttestationStatement } from '../../helpers/decodeAtt import base64url from 'base64url'; /** - * Convert device public key client extension data buffer to a proper object + * Convert base64url encoded device public key client extension data to buffer * - * @param devicePubKey Client Extension's device public key data buffer + * @param devicePubKey Base64url encoded device public key data obtained from + * client extension results */ export function decodeDevicePubKey( devicePubKeyJSON: AuthenticationExtensionsDevicePublicKeyOutputsJSON, @@ -41,6 +42,12 @@ export function decodeDevicePubKey( return devicePubKey; } +/** + * Decode device public key authenticator output data CBOR to JSON + * @param authenticatorOutput CBOR encoded device public key authenticator + * output + * @returns JSON based device public key authenticator data + */ export function decodeDevicePubKeyAuthenticatorOutput( authenticatorOutput: Buffer, ): DevicePublicKeyAuthenticatorOutput { @@ -58,7 +65,7 @@ export type DevicePublicKeyAuthenticatorOutput = { aaguid: Buffer; dpk: Buffer; scope: number; + fmt: AttestationFormat; + attStmt: AttestationStatement; nonce?: Buffer; - fmt?: AttestationFormat; - attStmt?: AttestationStatement; }; diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts index e661364d..3e5f2506 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts @@ -2,18 +2,22 @@ import { isRecognizedDevice } from './isRecognizedDevice'; import { DevicePublicKeyAuthenticatorOutput } from './decodeDevicePubKey'; const devicePubKey: DevicePublicKeyAuthenticatorOutput = { - "dpk": Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'), - "nonce": Buffer.from('', 'hex'), - "scope": 0, - "aaguid": Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), + dpk: Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'), + nonce: Buffer.from('', 'hex'), + scope: 0, + aaguid: Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), + fmt: 'none', + attStmt: {}, } const sameDevicePubKey = devicePubKey; const differentDevicePubKey: DevicePublicKeyAuthenticatorOutput = { - "dpk": Buffer.from('A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', 'hex'), - "nonce": Buffer.from('', 'hex'), - "scope": 0, - "aaguid": Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), + dpk: Buffer.from('A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', 'hex'), + nonce: Buffer.from('', 'hex'), + scope: 0, + aaguid: Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), + fmt: 'none', + attStmt: {}, }; it("should throw when more than two device public key matches", async () => { diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts index 9bcaec30..9ea30d21 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts @@ -74,12 +74,12 @@ export async function isRecognizedDevice( // is no attestation signature to verify and this is a known device public // key with a valid signature and thus a known device. Terminate these // verification steps. - if (responseDevicePublicKey.fmt && responseDevicePublicKey.fmt !== 'none') { + if (responseDevicePublicKey.fmt !== 'none') { // Perform a binary equality check of `attStmt`. const recognizedDPKAttStmt = matchedDPKs[0].attStmt; - let dpksAreBinaryEqual = false; try { - dpksAreBinaryEqual = checkAttStmtBinaryEquality(responseDevicePublicKey.attStmt, recognizedDPKAttStmt); + // Unless thrown, this always returns `true`. + checkAttStmtBinaryEquality(responseDevicePublicKey.attStmt, recognizedDPKAttStmt); } catch (err) { // const _err = err as Error; // How do we message the error cause? @@ -90,10 +90,6 @@ export async function isRecognizedDevice( throw new Error('DevicePublicKey attestation could not be verified.'); } } - - if (!dpksAreBinaryEqual) { - // TODO: - } } // This is a valid and a known device. return; diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts index ae268350..6a4b2189 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts @@ -1,14 +1,4 @@ import { DevicePublicKeyAuthenticatorOutput } from "./decodeDevicePubKey"; -import { - AuthenticationCredentialJSON, - RegistrationCredentialJSON, -} from "@simplewebauthn/typescript-types"; - -export type VerifyDevicePublicKeySignatureOpts = { - credential: RegistrationCredentialJSON | AuthenticationCredentialJSON - devicePubKey: DevicePublicKeyAuthenticatorOutput; - signature: Buffer; -}; /** * https://pr-preview.s3.amazonaws.com/w3c/webauthn/pull/1663.html#sctn-device-publickey-extension-verification-create @@ -22,7 +12,7 @@ export async function verifyDevicePublicKeyAttestation( devicePubKey: DevicePublicKeyAuthenticatorOutput ): Promise { const { fmt } = devicePubKey; - if (fmt === undefined || fmt === 'none') { + if (fmt === 'none') { return true; } else { throw new Error('Attestation verification on a device public key is not implemented yet.'); diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts index ad40b694..af6ece27 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts @@ -45,8 +45,7 @@ export async function verifyDevicePublicKeySignature( const { clientDataJSON } = credential.response; const clientDataHash = toHash(base64url.toBuffer(clientDataJSON)); - const nonce = authenticatorOutput.nonce ? authenticatorOutput.nonce : Buffer.from(''); - const signatureBase = Buffer.concat([authData, clientDataHash, nonce]); + const signatureBase = Buffer.concat([authData, clientDataHash]); // It's a device public key and not a credential public key, but to align with // the `verifySinature` signature, we name it `credentialPublicKey`. const credentialPublicKey = authenticatorOutput.dpk; diff --git a/packages/server/src/registration/verifyRegistrationResponse.test.ts b/packages/server/src/registration/verifyRegistrationResponse.test.ts index 6f69780f..ad6e111a 100644 --- a/packages/server/src/registration/verifyRegistrationResponse.test.ts +++ b/packages/server/src/registration/verifyRegistrationResponse.test.ts @@ -1,6 +1,6 @@ import base64url from 'base64url'; -import { verifyRegistrationResponse } from './verifyRegistrationResponse'; +import { verifyRegistrationResponse, VerifyRegistrationResponseOpts } from './verifyRegistrationResponse'; import * as esmDecodeAttestationObject from '../helpers/decodeAttestationObject'; import * as esmDecodeClientDataJSON from '../helpers/decodeClientDataJSON'; @@ -580,35 +580,39 @@ test('should return credential backup info', async () => { expect(verification.registrationInfo?.credentialBackedUp).toEqual(false); }); -test('should return authenticator extension output', async () => { - const verification = await verifyRegistrationResponse({ - credential: { - response: { - clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiNkM0QUptNmJyTVJwSF9JZVhDVmtHTTUydnVwTy14Y1huNldlcWIyVjJtTSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', - attestationObject: 'o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVkBMA11_MVj_ad52y40PupImIh1i3hUnUk6T9vqHNlqoxzE3QAAAAAAAAAAAAAAAAAAAAAAAAAAABAHFimPeuzlYZbxRWdeyYzOpQECAyYgASFYIPLEylOIRiI7z7q6zuYjWB9TcOj9yNwmawogQJ4ZKpNAIlggd9ZqIjd30p1tIU6A8ue5wEZl9q_AsKR_leaHFZ_bwWmhbGRldmljZVB1YktleViMpmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=', - }, - id: 'BxYpj3rs5WGW8UVnXsmMzg', - rawId: 'BxYpj3rs5WGW8UVnXsmMzg', - type: 'public-key', - transports: [], - clientExtensionResults: { - devicePubKey: { - authenticatorOutput: 'pmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=', - signature: 'MEUCIQDTf2ImngEOi3qHws6gxf6CpquI97oDIl8m_4T2xQO-YwIgdWN7elqNuU-yMZtGpy8hQtL_E-qmZ1_rM2u2nhXYw7A=', - } - } - }, - expectedChallenge: '6C4AJm6brMRpH_IeXCVkGM52vupO-xcXn6Weqb2V2mM', - expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', - expectedRPID: 'try-webauthn.appspot.com', - }); +const DpkRegCred: RegistrationCredentialJSON = { + response: { + clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiNkM0QUptNmJyTVJwSF9JZVhDVmtHTTUydnVwTy14Y1huNldlcWIyVjJtTSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', + attestationObject: 'o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVkBMA11_MVj_ad52y40PupImIh1i3hUnUk6T9vqHNlqoxzE3QAAAAAAAAAAAAAAAAAAAAAAAAAAABAHFimPeuzlYZbxRWdeyYzOpQECAyYgASFYIPLEylOIRiI7z7q6zuYjWB9TcOj9yNwmawogQJ4ZKpNAIlggd9ZqIjd30p1tIU6A8ue5wEZl9q_AsKR_leaHFZ_bwWmhbGRldmljZVB1YktleViMpmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=' + }, + id: 'BxYpj3rs5WGW8UVnXsmMzg', + rawId: 'BxYpj3rs5WGW8UVnXsmMzg', + type: 'public-key', + transports: [], + clientExtensionResults: { + devicePubKey: { + authenticatorOutput: 'pmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=', + signature: 'MEUCIQDTf2ImngEOi3qHws6gxf6CpquI97oDIl8m_4T2xQO-YwIgdWN7elqNuU-yMZtGpy8hQtL_E-qmZ1_rM2u2nhXYw7A=' + } + } +}; +if (!DpkRegCred?.clientExtensionResults?.devicePubKey) { + throw new Error('This exception will not happen.'); +} + +const DpkVerifyRegRespOpts: VerifyRegistrationResponseOpts = { + credential: DpkRegCred, + expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', + expectedRPID: 'try-webauthn.appspot.com', + expectedChallenge: '6C4AJm6brMRpH_IeXCVkGM52vupO-xcXn6Weqb2V2mM', +} + +test('should return authenticator extension output', async () => { + const verification = await verifyRegistrationResponse(DpkVerifyRegRespOpts); expect(verification.registrationInfo?.extensionOutputs).toMatchObject({ devicePubKeyToStore: { - dpk: Buffer.from( - 'A50102032620012158204DC1989D0C2F1040D01F7EC15AC542B14DB54BC5EA5D57ED7F6B383EBB4FABB02258205B61B7D9752FC83686A40EA3CA269C177D7D18F66F22739F5250AA7A75F6855B', - 'hex', - ), + dpk: Buffer.from('A50102032620012158204DC1989D0C2F1040D01F7EC15AC542B14DB54BC5EA5D57ED7F6B383EBB4FABB02258205B61B7D9752FC83686A40EA3CA269C177D7D18F66F22739F5250AA7A75F6855B', 'hex'), nonce: Buffer.from('', 'hex'), scope: 0, aaguid: Buffer.from('00000000000000000000000000000000', 'hex'), From 0747463598be6185cf4d74252f0a107be893ac0f Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Tue, 20 Sep 2022 21:58:47 +0900 Subject: [PATCH 25/37] Reflect feedback --- .../devicePublicKey/decodeDevicePubKey.ts | 8 +++-- .../devicePublicKey/isRecognizedDevice.ts | 2 +- .../src/helpers/decodeAttestationObject.ts | 20 +----------- packages/server/src/helpers/index.ts | 8 +---- .../verifyAttestationAndroidSafetyNet.test.ts | 6 ++-- .../verifyRegistrationResponse.ts | 8 ++--- .../server/src/services/settingsService.ts | 2 +- packages/typescript-types/src/index.ts | 32 +++++++++++++++---- 8 files changed, 41 insertions(+), 45 deletions(-) diff --git a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts index 14d0f732..b11a8d33 100644 --- a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts +++ b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts @@ -1,6 +1,10 @@ import { decodeCborFirst } from '../../helpers/decodeCbor'; -import { AuthenticationExtensionsDevicePublicKeyOutputs, AuthenticationExtensionsDevicePublicKeyOutputsJSON } from '@simplewebauthn/typescript-types'; -import { AttestationFormat, AttestationStatement } from '../../helpers/decodeAttestationObject'; +import { + AuthenticationExtensionsDevicePublicKeyOutputs, + AuthenticationExtensionsDevicePublicKeyOutputsJSON, + AttestationFormat, + AttestationStatement, +} from '@simplewebauthn/typescript-types'; import base64url from 'base64url'; /** diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts index 9ea30d21..e314b1f5 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts @@ -1,4 +1,4 @@ -import { AttestationStatement } from "../../helpers/decodeAttestationObject"; +import { AttestationStatement } from "@simplewebauthn/typescript-types"; import { DevicePublicKeyAuthenticatorOutput } from './decodeDevicePubKey'; import { verifyDevicePublicKeyAttestation } from "./verifyDevicePublicKeyAttestation"; diff --git a/packages/server/src/helpers/decodeAttestationObject.ts b/packages/server/src/helpers/decodeAttestationObject.ts index 5385106e..7a595d31 100644 --- a/packages/server/src/helpers/decodeAttestationObject.ts +++ b/packages/server/src/helpers/decodeAttestationObject.ts @@ -1,4 +1,5 @@ import cbor from 'cbor'; +import { AttestationFormat, AttestationStatement } from '@simplewebauthn/typescript-types'; /** * Convert an AttestationObject buffer to a proper object @@ -10,27 +11,8 @@ export function decodeAttestationObject(attestationObject: Buffer): AttestationO return toCBOR; } -export type AttestationFormat = - | 'fido-u2f' - | 'packed' - | 'android-safetynet' - | 'android-key' - | 'tpm' - | 'apple' - | 'none'; - export type AttestationObject = { fmt: AttestationFormat; attStmt: AttestationStatement; authData: Buffer; }; - -export type AttestationStatement = { - sig?: Buffer; - x5c?: Buffer[]; - response?: Buffer; - alg?: number; - ver?: string; - certInfo?: Buffer; - pubArea?: Buffer; -}; diff --git a/packages/server/src/helpers/index.ts b/packages/server/src/helpers/index.ts index d0c4f428..879dab80 100644 --- a/packages/server/src/helpers/index.ts +++ b/packages/server/src/helpers/index.ts @@ -34,20 +34,14 @@ export { verifySignature, }; -import type { - AttestationFormat, - AttestationObject, - AttestationStatement, -} from './decodeAttestationObject'; +import type { AttestationObject } from './decodeAttestationObject'; import type { CertificateInfo } from './getCertificateInfo'; import type { ClientDataJSON } from './decodeClientDataJSON'; import type { COSEPublicKey } from './convertCOSEtoPKCS'; import type { ParsedAuthenticatorData } from './parseAuthenticatorData'; export type { - AttestationFormat, AttestationObject, - AttestationStatement, CertificateInfo, ClientDataJSON, COSEPublicKey, diff --git a/packages/server/src/registration/verifications/verifyAttestationAndroidSafetyNet.test.ts b/packages/server/src/registration/verifications/verifyAttestationAndroidSafetyNet.test.ts index 5df3bee9..4463a206 100644 --- a/packages/server/src/registration/verifications/verifyAttestationAndroidSafetyNet.test.ts +++ b/packages/server/src/registration/verifications/verifyAttestationAndroidSafetyNet.test.ts @@ -2,13 +2,11 @@ import base64url from 'base64url'; import { verifyAttestationAndroidSafetyNet } from './verifyAttestationAndroidSafetyNet'; -import { - decodeAttestationObject, - AttestationStatement, -} from '../../helpers/decodeAttestationObject'; +import { decodeAttestationObject } from '../../helpers/decodeAttestationObject'; import { parseAuthenticatorData } from '../../helpers/parseAuthenticatorData'; import { toHash } from '../../helpers/toHash'; import { SettingsService } from '../../services/settingsService'; +import { AttestationStatement } from '@simplewebauthn/typescript-types'; const rootCertificates = SettingsService.getRootCertificates({ identifier: 'android-safetynet', diff --git a/packages/server/src/registration/verifyRegistrationResponse.ts b/packages/server/src/registration/verifyRegistrationResponse.ts index bb884bd0..d7352a97 100644 --- a/packages/server/src/registration/verifyRegistrationResponse.ts +++ b/packages/server/src/registration/verifyRegistrationResponse.ts @@ -3,13 +3,11 @@ import { RegistrationCredentialJSON, COSEAlgorithmIdentifier, CredentialDeviceType, -} from '@simplewebauthn/typescript-types'; - -import { AttestationFormat, AttestationStatement, - decodeAttestationObject, -} from '../helpers/decodeAttestationObject'; +} from '@simplewebauthn/typescript-types'; + +import { decodeAttestationObject } from '../helpers/decodeAttestationObject'; import { decodeClientDataJSON } from '../helpers/decodeClientDataJSON'; import { parseAuthenticatorData } from '../helpers/parseAuthenticatorData'; import { toHash } from '../helpers/toHash'; diff --git a/packages/server/src/services/settingsService.ts b/packages/server/src/services/settingsService.ts index 6dce26b3..d4da44b2 100644 --- a/packages/server/src/services/settingsService.ts +++ b/packages/server/src/services/settingsService.ts @@ -1,4 +1,4 @@ -import { AttestationFormat } from '../helpers/decodeAttestationObject'; +import { AttestationFormat } from '@simplewebauthn/typescript-types'; import { convertCertBufferToPEM } from '../helpers/convertCertBufferToPEM'; import { GlobalSign_Root_CA } from './defaultRootCerts/android-safetynet'; diff --git a/packages/typescript-types/src/index.ts b/packages/typescript-types/src/index.ts index 1252077e..4f05830a 100644 --- a/packages/typescript-types/src/index.ts +++ b/packages/typescript-types/src/index.ts @@ -15,6 +15,7 @@ import type { AuthenticationExtensionsClientInputs, AuthenticationExtensionsClientOutputs, AuthenticatorAttachment, + AttestationConveyancePreference, } from './dom'; export * from './dom'; @@ -90,9 +91,28 @@ export interface AuthenticationCredentialJSON clientExtensionResults: AuthenticationExtensionsClientOutputsJSON; } +export type AttestationFormat = + | 'fido-u2f' + | 'packed' + | 'android-safetynet' + | 'android-key' + | 'tpm' + | 'apple' + | 'none'; + +export type AttestationStatement = { + sig?: Buffer; + x5c?: Buffer[]; + response?: Buffer; + alg?: number; + ver?: string; + certInfo?: Buffer; + pubArea?: Buffer; +}; + export interface AuthenticationExtensionsDevicePublicKeyInputs { - attestation: string; - attestationFormats: string[]; + attestation?: AttestationConveyancePreference; + attestationFormats?: AttestationFormat[]; } export interface AuthenticationExtensionsClientInputsFuture extends AuthenticationExtensionsClientInputs { @@ -104,15 +124,15 @@ export interface AuthenticationExtensionsDevicePublicKeyOutputs { signature: Buffer; } -export interface AuthenticationExtensionsClientOutputsFuture extends AuthenticationExtensionsClientOutputs { - devicePubKey?: AuthenticationExtensionsDevicePublicKeyOutputs -} - export interface AuthenticationExtensionsDevicePublicKeyOutputsJSON { authenticatorOutput: Base64URLString; signature: Base64URLString; } +export interface AuthenticationExtensionsClientOutputsFuture extends AuthenticationExtensionsClientOutputs { + devicePubKey?: AuthenticationExtensionsDevicePublicKeyOutputs +} + export interface AuthenticationExtensionsClientOutputsJSON extends AuthenticationExtensionsClientOutputs { devicePubKey?: AuthenticationExtensionsDevicePublicKeyOutputsJSON } From f6a99a22df5560f1661b807534a769813bc2aaab Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Tue, 20 Sep 2022 22:02:50 +0900 Subject: [PATCH 26/37] Remove package.json files --- packages/server/package-lock.json | 695 -------------------- packages/typescript-types/package-lock.json | 13 - 2 files changed, 708 deletions(-) delete mode 100644 packages/server/package-lock.json delete mode 100644 packages/typescript-types/package-lock.json diff --git a/packages/server/package-lock.json b/packages/server/package-lock.json deleted file mode 100644 index 4cda2751..00000000 --- a/packages/server/package-lock.json +++ /dev/null @@ -1,695 +0,0 @@ -{ - "name": "@simplewebauthn/server", - "version": "6.3.0-alpha.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "@simplewebauthn/server", - "version": "6.3.0-alpha.0", - "license": "MIT", - "dependencies": { - "@noble/ed25519": "^1.6.1", - "@peculiar/asn1-android": "^2.1.7", - "@peculiar/asn1-schema": "^2.1.7", - "@peculiar/asn1-x509": "^2.1.7", - "@simplewebauthn/typescript-types": "^6.0.0", - "base64url": "^3.0.1", - "cbor": "^5.1.0", - "debug": "^4.3.2", - "jsrsasign": "^10.4.0", - "jwk-to-pem": "^2.0.4", - "node-fetch": "^2.6.0" - }, - "devDependencies": { - "@types/cbor": "^5.0.1", - "@types/debug": "^4.1.7", - "@types/jsrsasign": "^8.0.13", - "@types/jwk-to-pem": "^2.0.1", - "@types/node-fetch": "^2.5.12" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "../typescript-types": { - "name": "@simplewebauthn/typescript-types", - "version": "6.0.0", - "license": "MIT" - }, - "node_modules/@noble/ed25519": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.0.tgz", - "integrity": "sha512-LeAxFK0+181zQOhOUuKE8Jnd3duzYhDNd3iCLxpmzA5K+e4I1FdbrK3Ot0ZHBwZMeRD/6EojyUfTbpHZ+hkQHg==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, - "node_modules/@peculiar/asn1-android": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.3.0.tgz", - "integrity": "sha512-ooQ6zRxSXcJ7IW6y7rd3DztgGwzJ3Esq28ideiVwj1hmkPHwqhoRvgHoeddOUQds9GHiwDN5uM/fufnTOxrG2A==", - "dependencies": { - "@peculiar/asn1-schema": "^2.3.0", - "asn1js": "^3.0.5", - "tslib": "^2.4.0" - } - }, - "node_modules/@peculiar/asn1-schema": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.0.tgz", - "integrity": "sha512-DtNLAG4vmDrdSJFPe7rypkcj597chNQL7u+2dBtYo5mh7VW2+im6ke+O0NVr8W1f4re4C3F71LhoMb0Yxqa48Q==", - "dependencies": { - "asn1js": "^3.0.5", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@peculiar/asn1-x509": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.3.0.tgz", - "integrity": "sha512-iDRNPHAx/HLwR9wN5xaHDPifpdSW/bquu+zo/kQXurnxg6KQ1jcZw+4a63uTvrzyGU/hHzDqjalG/sQvV02lAw==", - "dependencies": { - "@peculiar/asn1-schema": "^2.3.0", - "asn1js": "^3.0.5", - "ipaddr.js": "^2.0.1", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@simplewebauthn/typescript-types": { - "resolved": "../typescript-types", - "link": true - }, - "node_modules/@types/cbor": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/cbor/-/cbor-5.0.1.tgz", - "integrity": "sha512-zVqJy2KzusZPLOgyGJDnOIbu3DxIGGqxYbEwtEEe4Z+la8jwIhOyb+GMrlHafs5tvKruwf8f8qOYP6zTvse/pw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/debug": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", - "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", - "dev": true, - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/jsrsasign": { - "version": "8.0.13", - "resolved": "https://registry.npmjs.org/@types/jsrsasign/-/jsrsasign-8.0.13.tgz", - "integrity": "sha512-+0Ij59D6NXP48KkeLhPXeQKOyLjvA9CD7zacc0Svy2IWHdl62BmDeTvGSIwKaGZSoamLJOo+on1AG/wPRLsd7A==", - "dev": true - }, - "node_modules/@types/jwk-to-pem": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/jwk-to-pem/-/jwk-to-pem-2.0.1.tgz", - "integrity": "sha512-QXmRPhR/LPzvXBHTPfG2BBfMTkNLUD7NyRcPft8m5xFCeANa1BZyLgT0Gw+OxdWx6i1WCpT27EqyggP4UUHMrA==", - "dev": true - }, - "node_modules/@types/ms": { - "version": "0.7.31", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "17.0.34", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node-fetch": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", - "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", - "dev": true, - "dependencies": { - "@types/node": "*", - "form-data": "^3.0.0" - } - }, - "node_modules/asn1.js": { - "version": "5.4.1", - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/asn1js": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", - "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", - "dependencies": { - "pvtsutils": "^1.3.2", - "pvutils": "^1.1.3", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/base64url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", - "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/bignumber.js": { - "version": "9.0.2", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/bn.js": { - "version": "4.12.0", - "license": "MIT" - }, - "node_modules/brorand": { - "version": "1.1.0", - "license": "MIT" - }, - "node_modules/cbor": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", - "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", - "dependencies": { - "bignumber.js": "^9.0.1", - "nofilter": "^1.0.4" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/elliptic": { - "version": "6.5.4", - "license": "MIT", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/form-data": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "license": "ISC" - }, - "node_modules/ipaddr.js": { - "version": "2.0.1", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/jsrsasign": { - "version": "10.5.27", - "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.5.27.tgz", - "integrity": "sha512-1F4LmDeJZHYwoVvB44jEo2uZL3XuwYNzXCDOu53Ui6vqofGQ/gCYDmaxfVZtN0TGd92UKXr/BONcfrPonUIcQQ==", - "funding": { - "url": "https://github.com/kjur/jsrsasign#donations" - } - }, - "node_modules/jwk-to-pem": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz", - "integrity": "sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==", - "dependencies": { - "asn1.js": "^5.3.0", - "elliptic": "^6.5.4", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "license": "ISC" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "license": "MIT" - }, - "node_modules/ms": { - "version": "2.1.2", - "license": "MIT" - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/nofilter": { - "version": "1.0.4", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pvtsutils": { - "version": "1.3.2", - "license": "MIT", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/pvutils": { - "version": "1.1.3", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "license": "MIT" - }, - "node_modules/tr46": { - "version": "0.0.3", - "license": "MIT" - }, - "node_modules/tslib": { - "version": "2.4.0", - "license": "0BSD" - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - } - }, - "dependencies": { - "@noble/ed25519": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.0.tgz", - "integrity": "sha512-LeAxFK0+181zQOhOUuKE8Jnd3duzYhDNd3iCLxpmzA5K+e4I1FdbrK3Ot0ZHBwZMeRD/6EojyUfTbpHZ+hkQHg==" - }, - "@peculiar/asn1-android": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.3.0.tgz", - "integrity": "sha512-ooQ6zRxSXcJ7IW6y7rd3DztgGwzJ3Esq28ideiVwj1hmkPHwqhoRvgHoeddOUQds9GHiwDN5uM/fufnTOxrG2A==", - "requires": { - "@peculiar/asn1-schema": "^2.3.0", - "asn1js": "^3.0.5", - "tslib": "^2.4.0" - } - }, - "@peculiar/asn1-schema": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.0.tgz", - "integrity": "sha512-DtNLAG4vmDrdSJFPe7rypkcj597chNQL7u+2dBtYo5mh7VW2+im6ke+O0NVr8W1f4re4C3F71LhoMb0Yxqa48Q==", - "requires": { - "asn1js": "^3.0.5", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" - } - }, - "@peculiar/asn1-x509": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.3.0.tgz", - "integrity": "sha512-iDRNPHAx/HLwR9wN5xaHDPifpdSW/bquu+zo/kQXurnxg6KQ1jcZw+4a63uTvrzyGU/hHzDqjalG/sQvV02lAw==", - "requires": { - "@peculiar/asn1-schema": "^2.3.0", - "asn1js": "^3.0.5", - "ipaddr.js": "^2.0.1", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" - } - }, - "@simplewebauthn/typescript-types": { - "version": "file:../typescript-types" - }, - "@types/cbor": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/cbor/-/cbor-5.0.1.tgz", - "integrity": "sha512-zVqJy2KzusZPLOgyGJDnOIbu3DxIGGqxYbEwtEEe4Z+la8jwIhOyb+GMrlHafs5tvKruwf8f8qOYP6zTvse/pw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/debug": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", - "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", - "dev": true, - "requires": { - "@types/ms": "*" - } - }, - "@types/jsrsasign": { - "version": "8.0.13", - "resolved": "https://registry.npmjs.org/@types/jsrsasign/-/jsrsasign-8.0.13.tgz", - "integrity": "sha512-+0Ij59D6NXP48KkeLhPXeQKOyLjvA9CD7zacc0Svy2IWHdl62BmDeTvGSIwKaGZSoamLJOo+on1AG/wPRLsd7A==", - "dev": true - }, - "@types/jwk-to-pem": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/jwk-to-pem/-/jwk-to-pem-2.0.1.tgz", - "integrity": "sha512-QXmRPhR/LPzvXBHTPfG2BBfMTkNLUD7NyRcPft8m5xFCeANa1BZyLgT0Gw+OxdWx6i1WCpT27EqyggP4UUHMrA==", - "dev": true - }, - "@types/ms": { - "version": "0.7.31", - "dev": true - }, - "@types/node": { - "version": "17.0.34", - "dev": true - }, - "@types/node-fetch": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", - "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", - "dev": true, - "requires": { - "@types/node": "*", - "form-data": "^3.0.0" - } - }, - "asn1.js": { - "version": "5.4.1", - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - } - }, - "asn1js": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", - "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", - "requires": { - "pvtsutils": "^1.3.2", - "pvutils": "^1.1.3", - "tslib": "^2.4.0" - } - }, - "asynckit": { - "version": "0.4.0", - "dev": true - }, - "base64url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", - "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" - }, - "bignumber.js": { - "version": "9.0.2" - }, - "bn.js": { - "version": "4.12.0" - }, - "brorand": { - "version": "1.1.0" - }, - "cbor": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", - "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", - "requires": { - "bignumber.js": "^9.0.1", - "nofilter": "^1.0.4" - } - }, - "combined-stream": { - "version": "1.0.8", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "delayed-stream": { - "version": "1.0.0", - "dev": true - }, - "elliptic": { - "version": "6.5.4", - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "form-data": { - "version": "3.0.1", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "hash.js": { - "version": "1.1.7", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "inherits": { - "version": "2.0.4" - }, - "ipaddr.js": { - "version": "2.0.1" - }, - "jsrsasign": { - "version": "10.5.27", - "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.5.27.tgz", - "integrity": "sha512-1F4LmDeJZHYwoVvB44jEo2uZL3XuwYNzXCDOu53Ui6vqofGQ/gCYDmaxfVZtN0TGd92UKXr/BONcfrPonUIcQQ==" - }, - "jwk-to-pem": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz", - "integrity": "sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==", - "requires": { - "asn1.js": "^5.3.0", - "elliptic": "^6.5.4", - "safe-buffer": "^5.0.1" - } - }, - "mime-db": { - "version": "1.52.0", - "dev": true - }, - "mime-types": { - "version": "2.1.35", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, - "minimalistic-assert": { - "version": "1.0.1" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1" - }, - "ms": { - "version": "2.1.2" - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "nofilter": { - "version": "1.0.4" - }, - "pvtsutils": { - "version": "1.3.2", - "requires": { - "tslib": "^2.4.0" - } - }, - "pvutils": { - "version": "1.1.3" - }, - "safe-buffer": { - "version": "5.2.1" - }, - "safer-buffer": { - "version": "2.1.2" - }, - "tr46": { - "version": "0.0.3" - }, - "tslib": { - "version": "2.4.0" - }, - "webidl-conversions": { - "version": "3.0.1" - }, - "whatwg-url": { - "version": "5.0.0", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - } - } -} diff --git a/packages/typescript-types/package-lock.json b/packages/typescript-types/package-lock.json deleted file mode 100644 index 2aa0dac4..00000000 --- a/packages/typescript-types/package-lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "@simplewebauthn/typescript-types", - "version": "6.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "@simplewebauthn/typescript-types", - "version": "6.0.0", - "license": "MIT" - } - } -} From e1881289012da1cd21ec7048fe95f44ccaddb1ea Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Sun, 2 Oct 2022 15:55:39 +0900 Subject: [PATCH 27/37] Parse dpk result on the browser --- .../parseClientExtensionResults.test.ts | 44 +++++++++++++++++++ .../helpers/parseClientExtensionResults.ts | 32 ++++++++++++++ .../src/methods/startAuthentication.ts | 3 +- .../browser/src/methods/startRegistration.ts | 3 +- 4 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 packages/browser/src/helpers/parseClientExtensionResults.test.ts create mode 100644 packages/browser/src/helpers/parseClientExtensionResults.ts diff --git a/packages/browser/src/helpers/parseClientExtensionResults.test.ts b/packages/browser/src/helpers/parseClientExtensionResults.test.ts new file mode 100644 index 00000000..90495f22 --- /dev/null +++ b/packages/browser/src/helpers/parseClientExtensionResults.test.ts @@ -0,0 +1,44 @@ +import { parseClientExtensionResults } from './parseClientExtensionResults'; +import { utf8StringToBuffer } from './utf8StringToBuffer'; +import { + AuthenticationExtensionsClientOutputsFuture, + AuthenticationCredential +} from '@simplewebauthn/typescript-types'; + +jest.mock('../helpers/browserSupportsWebAuthn'); + +const mockAuthenticatorData = 'mockAuthenticatorData'; +const mockClientDataJSON = 'mockClientDataJSON'; +const mockSignature = 'mockSignature'; +const mockUserHandle = 'mockUserHandle'; + +test('should return client extension results in JSON format', async () => { + const credential: AuthenticationCredential = { + id: 'foobar', + rawId: utf8StringToBuffer('foobar'), + response: { + authenticatorData: Buffer.from(mockAuthenticatorData, 'ascii'), + clientDataJSON: Buffer.from(mockClientDataJSON, 'ascii'), + signature: Buffer.from(mockSignature, 'ascii'), + userHandle: Buffer.from(mockUserHandle, 'ascii'), + }, + getClientExtensionResults: (): AuthenticationExtensionsClientOutputsFuture => { + return { + devicePubKey: { + authenticatorOutput: Buffer.from('a66364706b584da50102032620012158206c2411290f2f5dc0d590c25ed9f4b9645a94bb8ecba2377765b103dad5c99243225820c10b2ab6051e0610388d3f2d75a624b94454f4f51948b3dcc6f34b7518f2455263666d74646e6f6e65656e6f6e6365406573636f7065006661616775696450000000000000000000000000000000006761747453746d74a0', 'hex'), + signature: Buffer.from('3045022078ac013e33175eb74f335374715b70010f0fbef2a6697ce9402ec2a7485b7b45022100ca763fe60a93e03041df55c7020221d7c621849f8196126845d6d251e3bfd6b2', 'hex') + } + }; + }, + type: 'webauthn.create', + }; + + const result = parseClientExtensionResults(credential); + + expect(result).toMatchObject({ + devicePubKey: { + authenticatorOutput: 'pmNkcGtYTaUBAgMmIAEhWCBsJBEpDy9dwNWQwl7Z9LlkWpS7jsuiN3dlsQPa1cmSQyJYIMELKrYFHgYQOI0_LXWmJLlEVPT1GUiz3MbzS3UY8kVSY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA', + signature: 'MEUCIHisAT4zF163TzNTdHFbcAEPD77ypml86UAuwqdIW3tFAiEAynY_5gqT4DBB31XHAgIh18YhhJ-BlhJoRdbSUeO_1rI' + } + }); +}); diff --git a/packages/browser/src/helpers/parseClientExtensionResults.ts b/packages/browser/src/helpers/parseClientExtensionResults.ts new file mode 100644 index 00000000..83e9d614 --- /dev/null +++ b/packages/browser/src/helpers/parseClientExtensionResults.ts @@ -0,0 +1,32 @@ +import { + AuthenticationExtensionsClientOutputsJSON, + AuthenticationExtensionsClientOutputsFuture, + RegistrationCredential, + AuthenticationCredential +} from "@simplewebauthn/typescript-types"; +import { bufferToBase64URLString } from "./bufferToBase64URLString"; + +export function parseClientExtensionResults( + credential: AuthenticationCredential | RegistrationCredential +): AuthenticationExtensionsClientOutputsJSON { + const clientExtensionResults: AuthenticationExtensionsClientOutputsFuture = credential.getClientExtensionResults() + const clientExtensionResultsJSON: AuthenticationExtensionsClientOutputsJSON = {}; + + for (const key in clientExtensionResults) { + if (key === 'appid') { + clientExtensionResultsJSON.appid = clientExtensionResults.appid; + } else if (key === 'credProps') { + clientExtensionResultsJSON.credProps = clientExtensionResults.credProps; + } else if (key === 'devicePubKey') { + const { devicePubKey } = clientExtensionResults; + if (!devicePubKey) continue; + const authenticatorOutput = bufferToBase64URLString(devicePubKey.authenticatorOutput); + const signature = bufferToBase64URLString(devicePubKey.signature); + clientExtensionResultsJSON.devicePubKey = { authenticatorOutput, signature }; + } else if (key === 'uvm') { + clientExtensionResultsJSON.uvm = clientExtensionResults.uvm; + } + } + + return clientExtensionResultsJSON; +} diff --git a/packages/browser/src/methods/startAuthentication.ts b/packages/browser/src/methods/startAuthentication.ts index 761a96ca..22ececa2 100644 --- a/packages/browser/src/methods/startAuthentication.ts +++ b/packages/browser/src/methods/startAuthentication.ts @@ -12,6 +12,7 @@ import { browserSupportsWebAuthnAutofill } from '../helpers/browserSupportsWebAu import { toPublicKeyCredentialDescriptor } from '../helpers/toPublicKeyCredentialDescriptor'; import { identifyAuthenticationError } from '../helpers/identifyAuthenticationError'; import { webauthnAbortService } from '../helpers/webAuthnAbortService'; +import { parseClientExtensionResults } from '../helpers/parseClientExtensionResults'; /** * Begin authenticator "login" via WebAuthn assertion @@ -104,7 +105,7 @@ export async function startAuthentication( userHandle, }, type, - clientExtensionResults: credential.getClientExtensionResults(), + clientExtensionResults: parseClientExtensionResults(credential), authenticatorAttachment: credential.authenticatorAttachment, }; } diff --git a/packages/browser/src/methods/startRegistration.ts b/packages/browser/src/methods/startRegistration.ts index bc307076..3e094b94 100644 --- a/packages/browser/src/methods/startRegistration.ts +++ b/packages/browser/src/methods/startRegistration.ts @@ -11,6 +11,7 @@ import { browserSupportsWebAuthn } from '../helpers/browserSupportsWebAuthn'; import { toPublicKeyCredentialDescriptor } from '../helpers/toPublicKeyCredentialDescriptor'; import { identifyRegistrationError } from '../helpers/identifyRegistrationError'; import { webauthnAbortService } from '../helpers/webAuthnAbortService'; +import { parseClientExtensionResults } from '../helpers/parseClientExtensionResults'; /** * Begin authenticator "registration" via WebAuthn attestation @@ -63,7 +64,7 @@ export async function startRegistration( clientDataJSON: bufferToBase64URLString(response.clientDataJSON), }, type, - clientExtensionResults: credential.getClientExtensionResults(), + clientExtensionResults: parseClientExtensionResults(credential), authenticatorAttachment: credential.authenticatorAttachment, }; From 3fad254399647bbd5290ef18c11c4892893a8a4d Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Wed, 5 Oct 2022 15:30:41 +0900 Subject: [PATCH 28/37] Update packages/browser/src/helpers/parseClientExtensionResults.ts Co-authored-by: Matthew Miller --- .../helpers/parseClientExtensionResults.ts | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/packages/browser/src/helpers/parseClientExtensionResults.ts b/packages/browser/src/helpers/parseClientExtensionResults.ts index 83e9d614..414590ee 100644 --- a/packages/browser/src/helpers/parseClientExtensionResults.ts +++ b/packages/browser/src/helpers/parseClientExtensionResults.ts @@ -12,20 +12,25 @@ export function parseClientExtensionResults( const clientExtensionResults: AuthenticationExtensionsClientOutputsFuture = credential.getClientExtensionResults() const clientExtensionResultsJSON: AuthenticationExtensionsClientOutputsJSON = {}; - for (const key in clientExtensionResults) { - if (key === 'appid') { - clientExtensionResultsJSON.appid = clientExtensionResults.appid; - } else if (key === 'credProps') { - clientExtensionResultsJSON.credProps = clientExtensionResults.credProps; - } else if (key === 'devicePubKey') { - const { devicePubKey } = clientExtensionResults; - if (!devicePubKey) continue; - const authenticatorOutput = bufferToBase64URLString(devicePubKey.authenticatorOutput); - const signature = bufferToBase64URLString(devicePubKey.signature); - clientExtensionResultsJSON.devicePubKey = { authenticatorOutput, signature }; - } else if (key === 'uvm') { - clientExtensionResultsJSON.uvm = clientExtensionResults.uvm; - } + const { appid, credProps, devicePubKey, uvm } = clientExtensionResults; + + if (appid) { + clientExtensionResultsJSON.appid = appid; + } + + if (credProps) { + clientExtensionResultsJSON.credProps = credProps; + } + + if (uvm) { + clientExtensionResultsJSON.uvm = clientExtensionResults.uvm; + } + + if (devicePubKey) { + clientExtensionResultsJSON.devicePubKey = { + authenticatorOutput: bufferToBase64URLString(devicePubKey.authenticatorOutput), + signature: bufferToBase64URLString(devicePubKey.signature), + }; } return clientExtensionResultsJSON; From 72f5f649c263d6ad756b9858ea9ec898f1b81fcd Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Wed, 5 Oct 2022 15:34:27 +0900 Subject: [PATCH 29/37] Revert package-lock.json --- package-lock.json | 1087 +++++++-------------------------------------- 1 file changed, 159 insertions(+), 928 deletions(-) diff --git a/package-lock.json b/package-lock.json index 64e95a65..15096cd4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,28 +5,6 @@ "packages": { "": { "name": "simplewebauthn-monorepo", - "dependencies": { - "@noble/ed25519": "^1.6.1", - "@peculiar/asn1-android": "^2.1.7", - "@peculiar/asn1-schema": "^2.1.7", - "@peculiar/asn1-x509": "^2.1.7", - "@rollup/plugin-node-resolve": "^13.0.0", - "@rollup/plugin-typescript": "^8.2.1", - "@types/cbor": "^5.0.1", - "@types/debug": "^4.1.7", - "@types/jsrsasign": "^8.0.13", - "@types/jwk-to-pem": "^2.0.1", - "@types/node-fetch": "^2.5.12", - "base64url": "^3.0.1", - "cbor": "^5.1.0", - "debug": "^4.3.2", - "jsrsasign": "^10.4.0", - "jwk-to-pem": "^2.0.4", - "node-fetch": "^2.6.0", - "rollup": "^2.52.1", - "rollup-plugin-terser": "^7.0.2", - "rollup-plugin-version-injector": "^1.3.3" - }, "devDependencies": { "@types/express": "^4.17.9", "@types/jest": "^27.0.1", @@ -67,6 +45,7 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, "dependencies": { "@babel/highlight": "^7.10.4" } @@ -297,6 +276,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "dev": true, "engines": { "node": ">=6.9.0" } @@ -328,6 +308,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", @@ -341,6 +322,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -352,6 +334,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -365,6 +348,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -372,12 +356,14 @@ "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, "engines": { "node": ">=0.8.0" } @@ -386,6 +372,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, "engines": { "node": ">=4" } @@ -394,6 +381,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -1046,6 +1034,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, "engines": { "node": ">=6.0.0" } @@ -1054,28 +1043,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, + "dev": true, "engines": { "node": ">=6.0.0" } @@ -1083,12 +1051,14 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.15", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -2113,17 +2083,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@noble/ed25519": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.0.tgz", - "integrity": "sha512-LeAxFK0+181zQOhOUuKE8Jnd3duzYhDNd3iCLxpmzA5K+e4I1FdbrK3Ot0ZHBwZMeRD/6EojyUfTbpHZ+hkQHg==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2625,95 +2584,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@peculiar/asn1-android": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.3.0.tgz", - "integrity": "sha512-ooQ6zRxSXcJ7IW6y7rd3DztgGwzJ3Esq28ideiVwj1hmkPHwqhoRvgHoeddOUQds9GHiwDN5uM/fufnTOxrG2A==", - "dependencies": { - "@peculiar/asn1-schema": "^2.3.0", - "asn1js": "^3.0.5", - "tslib": "^2.4.0" - } - }, - "node_modules/@peculiar/asn1-schema": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.0.tgz", - "integrity": "sha512-DtNLAG4vmDrdSJFPe7rypkcj597chNQL7u+2dBtYo5mh7VW2+im6ke+O0NVr8W1f4re4C3F71LhoMb0Yxqa48Q==", - "dependencies": { - "asn1js": "^3.0.5", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@peculiar/asn1-x509": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.3.0.tgz", - "integrity": "sha512-iDRNPHAx/HLwR9wN5xaHDPifpdSW/bquu+zo/kQXurnxg6KQ1jcZw+4a63uTvrzyGU/hHzDqjalG/sQvV02lAw==", - "dependencies": { - "@peculiar/asn1-schema": "^2.3.0", - "asn1js": "^3.0.5", - "ipaddr.js": "^2.0.1", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz", - "integrity": "sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==", - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "deepmerge": "^4.2.2", - "is-builtin-module": "^3.1.0", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^2.42.0" - } - }, - "node_modules/@rollup/plugin-typescript": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.5.0.tgz", - "integrity": "sha512-wMv1/scv0m/rXx21wD2IsBbJFba8wGF3ErJIr6IKRfRj49S85Lszbxb4DCo8iILpluTjk2GAAu9CoZt4G3ppgQ==", - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "resolve": "^1.17.0" - }, - "engines": { - "node": ">=8.0.0" - }, - "peerDependencies": { - "rollup": "^2.14.0", - "tslib": "*", - "typescript": ">=3.7.0" - }, - "peerDependenciesMeta": { - "tslib": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, "node_modules/@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -2828,14 +2698,6 @@ "@types/node": "*" } }, - "node_modules/@types/cbor": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/cbor/-/cbor-5.0.1.tgz", - "integrity": "sha512-zVqJy2KzusZPLOgyGJDnOIbu3DxIGGqxYbEwtEEe4Z+la8jwIhOyb+GMrlHafs5tvKruwf8f8qOYP6zTvse/pw==", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -2845,19 +2707,6 @@ "@types/node": "*" } }, - "node_modules/@types/debug": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", - "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" - }, "node_modules/@types/express": { "version": "4.17.13", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", @@ -2936,16 +2785,6 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, - "node_modules/@types/jsrsasign": { - "version": "8.0.13", - "resolved": "https://registry.npmjs.org/@types/jsrsasign/-/jsrsasign-8.0.13.tgz", - "integrity": "sha512-+0Ij59D6NXP48KkeLhPXeQKOyLjvA9CD7zacc0Svy2IWHdl62BmDeTvGSIwKaGZSoamLJOo+on1AG/wPRLsd7A==" - }, - "node_modules/@types/jwk-to-pem": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/jwk-to-pem/-/jwk-to-pem-2.0.1.tgz", - "integrity": "sha512-QXmRPhR/LPzvXBHTPfG2BBfMTkNLUD7NyRcPft8m5xFCeANa1BZyLgT0Gw+OxdWx6i1WCpT27EqyggP4UUHMrA==" - }, "node_modules/@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", @@ -2964,24 +2803,11 @@ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, - "node_modules/@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" - }, "node_modules/@types/node": { "version": "18.7.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz", - "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==" - }, - "node_modules/@types/node-fetch": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", - "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", - "dependencies": { - "@types/node": "*", - "form-data": "^3.0.0" - } + "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==", + "dev": true }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -3013,14 +2839,6 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", @@ -3435,6 +3253,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -3531,30 +3350,6 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "dev": true }, - "node_modules/asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/asn1js": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", - "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", - "dependencies": { - "pvtsutils": "^1.3.2", - "pvutils": "^1.1.3", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -3567,7 +3362,8 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true }, "node_modules/at-least-node": { "version": "1.0.0", @@ -3696,28 +3492,12 @@ } ] }, - "node_modules/base64url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", - "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/before-after-hook": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==", "dev": true }, - "node_modules/bignumber.js": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.0.tgz", - "integrity": "sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A==", - "engines": { - "node": "*" - } - }, "node_modules/bin-links": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-3.0.3.tgz", @@ -3777,11 +3557,6 @@ "readable-stream": "^3.4.0" } }, - "node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3804,11 +3579,6 @@ "node": ">=8" } }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" - }, "node_modules/browser-process-hrtime": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", @@ -3891,18 +3661,8 @@ "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true }, "node_modules/builtins": { "version": "5.0.1", @@ -4042,22 +3802,11 @@ } ] }, - "node_modules/cbor": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", - "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", - "dependencies": { - "bignumber.js": "^9.0.1", - "nofilter": "^1.0.4" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -4274,6 +4023,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -4284,7 +4034,8 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/color-support": { "version": "1.1.3", @@ -4318,6 +4069,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -4644,6 +4396,7 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -4718,6 +4471,7 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -4744,6 +4498,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, "engines": { "node": ">=0.4.0" } @@ -4896,20 +4651,6 @@ "integrity": "sha512-gEM2awN5HZknWdLbngk4uQCVfhucFAfFzuchP3wM3NN6eow1eDU0dFy2kts43FB20ZfhVFF0jmFSTb1h5OhyIg==", "dev": true }, - "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "node_modules/emittery": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", @@ -4932,6 +4673,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -4941,6 +4683,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -5344,11 +5087,6 @@ "node": ">=4.0" } }, - "node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -5570,6 +5308,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -5622,6 +5361,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -5634,7 +5374,8 @@ "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true }, "node_modules/functional-red-black-tree": { "version": "1.0.1", @@ -5971,6 +5712,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, "dependencies": { "function-bind": "^1.1.1" }, @@ -5982,6 +5724,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "engines": { "node": ">=8" } @@ -5992,25 +5735,6 @@ "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", "dev": true }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "node_modules/hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -6265,7 +5989,8 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "node_modules/ini": { "version": "1.3.8", @@ -6350,14 +6075,6 @@ "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", "dev": true }, - "node_modules/ipaddr.js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", - "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", - "engines": { - "node": ">= 10" - } - }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -6376,20 +6093,6 @@ "node": ">=8" } }, - "node_modules/is-builtin-module": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", - "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-ci": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", @@ -6412,6 +6115,7 @@ "version": "2.10.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "dev": true, "dependencies": { "has": "^1.0.3" }, @@ -6488,11 +6192,6 @@ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "dev": true }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -7331,7 +7030,8 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "node_modules/js-yaml": { "version": "3.14.1", @@ -7510,14 +7210,6 @@ "node": "*" } }, - "node_modules/jsrsasign": { - "version": "10.5.27", - "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.5.27.tgz", - "integrity": "sha512-1F4LmDeJZHYwoVvB44jEo2uZL3XuwYNzXCDOu53Ui6vqofGQ/gCYDmaxfVZtN0TGd92UKXr/BONcfrPonUIcQQ==", - "funding": { - "url": "https://github.com/kjur/jsrsasign#donations" - } - }, "node_modules/just-diff": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-5.1.1.tgz", @@ -7530,16 +7222,6 @@ "integrity": "sha512-AAV5Jw7tsniWwih8Ly3fXxEZ06y+6p5TwQMsw0dzZ/wPKilzyDgdAnL0Ug4NNIquPUOh1vfFWEHbmXUqM5+o8g==", "dev": true }, - "node_modules/jwk-to-pem": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz", - "integrity": "sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==", - "dependencies": { - "asn1.js": "^5.3.0", - "elliptic": "^6.5.4", - "safe-buffer": "^5.0.1" - } - }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -7835,7 +7517,8 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true }, "node_modules/lodash.ismatch": { "version": "4.4.0", @@ -8171,7 +7854,8 @@ "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true }, "node_modules/merge2": { "version": "1.4.1", @@ -8199,6 +7883,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, "engines": { "node": ">= 0.6" } @@ -8207,6 +7892,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -8232,16 +7918,6 @@ "node": ">=4" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -8412,7 +8088,8 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "node_modules/multimatch": { "version": "5.0.0", @@ -8479,6 +8156,7 @@ "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -8497,17 +8175,20 @@ "node_modules/node-fetch/node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true }, "node_modules/node-fetch/node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true }, "node_modules/node-fetch/node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -8560,14 +8241,6 @@ "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", "dev": true }, - "node_modules/nofilter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz", - "integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==", - "engines": { - "node": ">=8" - } - }, "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -9501,7 +9174,8 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true }, "node_modules/path-type": { "version": "4.0.0", @@ -9522,6 +9196,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "engines": { "node": ">=8.6" }, @@ -9731,22 +9406,6 @@ "node": ">=6" } }, - "node_modules/pvtsutils": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.2.tgz", - "integrity": "sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/pvutils": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", - "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -9786,14 +9445,6 @@ "node": ">=8" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -10189,6 +9840,7 @@ "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, "dependencies": { "is-core-module": "^2.9.0", "path-parse": "^1.0.7", @@ -10293,65 +9945,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rollup": { - "version": "2.79.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.0.tgz", - "integrity": "sha512-x4KsrCgwQ7ZJPcFA/SUu6QVcYlO7uRLfLAy0DSA4NS2eG8japdbpM50ToH7z4iObodRYOJ0soneF0iaQRJ6zhA==", - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0" - } - }, - "node_modules/rollup-plugin-terser/node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/rollup-plugin-version-injector": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rollup-plugin-version-injector/-/rollup-plugin-version-injector-1.3.3.tgz", - "integrity": "sha512-+Rrf0xIFHkwFGuMfphVlAOtd9FlhHFh3vrDwamJ6+YR3IxebRHGVT879qwWzZ1CpWMCLlngb2MmHW5wC5EJqvg==", - "dependencies": { - "chalk": "^4.1.0", - "dateformat": "^4.2.1", - "lodash": "^4.17.20" - } - }, - "node_modules/rollup-plugin-version-injector/node_modules/dateformat": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", - "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", - "engines": { - "node": "*" - } - }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -10396,12 +9989,14 @@ "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true }, "node_modules/saxes": { "version": "5.0.1", @@ -10448,14 +10043,6 @@ "node": ">=10" } }, - "node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -10607,6 +10194,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -10615,6 +10203,7 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -10875,6 +10464,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -10899,6 +10489,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -11025,39 +10616,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/terser": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz", - "integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==", - "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser/node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -11353,7 +10911,8 @@ "node_modules/tslib": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true }, "node_modules/tsutils": { "version": "3.21.0", @@ -11499,6 +11058,7 @@ "version": "4.7.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -12095,6 +11655,7 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, "requires": { "@babel/highlight": "^7.10.4" } @@ -12272,7 +11833,8 @@ "@babel/helper-validator-identifier": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "dev": true }, "@babel/helper-validator-option": { "version": "7.18.6", @@ -12295,6 +11857,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", @@ -12305,6 +11868,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -12313,6 +11877,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -12323,6 +11888,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "requires": { "color-name": "1.1.3" } @@ -12330,22 +11896,26 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -12861,43 +12431,26 @@ "@jridgewell/resolve-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true }, "@jridgewell/set-array": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" - }, - "@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true }, "@jridgewell/sourcemap-codec": { "version": "1.4.14", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true }, "@jridgewell/trace-mapping": { "version": "0.3.15", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "dev": true, "requires": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -13740,11 +13293,6 @@ } } }, - "@noble/ed25519": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.0.tgz", - "integrity": "sha512-LeAxFK0+181zQOhOUuKE8Jnd3duzYhDNd3iCLxpmzA5K+e4I1FdbrK3Ot0ZHBwZMeRD/6EojyUfTbpHZ+hkQHg==" - }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -14141,70 +13689,6 @@ "node-gyp-build": "^4.3.0" } }, - "@peculiar/asn1-android": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.3.0.tgz", - "integrity": "sha512-ooQ6zRxSXcJ7IW6y7rd3DztgGwzJ3Esq28ideiVwj1hmkPHwqhoRvgHoeddOUQds9GHiwDN5uM/fufnTOxrG2A==", - "requires": { - "@peculiar/asn1-schema": "^2.3.0", - "asn1js": "^3.0.5", - "tslib": "^2.4.0" - } - }, - "@peculiar/asn1-schema": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.0.tgz", - "integrity": "sha512-DtNLAG4vmDrdSJFPe7rypkcj597chNQL7u+2dBtYo5mh7VW2+im6ke+O0NVr8W1f4re4C3F71LhoMb0Yxqa48Q==", - "requires": { - "asn1js": "^3.0.5", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" - } - }, - "@peculiar/asn1-x509": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.3.0.tgz", - "integrity": "sha512-iDRNPHAx/HLwR9wN5xaHDPifpdSW/bquu+zo/kQXurnxg6KQ1jcZw+4a63uTvrzyGU/hHzDqjalG/sQvV02lAw==", - "requires": { - "@peculiar/asn1-schema": "^2.3.0", - "asn1js": "^3.0.5", - "ipaddr.js": "^2.0.1", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" - } - }, - "@rollup/plugin-node-resolve": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz", - "integrity": "sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==", - "requires": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "deepmerge": "^4.2.2", - "is-builtin-module": "^3.1.0", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - } - }, - "@rollup/plugin-typescript": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.5.0.tgz", - "integrity": "sha512-wMv1/scv0m/rXx21wD2IsBbJFba8wGF3ErJIr6IKRfRj49S85Lszbxb4DCo8iILpluTjk2GAAu9CoZt4G3ppgQ==", - "requires": { - "@rollup/pluginutils": "^3.1.0", - "resolve": "^1.17.0" - } - }, - "@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "requires": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - } - }, "@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -14316,14 +13800,6 @@ "@types/node": "*" } }, - "@types/cbor": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/cbor/-/cbor-5.0.1.tgz", - "integrity": "sha512-zVqJy2KzusZPLOgyGJDnOIbu3DxIGGqxYbEwtEEe4Z+la8jwIhOyb+GMrlHafs5tvKruwf8f8qOYP6zTvse/pw==", - "requires": { - "@types/node": "*" - } - }, "@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -14333,19 +13809,6 @@ "@types/node": "*" } }, - "@types/debug": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", - "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", - "requires": { - "@types/ms": "*" - } - }, - "@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" - }, "@types/express": { "version": "4.17.13", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", @@ -14424,16 +13887,6 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, - "@types/jsrsasign": { - "version": "8.0.13", - "resolved": "https://registry.npmjs.org/@types/jsrsasign/-/jsrsasign-8.0.13.tgz", - "integrity": "sha512-+0Ij59D6NXP48KkeLhPXeQKOyLjvA9CD7zacc0Svy2IWHdl62BmDeTvGSIwKaGZSoamLJOo+on1AG/wPRLsd7A==" - }, - "@types/jwk-to-pem": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/jwk-to-pem/-/jwk-to-pem-2.0.1.tgz", - "integrity": "sha512-QXmRPhR/LPzvXBHTPfG2BBfMTkNLUD7NyRcPft8m5xFCeANa1BZyLgT0Gw+OxdWx6i1WCpT27EqyggP4UUHMrA==" - }, "@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", @@ -14452,24 +13905,11 @@ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, - "@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" - }, "@types/node": { "version": "18.7.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz", - "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==" - }, - "@types/node-fetch": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", - "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", - "requires": { - "@types/node": "*", - "form-data": "^3.0.0" - } + "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==", + "dev": true }, "@types/normalize-package-data": { "version": "2.4.1", @@ -14501,14 +13941,6 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, - "@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "requires": { - "@types/node": "*" - } - }, "@types/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", @@ -14790,6 +14222,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -14865,27 +14298,6 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "dev": true }, - "asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - } - }, - "asn1js": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", - "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", - "requires": { - "pvtsutils": "^1.3.2", - "pvutils": "^1.1.3", - "tslib": "^2.4.0" - } - }, "astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -14895,7 +14307,8 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true }, "at-least-node": { "version": "1.0.0", @@ -14986,22 +14399,12 @@ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true }, - "base64url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", - "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" - }, "before-after-hook": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==", "dev": true }, - "bignumber.js": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.0.tgz", - "integrity": "sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A==" - }, "bin-links": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-3.0.3.tgz", @@ -15051,11 +14454,6 @@ "readable-stream": "^3.4.0" } }, - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -15075,11 +14473,6 @@ "fill-range": "^7.0.1" } }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" - }, "browser-process-hrtime": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", @@ -15129,12 +14522,8 @@ "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==" + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true }, "builtins": { "version": "5.0.1", @@ -15239,19 +14628,11 @@ "integrity": "sha512-I5XeHI1x/mRSGl96LFOaSk528LA/yZG3m3iQgImGujjO8gotd/DL8QaI1R1h1dg5ATeI2jqPblMpKq4Tr5iKfQ==", "dev": true }, - "cbor": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", - "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", - "requires": { - "bignumber.js": "^9.0.1", - "nofilter": "^1.0.4" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -15410,6 +14791,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "requires": { "color-name": "~1.1.4" } @@ -15417,7 +14799,8 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "color-support": { "version": "1.1.3", @@ -15445,6 +14828,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -15714,6 +15098,7 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, "requires": { "ms": "2.1.2" } @@ -15769,7 +15154,8 @@ "deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true }, "defaults": { "version": "1.0.3", @@ -15789,7 +15175,8 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true }, "delegates": { "version": "1.0.0", @@ -15905,20 +15292,6 @@ "integrity": "sha512-gEM2awN5HZknWdLbngk4uQCVfhucFAfFzuchP3wM3NN6eow1eDU0dFy2kts43FB20ZfhVFF0jmFSTb1h5OhyIg==", "dev": true }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "emittery": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", @@ -15935,6 +15308,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, "optional": true, "requires": { "iconv-lite": "^0.6.2" @@ -15944,6 +15318,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -16245,11 +15620,6 @@ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, - "estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" - }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -16428,6 +15798,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -16471,12 +15842,14 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, "optional": true }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true }, "functional-red-black-tree": { "version": "1.0.1", @@ -16736,6 +16109,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -16743,7 +16117,8 @@ "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true }, "has-unicode": { "version": "2.0.1", @@ -16751,25 +16126,6 @@ "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", "dev": true }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -16954,7 +16310,8 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "ini": { "version": "1.3.8", @@ -17029,11 +16386,6 @@ "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", "dev": true }, - "ipaddr.js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", - "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==" - }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -17049,14 +16401,6 @@ "binary-extensions": "^2.0.0" } }, - "is-builtin-module": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", - "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", - "requires": { - "builtin-modules": "^3.3.0" - } - }, "is-ci": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", @@ -17078,6 +16422,7 @@ "version": "2.10.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "dev": true, "requires": { "has": "^1.0.3" } @@ -17127,11 +16472,6 @@ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "dev": true }, - "is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" - }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -17783,7 +17123,8 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "js-yaml": { "version": "3.14.1", @@ -17918,11 +17259,6 @@ "through": ">=2.2.7 <3" } }, - "jsrsasign": { - "version": "10.5.27", - "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.5.27.tgz", - "integrity": "sha512-1F4LmDeJZHYwoVvB44jEo2uZL3XuwYNzXCDOu53Ui6vqofGQ/gCYDmaxfVZtN0TGd92UKXr/BONcfrPonUIcQQ==" - }, "just-diff": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-5.1.1.tgz", @@ -17935,16 +17271,6 @@ "integrity": "sha512-AAV5Jw7tsniWwih8Ly3fXxEZ06y+6p5TwQMsw0dzZ/wPKilzyDgdAnL0Ug4NNIquPUOh1vfFWEHbmXUqM5+o8g==", "dev": true }, - "jwk-to-pem": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz", - "integrity": "sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==", - "requires": { - "asn1.js": "^5.3.0", - "elliptic": "^6.5.4", - "safe-buffer": "^5.0.1" - } - }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -18179,7 +17505,8 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true }, "lodash.ismatch": { "version": "4.4.0", @@ -18443,7 +17770,8 @@ "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true }, "merge2": { "version": "1.4.1", @@ -18464,12 +17792,14 @@ "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true }, "mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, "requires": { "mime-db": "1.52.0" } @@ -18486,16 +17816,6 @@ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" - }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -18625,7 +17945,8 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "multimatch": { "version": "5.0.0", @@ -18682,6 +18003,7 @@ "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, "requires": { "whatwg-url": "^5.0.0" }, @@ -18689,17 +18011,20 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -18743,11 +18068,6 @@ "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", "dev": true }, - "nofilter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz", - "integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==" - }, "nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -19461,7 +18781,8 @@ "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true }, "path-type": { "version": "4.0.0", @@ -19478,7 +18799,8 @@ "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true }, "pify": { "version": "5.0.0", @@ -19630,19 +18952,6 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, - "pvtsutils": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.2.tgz", - "integrity": "sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==", - "requires": { - "tslib": "^2.4.0" - } - }, - "pvutils": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", - "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==" - }, "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -19661,14 +18970,6 @@ "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -19977,6 +19278,7 @@ "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, "requires": { "is-core-module": "^2.9.0", "path-parse": "^1.0.7", @@ -20049,54 +19351,6 @@ "glob": "^7.1.3" } }, - "rollup": { - "version": "2.79.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.0.tgz", - "integrity": "sha512-x4KsrCgwQ7ZJPcFA/SUu6QVcYlO7uRLfLAy0DSA4NS2eG8japdbpM50ToH7z4iObodRYOJ0soneF0iaQRJ6zhA==", - "requires": { - "fsevents": "~2.3.2" - } - }, - "rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "requires": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - }, - "dependencies": { - "jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - } - } - } - }, - "rollup-plugin-version-injector": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rollup-plugin-version-injector/-/rollup-plugin-version-injector-1.3.3.tgz", - "integrity": "sha512-+Rrf0xIFHkwFGuMfphVlAOtd9FlhHFh3vrDwamJ6+YR3IxebRHGVT879qwWzZ1CpWMCLlngb2MmHW5wC5EJqvg==", - "requires": { - "chalk": "^4.1.0", - "dateformat": "^4.2.1", - "lodash": "^4.17.20" - }, - "dependencies": { - "dateformat": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", - "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==" - } - } - }, "run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -20124,12 +19378,14 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true }, "saxes": { "version": "5.0.1", @@ -20166,14 +19422,6 @@ "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", "dev": true }, - "serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "requires": { - "randombytes": "^2.1.0" - } - }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -20291,12 +19539,14 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true }, "source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -20498,6 +19748,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -20515,7 +19766,8 @@ "supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true }, "symbol-tree": { "version": "3.2.4", @@ -20610,29 +19862,6 @@ "supports-hyperlinks": "^2.0.0" } }, - "terser": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz", - "integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==", - "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "dependencies": { - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==" - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - } - } - }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -20840,7 +20069,8 @@ "tslib": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true }, "tsutils": { "version": "3.21.0", @@ -20951,7 +20181,8 @@ "typescript": { "version": "4.7.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==" + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true }, "uglify-js": { "version": "3.17.2", From edca70e07a4dfa9b69082b19d69c8a19a83d441a Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Wed, 5 Oct 2022 16:10:30 +0900 Subject: [PATCH 30/37] Update packages/server/src/authentication/verifyAuthenticationResponse.ts Co-authored-by: Matthew Miller --- .../server/src/authentication/verifyAuthenticationResponse.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.ts b/packages/server/src/authentication/verifyAuthenticationResponse.ts index 124ae114..7b86ae05 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.ts @@ -209,7 +209,7 @@ export async function verifyAuthenticationResponse( if (flags.ed) { if (!clientExtensionResults) { throw new Error('Authenticator data indicated extension data was present,'+ - ' but no client extension data were found'); + ' but no authenticator extension data were found'); } // TODO: Find a good way to check that returned extension outputs match what From efe0c41bc2498b965a25ab094d1babd2c5b0a038 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Wed, 5 Oct 2022 16:29:06 +0900 Subject: [PATCH 31/37] Reflect feedback --- .../authentication/verifyAuthenticationResponse.ts | 11 +++-------- .../extensions/devicePublicKey/isRecognizedDevice.ts | 6 ++---- .../src/registration/verifyRegistrationResponse.ts | 7 +------ 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.ts b/packages/server/src/authentication/verifyAuthenticationResponse.ts index 7b86ae05..9e8798cf 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.ts @@ -206,12 +206,7 @@ export async function verifyAuthenticationResponse( const extensionOutputs: AuthenticationExtensionOutputs = {}; - if (flags.ed) { - if (!clientExtensionResults) { - throw new Error('Authenticator data indicated extension data was present,'+ - ' but no authenticator extension data were found'); - } - + if (clientExtensionResults) { // TODO: Find a good way to check that returned extension outputs match what // was requested in extension inputs. See 7.1 step 18 in the spec. @@ -219,8 +214,8 @@ export async function verifyAuthenticationResponse( // extension results. if (clientExtensionResults.devicePubKey) { const devicePubKey = decodeDevicePubKey(clientExtensionResults.devicePubKey); - const { authenticatorOutput: encodedAuthenticatorOutput, signature } = devicePubKey; - const dpkAuthOutput = decodeDevicePubKeyAuthenticatorOutput(encodedAuthenticatorOutput); + const { authenticatorOutput, signature } = devicePubKey; + const dpkAuthOutput = decodeDevicePubKeyAuthenticatorOutput(authenticatorOutput); const dpkOptions: VerifyDevicePublicKeySignatureOpts = { credential, diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts index e314b1f5..a2f89d86 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts @@ -81,13 +81,11 @@ export async function isRecognizedDevice( // Unless thrown, this always returns `true`. checkAttStmtBinaryEquality(responseDevicePublicKey.attStmt, recognizedDPKAttStmt); } catch (err) { - // const _err = err as Error; - // How do we message the error cause? - // throw new Error(`DevicePublicKey attStmt's were not equal: ${_err.message}`); // Otherwise, verify attestation const isValidDPKAttestation = await verifyDevicePublicKeyAttestation(responseDevicePublicKey); if (!isValidDPKAttestation) { - throw new Error('DevicePublicKey attestation could not be verified.'); + const _err = err as Error; + throw new Error(`DevicePublicKey attStmt's were not equal: ${_err.message}`); } } } diff --git a/packages/server/src/registration/verifyRegistrationResponse.ts b/packages/server/src/registration/verifyRegistrationResponse.ts index d7352a97..bb338856 100644 --- a/packages/server/src/registration/verifyRegistrationResponse.ts +++ b/packages/server/src/registration/verifyRegistrationResponse.ts @@ -198,12 +198,7 @@ export async function verifyRegistrationResponse( const extensionOutputs: RegistrationExtensionOutputs = {}; - if (flags.ed) { - if (!clientExtensionResults) { - throw new Error('Authenticator data indicated extension data was present,'+ - ' but no client extension data were found'); - } - + if (clientExtensionResults) { // TODO: Find a good way to check that returned extension outputs match what // was requested in extension inputs. See 7.1 step 18 in the spec. From cacb1657e06e35d435fe3f77ce5d77aa86d76d90 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Thu, 6 Oct 2022 10:59:26 +0900 Subject: [PATCH 32/37] Reflect feedback --- packages/browser/src/methods/startAuthentication.test.ts | 2 +- packages/browser/src/methods/startRegistration.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/browser/src/methods/startAuthentication.test.ts b/packages/browser/src/methods/startAuthentication.test.ts index e112124d..ad7073e7 100644 --- a/packages/browser/src/methods/startAuthentication.test.ts +++ b/packages/browser/src/methods/startAuthentication.test.ts @@ -296,7 +296,7 @@ test('should return authenticatorAttachment if present', async () => { return new Promise(resolve => { resolve({ response: {}, - getClientExtensionResults: () => {}, + getClientExtensionResults: () => ({}), authenticatorAttachment: 'cross-platform', }); }); diff --git a/packages/browser/src/methods/startRegistration.test.ts b/packages/browser/src/methods/startRegistration.test.ts index 2dc11be6..2a09d656 100644 --- a/packages/browser/src/methods/startRegistration.test.ts +++ b/packages/browser/src/methods/startRegistration.test.ts @@ -232,7 +232,7 @@ test('should return authenticatorAttachment if present', async () => { return new Promise(resolve => { resolve({ response: {}, - getClientExtensionResults: () => {}, + getClientExtensionResults: () => ({}), authenticatorAttachment: 'cross-platform', }); }); From 883b49d8bb1e3cbfe4b1c0cb859ffde89a52562e Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Wed, 5 Oct 2022 19:44:59 -0700 Subject: [PATCH 33/37] chore(release): publish v6.3.0-alpha.1 --- lerna.json | 2 +- packages/browser/package.json | 4 ++-- packages/server/package.json | 4 ++-- packages/typescript-types/package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lerna.json b/lerna.json index 4089e083..156acd6d 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "6.3.0-alpha.0", + "version": "6.3.0-alpha.1", "npmClient": "npm", "useNx": true, "command": { diff --git a/packages/browser/package.json b/packages/browser/package.json index b761cfde..52fac22a 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -1,6 +1,6 @@ { "name": "@simplewebauthn/browser", - "version": "6.2.1", + "version": "6.3.0-alpha.1", "description": "SimpleWebAuthn for Browsers", "main": "dist/bundle/index.js", "unpkg": "dist/bundle/index.umd.min.js", @@ -33,7 +33,7 @@ "devDependencies": { "@rollup/plugin-node-resolve": "^13.0.0", "@rollup/plugin-typescript": "^8.2.1", - "@simplewebauthn/typescript-types": "*", + "@simplewebauthn/typescript-types": "^6.3.0-alpha.1", "rollup": "^2.52.1", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-version-injector": "^1.3.3" diff --git a/packages/server/package.json b/packages/server/package.json index 0a7b5cb7..aa656a5f 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@simplewebauthn/server", - "version": "6.3.0-alpha.0", + "version": "6.3.0-alpha.1", "description": "SimpleWebAuthn for Servers", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -60,7 +60,7 @@ }, "gitHead": "33ccf8c6c9add811c87d3089e24156c2342b3498", "devDependencies": { - "@simplewebauthn/typescript-types": "*", + "@simplewebauthn/typescript-types": "^6.3.0-alpha.1", "@types/cbor": "^5.0.1", "@types/debug": "^4.1.7", "@types/jsrsasign": "^8.0.13", diff --git a/packages/typescript-types/package.json b/packages/typescript-types/package.json index c86eeb5f..5444a8b3 100644 --- a/packages/typescript-types/package.json +++ b/packages/typescript-types/package.json @@ -1,6 +1,6 @@ { "name": "@simplewebauthn/typescript-types", - "version": "6.2.1", + "version": "6.3.0-alpha.1", "description": "TypeScript types used by the @simplewebauthn series of libraries", "main": "dist/index.js", "types": "dist/index.d.ts", From de678e74ffc3c6d9ab755fd3678713a66c84fae5 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Thu, 13 Oct 2022 21:05:49 +0900 Subject: [PATCH 34/37] Encode DPK output for simplicity --- .../verifyAuthenticationResponse.test.ts | 27 +++--- .../verifyAuthenticationResponse.ts | 19 ++-- .../decodeDevicePubKey.test.ts | 4 +- .../devicePublicKey/decodeDevicePubKey.ts | 90 ++++++++++++++++++- .../isRecognizedDevice.test.ts | 25 ++++-- .../devicePublicKey/isRecognizedDevice.ts | 16 +++- .../verifyDevicePublicKeyAttestation.ts | 2 +- .../verifyDevicePublicKeySignature.test.ts | 6 +- .../verifyDevicePublicKeySignature.ts | 2 +- packages/server/src/index.ts | 4 + .../verifyRegistrationResponse.test.ts | 8 +- .../verifyRegistrationResponse.ts | 12 +-- 12 files changed, 168 insertions(+), 47 deletions(-) diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts index bfe50f98..ea3eadbe 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts @@ -9,9 +9,7 @@ import { AuthenticationCredentialJSON, } from '@simplewebauthn/typescript-types'; import { - DevicePublicKeyAuthenticatorOutput, - decodeDevicePubKey, - decodeDevicePubKeyAuthenticatorOutput + DevicePublicKeyAuthenticatorOutputJSON, } from '../extensions/devicePublicKey/decodeDevicePubKey'; let mockDecodeClientData: jest.SpyInstance; @@ -350,13 +348,20 @@ if (!DpkAuthCred?.clientExtensionResults?.devicePubKey) { throw new Error('This exception will not happen.'); } -const encodedDevicePubKey = decodeDevicePubKey(DpkAuthCred.clientExtensionResults.devicePubKey); -const sameDevicePubKey = decodeDevicePubKeyAuthenticatorOutput(encodedDevicePubKey.authenticatorOutput); -const differentDevicePubKey: DevicePublicKeyAuthenticatorOutput = { - dpk: Buffer.from('A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', 'hex'), - nonce: Buffer.from('', 'hex'), +const sameDevicePubKey: DevicePublicKeyAuthenticatorOutputJSON = { + dpk: 'pQECAyYgASFYIE3BmJ0MLxBA0B9-wVrFQrFNtUvF6l1X7X9rOD67T6uwIlggW2G32XUvyDaGpA6jyiacF319GPZvInOfUlCqenX2hVs', + nonce: '', scope: 0, - aaguid: Buffer.from('00000000000000000000000000000000', 'hex'), + aaguid: 'AAAAAAAAAAAAAAAAAAAAAA', + fmt: 'none', + attStmt: {} +} + +const differentDevicePubKey: DevicePublicKeyAuthenticatorOutputJSON = { + dpk: 'pQECAyYgASFYIJkaq-2d5Ccant6tiAb53JbW3M0MR2JTpVEEieyDeb5bIlggoJc8_e27eeJ_707nSBZz-zMSUE3cpUNM_SNDHWrSnto', + nonce: '', + scope: 0, + aaguid: 'AAAAAAAAAAAAAAAAAAAAAA', fmt: 'none', attStmt: {}, }; @@ -372,14 +377,14 @@ test('should return the new device public key when no device public key matches' await expect(verifyAuthenticationResponse({ ...DpkVerifyAuthRespOpts, userDevicePublicKeys: [differentDevicePubKey, differentDevicePubKey], - }).then(verification => verification.authenticationInfo.extensionOutputs?.devicePubKeyToStore)).resolves.toMatchObject(sameDevicePubKey); + }).then(verification => verification.authenticationInfo.extensionOutputs?.unregisteredDevicePubKey)).resolves.toMatchObject(sameDevicePubKey); }); test('should return undefined when one device public key matches', async () => { await expect(verifyAuthenticationResponse({ ...DpkVerifyAuthRespOpts, userDevicePublicKeys: [sameDevicePubKey, differentDevicePubKey] - }).then(verification => verification.authenticationInfo.extensionOutputs?.devicePubKeyToStore)).resolves.toBeUndefined(); + }).then(verification => verification.authenticationInfo.extensionOutputs?.unregisteredDevicePubKey)).resolves.toBeUndefined(); }); test('should return credential backup info', async () => { diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.ts b/packages/server/src/authentication/verifyAuthenticationResponse.ts index 9e8798cf..7a26f1c2 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.ts @@ -14,12 +14,13 @@ import { isBase64URLString } from '../helpers/isBase64URLString'; import { parseBackupFlags } from '../helpers/parseBackupFlags'; import { verifyDevicePublicKeySignature, - VerifyDevicePublicKeySignatureOpts + VerifyDevicePublicKeySignatureOpts, } from '../extensions/devicePublicKey/verifyDevicePublicKeySignature'; import { - DevicePublicKeyAuthenticatorOutput, + DevicePublicKeyAuthenticatorOutputJSON, decodeDevicePubKey, - decodeDevicePubKeyAuthenticatorOutput + deserializeDevicePubKeyAuthenticatorOutput, + encodeDevicePubKeyAuthenticatorOutput, } from '../extensions/devicePublicKey/decodeDevicePubKey'; import { isRecognizedDevice } from '../extensions/devicePublicKey/isRecognizedDevice'; @@ -33,7 +34,7 @@ export type VerifyAuthenticationResponseOpts = { advancedFIDOConfig?: { userVerification?: UserVerificationRequirement; }; - userDevicePublicKeys?: DevicePublicKeyAuthenticatorOutput[]; + userDevicePublicKeys?: DevicePublicKeyAuthenticatorOutputJSON[]; }; /** @@ -215,7 +216,7 @@ export async function verifyAuthenticationResponse( if (clientExtensionResults.devicePubKey) { const devicePubKey = decodeDevicePubKey(clientExtensionResults.devicePubKey); const { authenticatorOutput, signature } = devicePubKey; - const dpkAuthOutput = decodeDevicePubKeyAuthenticatorOutput(authenticatorOutput); + const dpkAuthOutput = deserializeDevicePubKeyAuthenticatorOutput(authenticatorOutput); const dpkOptions: VerifyDevicePublicKeySignatureOpts = { credential, @@ -227,8 +228,10 @@ export async function verifyAuthenticationResponse( throw new Error('Invalid device public key signature.'); } - const devicePubKeyToStore = await isRecognizedDevice(dpkAuthOutput, userDevicePublicKeys); - extensionOutputs.devicePubKeyToStore = devicePubKeyToStore; + const unregisteredDevicePubKey = await isRecognizedDevice(dpkAuthOutput, userDevicePublicKeys); + if (unregisteredDevicePubKey) { + extensionOutputs.unregisteredDevicePubKey = encodeDevicePubKeyAuthenticatorOutput(unregisteredDevicePubKey); + } } } @@ -299,5 +302,5 @@ export type VerifiedAuthenticationResponse = { }; export type AuthenticationExtensionOutputs = { - devicePubKeyToStore?: DevicePublicKeyAuthenticatorOutput; + unregisteredDevicePubKey?: DevicePublicKeyAuthenticatorOutputJSON; } diff --git a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.test.ts b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.test.ts index 633d8b8c..a563eedb 100644 --- a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.test.ts +++ b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.test.ts @@ -1,5 +1,5 @@ import { AuthenticationExtensionsDevicePublicKeyOutputs, AuthenticationExtensionsDevicePublicKeyOutputsJSON } from "@simplewebauthn/typescript-types"; -import { decodeDevicePubKey, decodeDevicePubKeyAuthenticatorOutput } from "./decodeDevicePubKey"; +import { decodeDevicePubKey, deserializeDevicePubKeyAuthenticatorOutput } from "./decodeDevicePubKey"; it("should decode device public key client extension output", () => { const devicePubKeyJSON: AuthenticationExtensionsDevicePublicKeyOutputsJSON = { @@ -20,7 +20,7 @@ it("should decode device public key authenticator output", () => { signature: Buffer.from('3045022100d37f62269e010e8b7a87c2cea0c5fe82a6ab88f7ba03225f26ff84f6c503be63022075637b7a5a8db94fb2319b46a72f2142d2ff13eaa6675feb336bb69e15d8c3b0', 'hex'), } - const result = decodeDevicePubKeyAuthenticatorOutput(devicePubKey.authenticatorOutput); + const result = deserializeDevicePubKeyAuthenticatorOutput(devicePubKey.authenticatorOutput); expect(result).toMatchObject({ dpk: Buffer.from('A50102032620012158204DC1989D0C2F1040D01F7EC15AC542B14DB54BC5EA5D57ED7F6B383EBB4FABB02258205B61B7D9752FC83686A40EA3CA269C177D7D18F66F22739F5250AA7A75F6855B', 'hex'), fmt: "none", diff --git a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts index b11a8d33..a6825f57 100644 --- a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts +++ b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts @@ -52,7 +52,7 @@ export function decodeDevicePubKey( * output * @returns JSON based device public key authenticator data */ -export function decodeDevicePubKeyAuthenticatorOutput( +export function deserializeDevicePubKeyAuthenticatorOutput( authenticatorOutput: Buffer, ): DevicePublicKeyAuthenticatorOutput { let toCBOR: DevicePublicKeyAuthenticatorOutput; @@ -65,6 +65,77 @@ export function decodeDevicePubKeyAuthenticatorOutput( return toCBOR; } +export function encodeDevicePubKeyAuthenticatorOutput( + devicePubKey: DevicePublicKeyAuthenticatorOutput +): DevicePublicKeyAuthenticatorOutputJSON { + const base64Aaguid = base64url.encode(devicePubKey.aaguid); + const base64Dpk = base64url.encode(devicePubKey.dpk); + const base64Nonce = devicePubKey.nonce ? base64url.encode(devicePubKey.nonce) : undefined; + + const encodedDevicePubKey: DevicePublicKeyAuthenticatorOutputJSON = { + aaguid: base64Aaguid, + dpk: base64Dpk, + scope: devicePubKey.scope, + nonce: base64Nonce, + fmt: devicePubKey.fmt || 'none', + }; + + encodedDevicePubKey.attStmt = {}; + + if (devicePubKey.fmt !== 'none' && devicePubKey.attStmt) { + const { attStmt } = devicePubKey; + encodedDevicePubKey.attStmt.sig = attStmt.sig ? base64url.encode(attStmt.sig) : ''; + encodedDevicePubKey.attStmt.x5c = []; + if (attStmt.x5c && attStmt.x5c.length > 0) { + for (const x of attStmt.x5c) { + encodedDevicePubKey.attStmt.x5c.push(base64url.encode(x)); + } + } + encodedDevicePubKey.attStmt.response = attStmt.response ? base64url.encode(attStmt.response) : ''; + encodedDevicePubKey.attStmt.certInfo = attStmt.certInfo ? base64url.encode(attStmt.certInfo) : ''; + encodedDevicePubKey.attStmt.pubArea = attStmt.pubArea ? base64url.encode(attStmt.pubArea) : ''; + encodedDevicePubKey.attStmt.alg = attStmt.alg; + encodedDevicePubKey.attStmt.ver = attStmt.ver; + } + + return encodedDevicePubKey; +} + +export function decodeDevicePubKeyAuthenticatorOutput( + encodedDevicePubKey: DevicePublicKeyAuthenticatorOutputJSON +): DevicePublicKeyAuthenticatorOutput { + const aaguid = base64url.toBuffer(encodedDevicePubKey.aaguid); + const dpk = base64url.toBuffer(encodedDevicePubKey.dpk); + const scope = encodedDevicePubKey.scope; + const nonce = encodedDevicePubKey.nonce ? base64url.toBuffer(encodedDevicePubKey.nonce) : Buffer.from('', 'hex'); + const fmt = encodedDevicePubKey.fmt ? encodedDevicePubKey.fmt : 'none'; + + const decodedDevicePubKey: DevicePublicKeyAuthenticatorOutput = { + aaguid, + dpk, + scope, + nonce, + fmt, + attStmt: {} + } + + if (encodedDevicePubKey.fmt !== 'none' && encodedDevicePubKey.attStmt) { + const { attStmt: encodedAttStmt } = encodedDevicePubKey; + decodedDevicePubKey.attStmt.sig = encodedAttStmt.sig ? base64url.toBuffer(encodedAttStmt.sig) : undefined; + decodedDevicePubKey.attStmt.x5c = []; + if (encodedAttStmt.x5c && encodedAttStmt.x5c.length > 0) { + for (const x of encodedAttStmt.x5c) { + decodedDevicePubKey.attStmt.x5c.push(base64url.toBuffer(x)); + } + } + decodedDevicePubKey.attStmt.response = encodedAttStmt.response ? base64url.toBuffer(encodedAttStmt.response) : undefined; + decodedDevicePubKey.attStmt.certInfo = encodedAttStmt.certInfo ? base64url.toBuffer(encodedAttStmt.certInfo) : undefined; + decodedDevicePubKey.attStmt.pubArea = encodedAttStmt.pubArea ? base64url.toBuffer(encodedAttStmt.pubArea) : undefined; + decodedDevicePubKey.attStmt.alg = encodedAttStmt.alg; + decodedDevicePubKey.attStmt.ver = encodedAttStmt.ver; + } + return decodedDevicePubKey; +} export type DevicePublicKeyAuthenticatorOutput = { aaguid: Buffer; dpk: Buffer; @@ -73,3 +144,20 @@ export type DevicePublicKeyAuthenticatorOutput = { attStmt: AttestationStatement; nonce?: Buffer; }; + +export type DevicePublicKeyAuthenticatorOutputJSON = { + aaguid: string; + dpk: string; + scope: number; + nonce?: string; + fmt?: AttestationFormat; + attStmt?: { + sig?: string; + x5c?: string[]; + response?: string; + alg?: number; + ver?: string; + certInfo?: string; + pubArea?: string; + }; +} diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts index 3e5f2506..ccff997a 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts @@ -1,5 +1,8 @@ import { isRecognizedDevice } from './isRecognizedDevice'; -import { DevicePublicKeyAuthenticatorOutput } from './decodeDevicePubKey'; +import { + DevicePublicKeyAuthenticatorOutput, + DevicePublicKeyAuthenticatorOutputJSON, +} from './decodeDevicePubKey'; const devicePubKey: DevicePublicKeyAuthenticatorOutput = { dpk: Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'), @@ -10,12 +13,20 @@ const devicePubKey: DevicePublicKeyAuthenticatorOutput = { attStmt: {}, } -const sameDevicePubKey = devicePubKey; -const differentDevicePubKey: DevicePublicKeyAuthenticatorOutput = { - dpk: Buffer.from('A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', 'hex'), - nonce: Buffer.from('', 'hex'), +const sameDevicePubKey: DevicePublicKeyAuthenticatorOutputJSON = { + dpk: 'pQECAyYgASFYIO3q0_01dpwj00DdwYMKf_IOc1XynRx1qg3CtqwYLqfTIlggNFHcmZKvlGgltEGUX8nRNOF7c6pf6pWANR58k_XTZRM', + nonce: '', scope: 0, - aaguid: Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), + aaguid: 'uT_ZYfLmRi-xIoIAIkfeeA', + fmt: 'none', + attStmt: {}, +} + +const differentDevicePubKey: DevicePublicKeyAuthenticatorOutputJSON = { + dpk: 'pQECAyYgASFYIJkaq-2d5Ccant6tiAb53JbW3M0MR2JTpVEEieyDeb5bIlggoJc8_e27eeJ_707nSBZz-zMSUE3cpUNM_SNDHWrSnto', + nonce: '', + scope: 0, + aaguid: 'uT_ZYfLmRi-xIoIAIkfeeA', fmt: 'none', attStmt: {}, }; @@ -25,7 +36,7 @@ it("should throw when more than two device public key matches", async () => { }); it("should return the new device public key when no device public key matches", async () => { - expect(isRecognizedDevice(devicePubKey, [differentDevicePubKey, differentDevicePubKey])).resolves.toMatchObject(sameDevicePubKey); + expect(isRecognizedDevice(devicePubKey, [differentDevicePubKey, differentDevicePubKey])).resolves.toMatchObject(devicePubKey); }); it("should return undefined when one device public key matches", async () => { diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts index a2f89d86..98972752 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts @@ -1,5 +1,9 @@ import { AttestationStatement } from "@simplewebauthn/typescript-types"; -import { DevicePublicKeyAuthenticatorOutput } from './decodeDevicePubKey'; +import { + DevicePublicKeyAuthenticatorOutput, + DevicePublicKeyAuthenticatorOutputJSON, + decodeDevicePubKeyAuthenticatorOutput, +} from './decodeDevicePubKey'; import { verifyDevicePublicKeyAttestation } from "./verifyDevicePublicKeyAttestation"; /** @@ -13,9 +17,13 @@ import { verifyDevicePublicKeyAttestation } from "./verifyDevicePublicKeyAttesta */ export async function isRecognizedDevice( responseDevicePublicKey: DevicePublicKeyAuthenticatorOutput, - userDevicePublicKeys?: DevicePublicKeyAuthenticatorOutput[] + userDevicePublicKeys?: DevicePublicKeyAuthenticatorOutputJSON[] ): Promise { if (userDevicePublicKeys && userDevicePublicKeys.length > 0) { + // Decode all DPKs + const decodedDPKs = userDevicePublicKeys.map(userDPK => { + return decodeDevicePubKeyAuthenticatorOutput(userDPK); + }); // If the Relying Party's user account mapped to the credential.id in play // (i.e., for the user being authenticated) holds aaguid, dpk and scope // values corresponding to the extracted attObjForDevicePublicKey fields, @@ -23,7 +31,7 @@ export async function isRecognizedDevice( // values and the extracted field values. The Relying Party MAY have more // than one set of {aaguid, dpk, scope} values mapped to the user account // and credential.id pair and each set MUST be checked. - const matchedDPKs = userDevicePublicKeys.filter(userDPK => { + const matchedDPKs = decodedDPKs.filter(userDPK => { if (!responseDevicePublicKey.aaguid.equals(userDPK.aaguid)) { return false; } @@ -45,7 +53,7 @@ export async function isRecognizedDevice( if (matchedDPKs.length === 0) { // This is possibly a new device. - const index = userDevicePublicKeys.findIndex(userDPK => { + const index = decodedDPKs.findIndex(userDPK => { return responseDevicePublicKey.dpk.equals(userDPK.dpk) }); if (index === -1) { diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts index 6a4b2189..069d15cf 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeyAttestation.ts @@ -1,7 +1,7 @@ import { DevicePublicKeyAuthenticatorOutput } from "./decodeDevicePubKey"; /** - * https://pr-preview.s3.amazonaws.com/w3c/webauthn/pull/1663.html#sctn-device-publickey-extension-verification-create + * https://w3c.github.io/webauthn/#sctn-device-publickey-extension-verification-create * 3. Verify that `signature` is a valid signature over the assertion signature * input by the device public key *dpk*. (The signature algorithm is the same * as for the user credential.) diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.test.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.test.ts index 9bb30dad..3d457ebf 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.test.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.test.ts @@ -1,5 +1,5 @@ import { AuthenticationCredentialJSON, RegistrationCredentialJSON } from '@simplewebauthn/typescript-types'; -import { decodeDevicePubKey, decodeDevicePubKeyAuthenticatorOutput } from './decodeDevicePubKey'; +import { decodeDevicePubKey, deserializeDevicePubKeyAuthenticatorOutput } from './decodeDevicePubKey'; import { verifyDevicePublicKeySignature, VerifyDevicePublicKeySignatureOpts } from './verifyDevicePublicKeySignature'; it("should verify a registration response's device public key signature", async () => { @@ -26,7 +26,7 @@ it("should verify a registration response's device public key signature", async const devicePubKey = decodeDevicePubKey(credential.clientExtensionResults.devicePubKey); const { authenticatorOutput: encodedAuthenticatorOutput, signature } = devicePubKey; - const dpkAuthOutput = decodeDevicePubKeyAuthenticatorOutput(encodedAuthenticatorOutput); + const dpkAuthOutput = deserializeDevicePubKeyAuthenticatorOutput(encodedAuthenticatorOutput); const dpkOpts: VerifyDevicePublicKeySignatureOpts = { credential, @@ -62,7 +62,7 @@ it("should verify an authentication response's device public key signature", asy const devicePubKey = decodeDevicePubKey(credential.clientExtensionResults.devicePubKey); const {authenticatorOutput: encodedAuthenticatorOutput, signature } = devicePubKey; - const dpkAuthOutput = decodeDevicePubKeyAuthenticatorOutput(encodedAuthenticatorOutput); + const dpkAuthOutput = deserializeDevicePubKeyAuthenticatorOutput(encodedAuthenticatorOutput); const dpkOpts: VerifyDevicePublicKeySignatureOpts = { credential, diff --git a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts index af6ece27..5549318b 100644 --- a/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts +++ b/packages/server/src/extensions/devicePublicKey/verifyDevicePublicKeySignature.ts @@ -17,7 +17,7 @@ export type VerifyDevicePublicKeySignatureOpts = { }; /** - * https://pr-preview.s3.amazonaws.com/w3c/webauthn/pull/1663.html#sctn-device-publickey-extension-verification-create + * https://w3c.github.io/webauthn/#sctn-device-publickey-extension-verification-create * 3. Verify that `signature` is a valid signature over the assertion signature * input by the device public key *dpk*. (The signature algorithm is the same * as for the user credential.) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index e15054ad..1d8daf0c 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -29,6 +29,9 @@ import type { VerifiedAuthenticationResponse, VerifyAuthenticationResponseOpts, } from './authentication/verifyAuthenticationResponse'; +import type { + DevicePublicKeyAuthenticatorOutputJSON +} from './extensions/devicePublicKey/decodeDevicePubKey'; export type { GenerateRegistrationOptionsOpts, @@ -38,4 +41,5 @@ export type { VerifyAuthenticationResponseOpts, VerifiedRegistrationResponse, VerifiedAuthenticationResponse, + DevicePublicKeyAuthenticatorOutputJSON, }; diff --git a/packages/server/src/registration/verifyRegistrationResponse.test.ts b/packages/server/src/registration/verifyRegistrationResponse.test.ts index ad6e111a..c29a6797 100644 --- a/packages/server/src/registration/verifyRegistrationResponse.test.ts +++ b/packages/server/src/registration/verifyRegistrationResponse.test.ts @@ -611,11 +611,11 @@ const DpkVerifyRegRespOpts: VerifyRegistrationResponseOpts = { test('should return authenticator extension output', async () => { const verification = await verifyRegistrationResponse(DpkVerifyRegRespOpts); expect(verification.registrationInfo?.extensionOutputs).toMatchObject({ - devicePubKeyToStore: { - dpk: Buffer.from('A50102032620012158204DC1989D0C2F1040D01F7EC15AC542B14DB54BC5EA5D57ED7F6B383EBB4FABB02258205B61B7D9752FC83686A40EA3CA269C177D7D18F66F22739F5250AA7A75F6855B', 'hex'), - nonce: Buffer.from('', 'hex'), + unregisteredDevicePubKey: { + dpk: 'pQECAyYgASFYIE3BmJ0MLxBA0B9-wVrFQrFNtUvF6l1X7X9rOD67T6uwIlggW2G32XUvyDaGpA6jyiacF319GPZvInOfUlCqenX2hVs', + nonce: '', scope: 0, - aaguid: Buffer.from('00000000000000000000000000000000', 'hex'), + aaguid: 'AAAAAAAAAAAAAAAAAAAAAA', fmt: 'none', attStmt: {} }, diff --git a/packages/server/src/registration/verifyRegistrationResponse.ts b/packages/server/src/registration/verifyRegistrationResponse.ts index bb338856..eef603cc 100644 --- a/packages/server/src/registration/verifyRegistrationResponse.ts +++ b/packages/server/src/registration/verifyRegistrationResponse.ts @@ -27,9 +27,10 @@ import { verifyAttestationApple } from './verifications/verifyAttestationApple'; import { verifyDevicePublicKeySignature, VerifyDevicePublicKeySignatureOpts } from '../extensions/devicePublicKey/verifyDevicePublicKeySignature'; import { verifyDevicePublicKeyAttestation } from '../extensions/devicePublicKey/verifyDevicePublicKeyAttestation'; import { - DevicePublicKeyAuthenticatorOutput, decodeDevicePubKey, - decodeDevicePubKeyAuthenticatorOutput + deserializeDevicePubKeyAuthenticatorOutput, + encodeDevicePubKeyAuthenticatorOutput, + DevicePublicKeyAuthenticatorOutputJSON, } from '../extensions/devicePublicKey/decodeDevicePubKey'; export type VerifyRegistrationResponseOpts = { @@ -207,7 +208,7 @@ export async function verifyRegistrationResponse( if (clientExtensionResults.devicePubKey) { const devicePubKey = decodeDevicePubKey(clientExtensionResults.devicePubKey); const { authenticatorOutput: encodedAuthenticatorOutput, signature } = devicePubKey; - const dpkAuthOutput = decodeDevicePubKeyAuthenticatorOutput(encodedAuthenticatorOutput); + const dpkAuthOutput = deserializeDevicePubKeyAuthenticatorOutput(encodedAuthenticatorOutput); const dpkOpts: VerifyDevicePublicKeySignatureOpts = { credential, @@ -228,7 +229,8 @@ export async function verifyRegistrationResponse( throw new Error('Invalid device public key attestation.'); } - extensionOutputs.devicePubKeyToStore = dpkAuthOutput; + const unregisteredDevicePubKey = encodeDevicePubKeyAuthenticatorOutput(dpkAuthOutput); + extensionOutputs.unregisteredDevicePubKey = unregisteredDevicePubKey; } } @@ -354,5 +356,5 @@ export type AttestationFormatVerifierOpts = { }; export type RegistrationExtensionOutputs = { - devicePubKeyToStore?: DevicePublicKeyAuthenticatorOutput; + unregisteredDevicePubKey?: DevicePublicKeyAuthenticatorOutputJSON; } From 8d3602fac2ab61c9af52375ff119007274c470cc Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Fri, 14 Oct 2022 07:11:21 +0900 Subject: [PATCH 35/37] Update AuthenticationExtensionsClientInputs --- .../server/src/registration/generateRegistrationOptions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/src/registration/generateRegistrationOptions.ts b/packages/server/src/registration/generateRegistrationOptions.ts index 20b32838..ff6979ba 100644 --- a/packages/server/src/registration/generateRegistrationOptions.ts +++ b/packages/server/src/registration/generateRegistrationOptions.ts @@ -1,6 +1,6 @@ import type { AttestationConveyancePreference, - AuthenticationExtensionsClientInputs, + AuthenticationExtensionsClientInputsFuture, AuthenticatorSelectionCriteria, COSEAlgorithmIdentifier, PublicKeyCredentialCreationOptionsJSON, @@ -22,7 +22,7 @@ export type GenerateRegistrationOptionsOpts = { attestationType?: AttestationConveyancePreference; excludeCredentials?: PublicKeyCredentialDescriptorFuture[]; authenticatorSelection?: AuthenticatorSelectionCriteria; - extensions?: AuthenticationExtensionsClientInputs; + extensions?: AuthenticationExtensionsClientInputsFuture; supportedAlgorithmIDs?: COSEAlgorithmIdentifier[]; }; From 4ce11e703aa62d1c0fa414765b7afe6c860eaae3 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Mon, 21 Nov 2022 19:19:35 +0900 Subject: [PATCH 36/37] DPK related changes: - Output a recognition object in `verifyAuthenticationResponse` - Output a DPK binary instead of JSON in `verifyRegistrationResponse` - Update tests --- .../verifyAuthenticationResponse.test.ts | 161 +++++++++++------- .../verifyAuthenticationResponse.ts | 13 +- .../isRecognizedDevice.test.ts | 29 +++- .../devicePublicKey/isRecognizedDevice.ts | 37 +++- .../verifyRegistrationResponse.test.ts | 75 ++++---- .../verifyRegistrationResponse.ts | 8 +- 6 files changed, 195 insertions(+), 128 deletions(-) diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts index ea3eadbe..506a2884 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts @@ -9,6 +9,7 @@ import { AuthenticationCredentialJSON, } from '@simplewebauthn/typescript-types'; import { + DevicePublicKeyAuthenticatorOutput, DevicePublicKeyAuthenticatorOutputJSON, } from '../extensions/devicePublicKey/decodeDevicePubKey'; @@ -314,77 +315,107 @@ test('should fail verification if custom challenge verifier returns false', asyn ).rejects.toThrow(/custom challenge verifier returned false/i); }); -const DpkAuthCred: AuthenticationCredentialJSON = { - response: { - clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiS05aUmtPRU5KY1dCTzZHX0VjcE1GS2FWRDlham1xNExsZDZJMllJc1c3QSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', - authenticatorData: 'DXX8xWP9p3nbLjQ-6kiYiHWLeFSdSTpP2-oc2WqjHMSdAAAAAKFsZGV2aWNlUHViS2V5WIymY2Rwa1hNpQECAyYgASFYIE3BmJ0MLxBA0B9-wVrFQrFNtUvF6l1X7X9rOD67T6uwIlggW2G32XUvyDaGpA6jyiacF319GPZvInOfUlCqenX2hVtjZm10ZG5vbmVlbm9uY2VAZXNjb3BlAGZhYWd1aWRQAAAAAAAAAAAAAAAAAAAAAGdhdHRTdG10oA==', - signature: 'MEUCIF1LvdGHiW5aq25ZrNVUeZOm7pcS_9a172pkO2C6ILE1AiEA8NYg-ZzOgt1pN0Bqv02t7lWCSMn_IPpvKHdT5Mjv75E=', - userHandle: 'b2FPajFxcmM4MWo3QkFFel9RN2lEakh5RVNlU2RLNDF0Sl92eHpQYWV5UQ==', - }, - id: 'BxYpj3rs5WGW8UVnXsmMzg', - rawId: 'BxYpj3rs5WGW8UVnXsmMzg', - type: 'public-key', - clientExtensionResults: { - devicePubKey: { - 'authenticatorOutput': 'pmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=', - 'signature': 'MEQCIAdwrIjLt7ULTU5OzpnhzvbWJ3srVLoOCYs72Hlw6ugoAiAFl4_jfJJv89cM5qSx8lI_pIXLRIy6lO9N3O8SUjyNKQ==', +describe('device public key related tests', () => { + const DpkAuthCred: AuthenticationCredentialJSON = { + response: { + clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiS05aUmtPRU5KY1dCTzZHX0VjcE1GS2FWRDlham1xNExsZDZJMllJc1c3QSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', + authenticatorData: 'DXX8xWP9p3nbLjQ-6kiYiHWLeFSdSTpP2-oc2WqjHMSdAAAAAKFsZGV2aWNlUHViS2V5WIymY2Rwa1hNpQECAyYgASFYIE3BmJ0MLxBA0B9-wVrFQrFNtUvF6l1X7X9rOD67T6uwIlggW2G32XUvyDaGpA6jyiacF319GPZvInOfUlCqenX2hVtjZm10ZG5vbmVlbm9uY2VAZXNjb3BlAGZhYWd1aWRQAAAAAAAAAAAAAAAAAAAAAGdhdHRTdG10oA==', + signature: 'MEUCIF1LvdGHiW5aq25ZrNVUeZOm7pcS_9a172pkO2C6ILE1AiEA8NYg-ZzOgt1pN0Bqv02t7lWCSMn_IPpvKHdT5Mjv75E=', + userHandle: 'b2FPajFxcmM4MWo3QkFFel9RN2lEakh5RVNlU2RLNDF0Sl92eHpQYWV5UQ==', + }, + id: 'BxYpj3rs5WGW8UVnXsmMzg', + rawId: 'BxYpj3rs5WGW8UVnXsmMzg', + type: 'public-key', + clientExtensionResults: { + devicePubKey: { + 'authenticatorOutput': 'pmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=', + 'signature': 'MEQCIAdwrIjLt7ULTU5OzpnhzvbWJ3srVLoOCYs72Hlw6ugoAiAFl4_jfJJv89cM5qSx8lI_pIXLRIy6lO9N3O8SUjyNKQ==', + } } + }; + + const DpkVerifyAuthRespOpts: VerifyAuthenticationResponseOpts = { + credential: DpkAuthCred, + expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', + expectedRPID: 'try-webauthn.appspot.com', + expectedChallenge: 'KNZRkOENJcWBO6G_EcpMFKaVD9ajmq4Lld6I2YIsW7A', + authenticator: { + credentialID: base64url.toBuffer('BxYpj3rs5WGW8UVnXsmMzg'), + credentialPublicKey: base64url.toBuffer('pQECAyYgASFYIPLEylOIRiI7z7q6zuYjWB9TcOj9yNwmawogQJ4ZKpNAIlggd9ZqIjd30p1tIU6A8ue5wEZl9q/AsKR/leaHFZ/bwWk='), + counter: 0, + }, } -}; -const DpkVerifyAuthRespOpts: VerifyAuthenticationResponseOpts = { - credential: DpkAuthCred, - expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', - expectedRPID: 'try-webauthn.appspot.com', - expectedChallenge: 'KNZRkOENJcWBO6G_EcpMFKaVD9ajmq4Lld6I2YIsW7A', - authenticator: { - credentialID: base64url.toBuffer('BxYpj3rs5WGW8UVnXsmMzg'), - credentialPublicKey: base64url.toBuffer('pQECAyYgASFYIPLEylOIRiI7z7q6zuYjWB9TcOj9yNwmawogQJ4ZKpNAIlggd9ZqIjd30p1tIU6A8ue5wEZl9q/AsKR/leaHFZ/bwWk='), - counter: 0, - }, -} - -if (!DpkAuthCred?.clientExtensionResults?.devicePubKey) { - throw new Error('This exception will not happen.'); -} - -const sameDevicePubKey: DevicePublicKeyAuthenticatorOutputJSON = { - dpk: 'pQECAyYgASFYIE3BmJ0MLxBA0B9-wVrFQrFNtUvF6l1X7X9rOD67T6uwIlggW2G32XUvyDaGpA6jyiacF319GPZvInOfUlCqenX2hVs', - nonce: '', - scope: 0, - aaguid: 'AAAAAAAAAAAAAAAAAAAAAA', - fmt: 'none', - attStmt: {} -} - -const differentDevicePubKey: DevicePublicKeyAuthenticatorOutputJSON = { - dpk: 'pQECAyYgASFYIJkaq-2d5Ccant6tiAb53JbW3M0MR2JTpVEEieyDeb5bIlggoJc8_e27eeJ_707nSBZz-zMSUE3cpUNM_SNDHWrSnto', - nonce: '', - scope: 0, - aaguid: 'AAAAAAAAAAAAAAAAAAAAAA', - fmt: 'none', - attStmt: {}, -}; + if (!DpkAuthCred?.clientExtensionResults?.devicePubKey) { + throw new Error('This exception will not happen.'); + } -test('should throw if multiple device public key matches', async () => { - await expect(verifyAuthenticationResponse({ - ...DpkVerifyAuthRespOpts, - userDevicePublicKeys: [sameDevicePubKey, sameDevicePubKey], - })).rejects.toThrowError(new Error('It is undetermined whether this is a known device.')); -}); + // This DPK is baked into `DpkAuthCred`. + const devicePubKey: DevicePublicKeyAuthenticatorOutput = { + dpk: Buffer.from('a50102032620012158204dc1989d0c2f1040d01f7ec15ac542b14db54bc5ea5d57ed7f6b383ebb4fabb02258205b61b7d9752fc83686a40ea3ca269c177d7d18f66f22739f5250aa7a75f6855b', 'hex'), + nonce: Buffer.from('', 'hex'), + scope: 0, + aaguid: Buffer.from('00000000000000000000000000000000', 'hex'), + fmt: 'none', + attStmt: {} + } -test('should return the new device public key when no device public key matches', async () => { - await expect(verifyAuthenticationResponse({ - ...DpkVerifyAuthRespOpts, - userDevicePublicKeys: [differentDevicePubKey, differentDevicePubKey], - }).then(verification => verification.authenticationInfo.extensionOutputs?.unregisteredDevicePubKey)).resolves.toMatchObject(sameDevicePubKey); -}); + // This is an encoded version of `devicePubKey`. + const devicePubKeyJSON: DevicePublicKeyAuthenticatorOutputJSON = { + dpk: 'pQECAyYgASFYIE3BmJ0MLxBA0B9-wVrFQrFNtUvF6l1X7X9rOD67T6uwIlggW2G32XUvyDaGpA6jyiacF319GPZvInOfUlCqenX2hVs', + nonce: '', + scope: 0, + aaguid: 'AAAAAAAAAAAAAAAAAAAAAA', + fmt: 'none', + attStmt: {} + } -test('should return undefined when one device public key matches', async () => { - await expect(verifyAuthenticationResponse({ - ...DpkVerifyAuthRespOpts, - userDevicePublicKeys: [sameDevicePubKey, differentDevicePubKey] - }).then(verification => verification.authenticationInfo.extensionOutputs?.unregisteredDevicePubKey)).resolves.toBeUndefined(); + // A different DPK example. + const differentDevicePubKey: DevicePublicKeyAuthenticatorOutput = { + dpk: Buffer.from('a5010203262001215820991aabed9de4271a9edead8806f9dc96d6dccd0c476253a5510489ec8379be5b225820a0973cfdedbb79e27fef4ee7481673fb3312504ddca5434cfd23431d6ad29eda', 'hex'), + nonce: Buffer.from('', 'hex'), + scope: 0, + aaguid: Buffer.from('00000000000000000000000000000000', 'hex'), + fmt: 'none', + attStmt: {}, + } + + // This is an encoded version of `differentDevicePubKey`. + const differentDevicePubKeyJSON: DevicePublicKeyAuthenticatorOutputJSON = { + dpk: 'pQECAyYgASFYIJkaq-2d5Ccant6tiAb53JbW3M0MR2JTpVEEieyDeb5bIlggoJc8_e27eeJ_707nSBZz-zMSUE3cpUNM_SNDHWrSnto', + nonce: '', + scope: 0, + aaguid: 'AAAAAAAAAAAAAAAAAAAAAA', + fmt: 'none', + attStmt: {}, + }; + + test('should throw if multiple device public key matches', async () => { + await expect(verifyAuthenticationResponse({ + ...DpkVerifyAuthRespOpts, + userDevicePublicKeys: [devicePubKeyJSON, devicePubKeyJSON], + })).rejects.toThrowError(new Error('It is undetermined whether this is a known device.')); + }); + + test('should return the new device public key when no device public key matches', async () => { + await expect(verifyAuthenticationResponse({ + ...DpkVerifyAuthRespOpts, + userDevicePublicKeys: [differentDevicePubKeyJSON, differentDevicePubKeyJSON], + }).then(verification => verification.authenticationInfo.extensionOutputs?.devicePubKey)).resolves.toMatchObject({ + authenticatorOutput: devicePubKey, + recognitionResult: 'unrecognized' + }); + }); + + test('should return undefined when one device public key matches', async () => { + await expect(verifyAuthenticationResponse({ + ...DpkVerifyAuthRespOpts, + userDevicePublicKeys: [devicePubKeyJSON, differentDevicePubKeyJSON] + }).then(verification => verification.authenticationInfo.extensionOutputs?.devicePubKey)).resolves.toMatchObject({ + authenticatorOutput: devicePubKey, + recognitionResult: 'recognized' + }); + }); }); test('should return credential backup info', async () => { diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.ts b/packages/server/src/authentication/verifyAuthenticationResponse.ts index 7a26f1c2..2cda9bcd 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.ts @@ -20,9 +20,11 @@ import { DevicePublicKeyAuthenticatorOutputJSON, decodeDevicePubKey, deserializeDevicePubKeyAuthenticatorOutput, - encodeDevicePubKeyAuthenticatorOutput, } from '../extensions/devicePublicKey/decodeDevicePubKey'; -import { isRecognizedDevice } from '../extensions/devicePublicKey/isRecognizedDevice'; +import { + isRecognizedDevice, + DevicePublicKeyRecognitionResult +} from '../extensions/devicePublicKey/isRecognizedDevice'; export type VerifyAuthenticationResponseOpts = { credential: AuthenticationCredentialJSON; @@ -228,10 +230,7 @@ export async function verifyAuthenticationResponse( throw new Error('Invalid device public key signature.'); } - const unregisteredDevicePubKey = await isRecognizedDevice(dpkAuthOutput, userDevicePublicKeys); - if (unregisteredDevicePubKey) { - extensionOutputs.unregisteredDevicePubKey = encodeDevicePubKeyAuthenticatorOutput(unregisteredDevicePubKey); - } + extensionOutputs.devicePubKey = await isRecognizedDevice(dpkAuthOutput, userDevicePublicKeys); } } @@ -302,5 +301,5 @@ export type VerifiedAuthenticationResponse = { }; export type AuthenticationExtensionOutputs = { - unregisteredDevicePubKey?: DevicePublicKeyAuthenticatorOutputJSON; + devicePubKey?: DevicePublicKeyRecognitionResult; } diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts index ccff997a..5a97c458 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.test.ts @@ -13,7 +13,7 @@ const devicePubKey: DevicePublicKeyAuthenticatorOutput = { attStmt: {}, } -const sameDevicePubKey: DevicePublicKeyAuthenticatorOutputJSON = { +const devicePubKeyJSON: DevicePublicKeyAuthenticatorOutputJSON = { dpk: 'pQECAyYgASFYIO3q0_01dpwj00DdwYMKf_IOc1XynRx1qg3CtqwYLqfTIlggNFHcmZKvlGgltEGUX8nRNOF7c6pf6pWANR58k_XTZRM', nonce: '', scope: 0, @@ -22,7 +22,16 @@ const sameDevicePubKey: DevicePublicKeyAuthenticatorOutputJSON = { attStmt: {}, } -const differentDevicePubKey: DevicePublicKeyAuthenticatorOutputJSON = { +const differentDevicePubKey: DevicePublicKeyAuthenticatorOutput = { + dpk: Buffer.from('a5010203262001215820991aabed9de4271a9edead8806f9dc96d6dccd0c476253a5510489ec8379be5b225820a0973cfdedbb79e27fef4ee7481673fb3312504ddca5434cfd23431d6ad29eda', 'hex'), + nonce: Buffer.from('', 'hex'), + scope: 0, + aaguid: Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), + fmt: 'none', + attStmt: {}, +}; + +const differentDevicePubKeyJSON: DevicePublicKeyAuthenticatorOutputJSON = { dpk: 'pQECAyYgASFYIJkaq-2d5Ccant6tiAb53JbW3M0MR2JTpVEEieyDeb5bIlggoJc8_e27eeJ_707nSBZz-zMSUE3cpUNM_SNDHWrSnto', nonce: '', scope: 0, @@ -32,15 +41,21 @@ const differentDevicePubKey: DevicePublicKeyAuthenticatorOutputJSON = { }; it("should throw when more than two device public key matches", async () => { - expect(isRecognizedDevice(devicePubKey, [sameDevicePubKey, sameDevicePubKey])).rejects.toThrowError(new Error('It is undetermined whether this is a known device.')); + await expect(isRecognizedDevice(devicePubKey, [devicePubKeyJSON, devicePubKeyJSON])).rejects.toThrowError(new Error('It is undetermined whether this is a known device.')); }); -it("should return the new device public key when no device public key matches", async () => { - expect(isRecognizedDevice(devicePubKey, [differentDevicePubKey, differentDevicePubKey])).resolves.toMatchObject(devicePubKey); +it("should return the unrecognized new device public key", async () => { + await expect(isRecognizedDevice(devicePubKey, [differentDevicePubKeyJSON, differentDevicePubKeyJSON])).resolves.toMatchObject({ + authenticatorOutput: devicePubKey, + recognitionResult: 'unrecognized' + }); }); -it("should return undefined when one device public key matches", async () => { - expect(isRecognizedDevice(devicePubKey, [sameDevicePubKey, differentDevicePubKey])).resolves.toBeUndefined(); +it("should return one recognized device public key that matches", async () => { + await expect(isRecognizedDevice(devicePubKey, [devicePubKeyJSON, differentDevicePubKeyJSON])).resolves.toMatchObject({ + authenticatorOutput: devicePubKey, + recognitionResult: 'recognized' + }); }); // Needs test data diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts index 98972752..fa182ec1 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts @@ -13,12 +13,12 @@ import { verifyDevicePublicKeyAttestation } from "./verifyDevicePublicKeyAttesta * store it. Throws when it's an invalid device or any unexpected issue occurs. * @param responseDevicePublicKey * @param knownDevicePublicKeys - * @returns DevicePublicKeyAuthenticatorOutput | undefined + * @returns DevicePubKeyAuthenticatorOutputRecognizedResult | undefined */ export async function isRecognizedDevice( responseDevicePublicKey: DevicePublicKeyAuthenticatorOutput, userDevicePublicKeys?: DevicePublicKeyAuthenticatorOutputJSON[] -): Promise { +): Promise { if (userDevicePublicKeys && userDevicePublicKeys.length > 0) { // Decode all DPKs const decodedDPKs = userDevicePublicKeys.map(userDPK => { @@ -64,8 +64,14 @@ export async function isRecognizedDevice( if (!isValidDPKAttestation) { throw new Error('DevicePublicKey attestation could not be verified'); } - // When `fmt` is `none` or the device public key attestation is valid, store the DPK. - return responseDevicePublicKey; + + // When `fmt` is `none` or the device public key attestation is valid, + // return the DPK as unrecognized. + const result: DevicePublicKeyRecognitionResult = { + authenticatorOutput: responseDevicePublicKey, + recognitionResult: 'unrecognized' + } + return result; } else { // Otherwise there is some form of error: we recieved a known dpk // value, but one or more of the accompanying aaguid, scope values @@ -97,8 +103,13 @@ export async function isRecognizedDevice( } } } - // This is a valid and a known device. - return; + // When a matched device public key is found and equal, or the attestation + // is valid, return the DPK as recognized. + const result: DevicePublicKeyRecognitionResult = { + authenticatorOutput: matchedDPKs[0], + recognitionResult: 'recognized' + } + return result; } else { // Otherwise, the Relying Party does not have `attObjForDevicePublicKey` @@ -107,8 +118,13 @@ export async function isRecognizedDevice( if (!isValidDPKAttestation) { throw new Error('DevicePublicKey attestation could not be verified'); } - // When `fmt` is `none` or the device public key attestation is valid, store the DPK. - return responseDevicePublicKey; + // When `fmt` is `none` or the device public key attestation is valid, + // return the DPK as unrecognized. + const result: DevicePublicKeyRecognitionResult = { + authenticatorOutput: responseDevicePublicKey, + recognitionResult: 'unrecognized' + } + return result; } } @@ -152,3 +168,8 @@ export function checkAttStmtBinaryEquality( } return true; } + +export type DevicePublicKeyRecognitionResult = { + authenticatorOutput: DevicePublicKeyAuthenticatorOutput, + recognitionResult: 'recognized' | 'unrecognized' +} diff --git a/packages/server/src/registration/verifyRegistrationResponse.test.ts b/packages/server/src/registration/verifyRegistrationResponse.test.ts index c29a6797..3537a91d 100644 --- a/packages/server/src/registration/verifyRegistrationResponse.test.ts +++ b/packages/server/src/registration/verifyRegistrationResponse.test.ts @@ -12,6 +12,7 @@ import * as esmVerifyAttestationFIDOU2F from './verifications/verifyAttestationF import { toHash } from '../helpers/toHash'; import { RegistrationCredentialJSON } from '@simplewebauthn/typescript-types'; +import { DevicePublicKeyAuthenticatorOutput } from '../extensions/devicePublicKey/decodeDevicePubKey'; /** * Clear out root certs for android-key since responses were captured from FIDO Conformance testing @@ -580,45 +581,47 @@ test('should return credential backup info', async () => { expect(verification.registrationInfo?.credentialBackedUp).toEqual(false); }); -const DpkRegCred: RegistrationCredentialJSON = { - response: { - clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiNkM0QUptNmJyTVJwSF9JZVhDVmtHTTUydnVwTy14Y1huNldlcWIyVjJtTSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', - attestationObject: 'o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVkBMA11_MVj_ad52y40PupImIh1i3hUnUk6T9vqHNlqoxzE3QAAAAAAAAAAAAAAAAAAAAAAAAAAABAHFimPeuzlYZbxRWdeyYzOpQECAyYgASFYIPLEylOIRiI7z7q6zuYjWB9TcOj9yNwmawogQJ4ZKpNAIlggd9ZqIjd30p1tIU6A8ue5wEZl9q_AsKR_leaHFZ_bwWmhbGRldmljZVB1YktleViMpmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=' - }, - id: 'BxYpj3rs5WGW8UVnXsmMzg', - rawId: 'BxYpj3rs5WGW8UVnXsmMzg', - type: 'public-key', - transports: [], - clientExtensionResults: { - devicePubKey: { - authenticatorOutput: 'pmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=', - signature: 'MEUCIQDTf2ImngEOi3qHws6gxf6CpquI97oDIl8m_4T2xQO-YwIgdWN7elqNuU-yMZtGpy8hQtL_E-qmZ1_rM2u2nhXYw7A=' +describe('device public key related tests', () => { + const DpkRegCred: RegistrationCredentialJSON = { + response: { + clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiNkM0QUptNmJyTVJwSF9JZVhDVmtHTTUydnVwTy14Y1huNldlcWIyVjJtTSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', + attestationObject: 'o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVkBMA11_MVj_ad52y40PupImIh1i3hUnUk6T9vqHNlqoxzE3QAAAAAAAAAAAAAAAAAAAAAAAAAAABAHFimPeuzlYZbxRWdeyYzOpQECAyYgASFYIPLEylOIRiI7z7q6zuYjWB9TcOj9yNwmawogQJ4ZKpNAIlggd9ZqIjd30p1tIU6A8ue5wEZl9q_AsKR_leaHFZ_bwWmhbGRldmljZVB1YktleViMpmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=' + }, + id: 'BxYpj3rs5WGW8UVnXsmMzg', + rawId: 'BxYpj3rs5WGW8UVnXsmMzg', + type: 'public-key', + transports: [], + clientExtensionResults: { + devicePubKey: { + authenticatorOutput: 'pmNkcGtYTaUBAgMmIAEhWCBNwZidDC8QQNAffsFaxUKxTbVLxepdV-1_azg-u0-rsCJYIFtht9l1L8g2hqQOo8omnBd9fRj2byJzn1JQqnp19oVbY2ZtdGRub25lZW5vbmNlQGVzY29wZQBmYWFndWlkUAAAAAAAAAAAAAAAAAAAAABnYXR0U3RtdKA=', + signature: 'MEUCIQDTf2ImngEOi3qHws6gxf6CpquI97oDIl8m_4T2xQO-YwIgdWN7elqNuU-yMZtGpy8hQtL_E-qmZ1_rM2u2nhXYw7A=' + } } + }; + + if (!DpkRegCred?.clientExtensionResults?.devicePubKey) { + throw new Error('This exception will not happen.'); } -}; -if (!DpkRegCred?.clientExtensionResults?.devicePubKey) { - throw new Error('This exception will not happen.'); -} - -const DpkVerifyRegRespOpts: VerifyRegistrationResponseOpts = { - credential: DpkRegCred, - expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', - expectedRPID: 'try-webauthn.appspot.com', - expectedChallenge: '6C4AJm6brMRpH_IeXCVkGM52vupO-xcXn6Weqb2V2mM', -} - -test('should return authenticator extension output', async () => { - const verification = await verifyRegistrationResponse(DpkVerifyRegRespOpts); - expect(verification.registrationInfo?.extensionOutputs).toMatchObject({ - unregisteredDevicePubKey: { - dpk: 'pQECAyYgASFYIE3BmJ0MLxBA0B9-wVrFQrFNtUvF6l1X7X9rOD67T6uwIlggW2G32XUvyDaGpA6jyiacF319GPZvInOfUlCqenX2hVs', - nonce: '', - scope: 0, - aaguid: 'AAAAAAAAAAAAAAAAAAAAAA', - fmt: 'none', - attStmt: {} - }, + const DpkVerifyRegRespOpts: VerifyRegistrationResponseOpts = { + credential: DpkRegCred, + expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q', + expectedRPID: 'try-webauthn.appspot.com', + expectedChallenge: '6C4AJm6brMRpH_IeXCVkGM52vupO-xcXn6Weqb2V2mM', + } + + const devicePubKey: DevicePublicKeyAuthenticatorOutput = { + dpk: Buffer.from('a50102032620012158204dc1989d0c2f1040d01f7ec15ac542b14db54bc5ea5d57ed7f6b383ebb4fabb02258205b61b7d9752fc83686a40ea3ca269c177d7d18f66f22739f5250aa7a75f6855b', 'hex'), + nonce: Buffer.from('', 'hex'), + scope: 0, + aaguid: Buffer.from('00000000000000000000000000000000', 'hex'), + fmt: 'none', + attStmt: {} + } + + test('should return authenticator extension output', async () => { + const verification = await verifyRegistrationResponse(DpkVerifyRegRespOpts); + expect(verification.registrationInfo?.extensionOutputs?.devicePubKey).toMatchObject(devicePubKey); }); }); diff --git a/packages/server/src/registration/verifyRegistrationResponse.ts b/packages/server/src/registration/verifyRegistrationResponse.ts index eef603cc..1be289f3 100644 --- a/packages/server/src/registration/verifyRegistrationResponse.ts +++ b/packages/server/src/registration/verifyRegistrationResponse.ts @@ -29,8 +29,7 @@ import { verifyDevicePublicKeyAttestation } from '../extensions/devicePublicKey/ import { decodeDevicePubKey, deserializeDevicePubKeyAuthenticatorOutput, - encodeDevicePubKeyAuthenticatorOutput, - DevicePublicKeyAuthenticatorOutputJSON, + DevicePublicKeyAuthenticatorOutput, } from '../extensions/devicePublicKey/decodeDevicePubKey'; export type VerifyRegistrationResponseOpts = { @@ -229,8 +228,7 @@ export async function verifyRegistrationResponse( throw new Error('Invalid device public key attestation.'); } - const unregisteredDevicePubKey = encodeDevicePubKeyAuthenticatorOutput(dpkAuthOutput); - extensionOutputs.unregisteredDevicePubKey = unregisteredDevicePubKey; + extensionOutputs.devicePubKey = dpkAuthOutput; } } @@ -356,5 +354,5 @@ export type AttestationFormatVerifierOpts = { }; export type RegistrationExtensionOutputs = { - unregisteredDevicePubKey?: DevicePublicKeyAuthenticatorOutputJSON; + devicePubKey?: DevicePublicKeyAuthenticatorOutput; } From c20bde9771f174c95882159cd711188df2248b21 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Wed, 23 Nov 2022 21:55:50 +0900 Subject: [PATCH 37/37] Allow extending DPK object --- .../decodeDevicePubKey.test.ts | 45 +++++++++++++++++-- .../devicePublicKey/decodeDevicePubKey.ts | 9 +++- .../devicePublicKey/isRecognizedDevice.ts | 3 +- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.test.ts b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.test.ts index a563eedb..23d326ba 100644 --- a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.test.ts +++ b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.test.ts @@ -1,5 +1,15 @@ -import { AuthenticationExtensionsDevicePublicKeyOutputs, AuthenticationExtensionsDevicePublicKeyOutputsJSON } from "@simplewebauthn/typescript-types"; -import { decodeDevicePubKey, deserializeDevicePubKeyAuthenticatorOutput } from "./decodeDevicePubKey"; +import { + AuthenticationExtensionsDevicePublicKeyOutputs, + AuthenticationExtensionsDevicePublicKeyOutputsJSON +} from "@simplewebauthn/typescript-types"; +import { decode } from "cbor"; +import { + decodeDevicePubKey, + decodeDevicePubKeyAuthenticatorOutput, + deserializeDevicePubKeyAuthenticatorOutput, + DevicePublicKeyAuthenticatorOutputExtended, + DevicePublicKeyAuthenticatorOutputJSON +} from "./decodeDevicePubKey"; it("should decode device public key client extension output", () => { const devicePubKeyJSON: AuthenticationExtensionsDevicePublicKeyOutputsJSON = { @@ -14,7 +24,7 @@ it("should decode device public key client extension output", () => { }); }); -it("should decode device public key authenticator output", () => { +it("should deserialize device public key authenticator output", () => { const devicePubKey: AuthenticationExtensionsDevicePublicKeyOutputs = { authenticatorOutput: Buffer.from('A66364706B584DA50102032620012158204DC1989D0C2F1040D01F7EC15AC542B14DB54BC5EA5D57ED7F6B383EBB4FABB02258205B61B7D9752FC83686A40EA3CA269C177D7D18F66F22739F5250AA7A75F6855B63666D74646E6F6E65656E6F6E6365406573636F7065006661616775696450000000000000000000000000000000006761747453746D74A0', 'hex'), signature: Buffer.from('3045022100d37f62269e010e8b7a87c2cea0c5fe82a6ab88f7ba03225f26ff84f6c503be63022075637b7a5a8db94fb2319b46a72f2142d2ff13eaa6675feb336bb69e15d8c3b0', 'hex'), @@ -29,4 +39,31 @@ it("should decode device public key authenticator output", () => { aaguid: Buffer.from('00000000000000000000000000000000', 'hex'), attStmt: {}, }); -}) +}); + +test("should decode device public key authenticator output that includes additional values", () => { + const devicePubKeyJSON: DevicePublicKeyAuthenticatorOutputJSON = { + id: 'abcdefghijklmn', + dpk: 'pQECAyYgASFYIO3q0_01dpwj00DdwYMKf_IOc1XynRx1qg3CtqwYLqfTIlggNFHcmZKvlGgltEGUX8nRNOF7c6pf6pWANR58k_XTZRM', + nonce: '', + scope: 0, + aaguid: 'uT_ZYfLmRi-xIoIAIkfeeA', + fmt: 'none', + attStmt: {}, + last_update: 1000000000000000 + } + + const devicePubKey: DevicePublicKeyAuthenticatorOutputExtended = { + id: 'abcdefghijklmn', + dpk: Buffer.from('A5010203262001215820EDEAD3FD35769C23D340DDC1830A7FF20E7355F29D1C75AA0DC2B6AC182EA7D32258203451DC9992AF946825B441945FC9D134E17B73AA5FEA9580351E7C93F5D36513', 'hex'), + nonce: Buffer.from('', 'hex'), + scope: 0, + aaguid: Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), + fmt: 'none', + attStmt: {}, + last_update: 1000000000000000, + } + + const result = decodeDevicePubKeyAuthenticatorOutput(devicePubKeyJSON); + expect(result).toMatchObject(devicePubKey); +}); diff --git a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts index a6825f57..de6f1253 100644 --- a/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts +++ b/packages/server/src/extensions/devicePublicKey/decodeDevicePubKey.ts @@ -103,14 +103,15 @@ export function encodeDevicePubKeyAuthenticatorOutput( export function decodeDevicePubKeyAuthenticatorOutput( encodedDevicePubKey: DevicePublicKeyAuthenticatorOutputJSON -): DevicePublicKeyAuthenticatorOutput { +): DevicePublicKeyAuthenticatorOutputExtended { const aaguid = base64url.toBuffer(encodedDevicePubKey.aaguid); const dpk = base64url.toBuffer(encodedDevicePubKey.dpk); const scope = encodedDevicePubKey.scope; const nonce = encodedDevicePubKey.nonce ? base64url.toBuffer(encodedDevicePubKey.nonce) : Buffer.from('', 'hex'); const fmt = encodedDevicePubKey.fmt ? encodedDevicePubKey.fmt : 'none'; - const decodedDevicePubKey: DevicePublicKeyAuthenticatorOutput = { + const decodedDevicePubKey: DevicePublicKeyAuthenticatorOutputExtended = { + ...encodedDevicePubKey, aaguid, dpk, scope, @@ -145,7 +146,11 @@ export type DevicePublicKeyAuthenticatorOutput = { nonce?: Buffer; }; +export type DevicePublicKeyAuthenticatorOutputExtended = + DevicePublicKeyAuthenticatorOutput | {[key: string]: any} + export type DevicePublicKeyAuthenticatorOutputJSON = { + [key: string]: any; aaguid: string; dpk: string; scope: number; diff --git a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts index fa182ec1..e9642570 100644 --- a/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts +++ b/packages/server/src/extensions/devicePublicKey/isRecognizedDevice.ts @@ -1,6 +1,7 @@ import { AttestationStatement } from "@simplewebauthn/typescript-types"; import { DevicePublicKeyAuthenticatorOutput, + DevicePublicKeyAuthenticatorOutputExtended, DevicePublicKeyAuthenticatorOutputJSON, decodeDevicePubKeyAuthenticatorOutput, } from './decodeDevicePubKey'; @@ -170,6 +171,6 @@ export function checkAttStmtBinaryEquality( } export type DevicePublicKeyRecognitionResult = { - authenticatorOutput: DevicePublicKeyAuthenticatorOutput, + authenticatorOutput: DevicePublicKeyAuthenticatorOutputExtended, recognitionResult: 'recognized' | 'unrecognized' }