summaryrefslogtreecommitdiffhomepage
path: root/packages/server/src/authentication/verifyAuthenticationResponse.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/server/src/authentication/verifyAuthenticationResponse.test.ts')
-rw-r--r--packages/server/src/authentication/verifyAuthenticationResponse.test.ts285
1 files changed, 137 insertions, 148 deletions
diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts
index 44aeffd..bf2a79a 100644
--- a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts
+++ b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts
@@ -3,31 +3,28 @@ import {
assertEquals,
assertExists,
assertRejects,
-} from "https://deno.land/std@0.198.0/assert/mod.ts";
-import {
- returnsNext,
- stub,
-} from "https://deno.land/std@0.198.0/testing/mock.ts";
+} from 'https://deno.land/std@0.198.0/assert/mod.ts';
+import { returnsNext, stub } from 'https://deno.land/std@0.198.0/testing/mock.ts';
-import { verifyAuthenticationResponse } from "./verifyAuthenticationResponse.ts";
+import { verifyAuthenticationResponse } from './verifyAuthenticationResponse.ts';
-import { _decodeClientDataJSONInternals } from "../helpers/decodeClientDataJSON.ts";
+import { _decodeClientDataJSONInternals } from '../helpers/decodeClientDataJSON.ts';
import {
_parseAuthenticatorDataInternals,
parseAuthenticatorData,
-} from "../helpers/parseAuthenticatorData.ts";
-import { toHash } from "../helpers/toHash.ts";
-import { AuthenticationResponseJSON, AuthenticatorDevice } from "../deps.ts";
-import { isoBase64URL, isoUint8Array } from "../helpers/iso/index.ts";
-import { assertObjectMatch } from "https://deno.land/std@0.198.0/assert/assert_object_match.ts";
-import { assertFalse } from "https://deno.land/std@0.198.0/assert/assert_false.ts";
-
-Deno.test("should verify an assertion response", async () => {
+} from '../helpers/parseAuthenticatorData.ts';
+import { toHash } from '../helpers/toHash.ts';
+import { AuthenticationResponseJSON, AuthenticatorDevice } from '../deps.ts';
+import { isoBase64URL, isoUint8Array } from '../helpers/iso/index.ts';
+import { assertObjectMatch } from 'https://deno.land/std@0.198.0/assert/assert_object_match.ts';
+import { assertFalse } from 'https://deno.land/std@0.198.0/assert/assert_false.ts';
+
+Deno.test('should verify an assertion response', async () => {
const verification = await verifyAuthenticationResponse({
response: assertionResponse,
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
- expectedRPID: "dev.dontneeda.pw",
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
requireUserVerification: false,
});
@@ -35,12 +32,12 @@ Deno.test("should verify an assertion response", async () => {
assertEquals(verification.verified, true);
});
-Deno.test("should return authenticator info after verification", async () => {
+Deno.test('should return authenticator info after verification', async () => {
const verification = await verifyAuthenticationResponse({
response: assertionResponse,
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
- expectedRPID: "dev.dontneeda.pw",
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
requireUserVerification: false,
});
@@ -51,47 +48,47 @@ Deno.test("should return authenticator info after verification", async () => {
authenticator.credentialID,
);
assertEquals(verification.authenticationInfo?.origin, assertionOrigin);
- assertEquals(verification.authenticationInfo?.rpID, "dev.dontneeda.pw");
+ assertEquals(verification.authenticationInfo?.rpID, 'dev.dontneeda.pw');
});
-Deno.test("should throw when response challenge is not expected value", async () => {
+Deno.test('should throw when response challenge is not expected value', async () => {
await assertRejects(
() =>
verifyAuthenticationResponse({
response: assertionResponse,
- expectedChallenge: "shouldhavebeenthisvalue",
- expectedOrigin: "https://different.address",
- expectedRPID: "dev.dontneeda.pw",
+ expectedChallenge: 'shouldhavebeenthisvalue',
+ expectedOrigin: 'https://different.address',
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
}),
Error,
- "authentication response challenge",
+ 'authentication response challenge',
);
});
-Deno.test("should throw when response origin is not expected value", async () => {
+Deno.test('should throw when response origin is not expected value', async () => {
await assertRejects(
() =>
verifyAuthenticationResponse({
response: assertionResponse,
expectedChallenge: assertionChallenge,
- expectedOrigin: "https://different.address",
- expectedRPID: "dev.dontneeda.pw",
+ expectedOrigin: 'https://different.address',
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
}),
Error,
- "authentication response origin",
+ 'authentication response origin',
);
});
-Deno.test("should throw when assertion type is not webauthn.create", async () => {
+Deno.test('should throw when assertion type is not webauthn.create', async () => {
const mockDecodeClientData = stub(
_decodeClientDataJSONInternals,
- "stubThis",
+ 'stubThis',
returnsNext([
{
origin: assertionOrigin,
- type: "webauthn.badtype",
+ type: 'webauthn.badtype',
challenge: assertionChallenge,
},
]),
@@ -103,25 +100,25 @@ Deno.test("should throw when assertion type is not webauthn.create", async () =>
response: assertionResponse,
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
- expectedRPID: "dev.dontneeda.pw",
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
}),
Error,
- "authentication response type",
+ 'authentication response type',
);
mockDecodeClientData.restore();
});
-Deno.test("should throw error if user was not present", async () => {
+Deno.test('should throw error if user was not present', async () => {
const mockParseAuthData = stub(
_parseAuthenticatorDataInternals,
- "stubThis",
+ 'stubThis',
// @ts-ignore: Only return the values that matter
returnsNext([
{
rpIdHash: await toHash(
- isoUint8Array.fromASCIIString("dev.dontneeda.pw"),
+ isoUint8Array.fromASCIIString('dev.dontneeda.pw'),
),
flags: { up: false },
},
@@ -134,17 +131,17 @@ Deno.test("should throw error if user was not present", async () => {
response: assertionResponse,
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
- expectedRPID: "dev.dontneeda.pw",
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
}),
Error,
- "not present",
+ 'not present',
);
mockParseAuthData.restore();
});
-Deno.test("should throw error if previous counter value is not less than in response", async () => {
+Deno.test('should throw error if previous counter value is not less than in response', async () => {
// This'll match the `counter` value in `assertionResponse`, simulating a potential replay attack
const badCounter = 144;
const badDevice = {
@@ -158,23 +155,23 @@ Deno.test("should throw error if previous counter value is not less than in resp
response: assertionResponse,
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
- expectedRPID: "dev.dontneeda.pw",
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: badDevice,
requireUserVerification: false,
}),
Error,
- "counter value",
+ 'counter value',
);
});
-Deno.test("should throw error if assertion RP ID is unexpected value", async () => {
+Deno.test('should throw error if assertion RP ID is unexpected value', async () => {
const mockParseAuthData = stub(
_parseAuthenticatorDataInternals,
- "stubThis",
+ 'stubThis',
// @ts-ignore: Only return the values that matter
returnsNext([
{
- rpIdHash: await toHash(isoUint8Array.fromASCIIString("bad.url")),
+ rpIdHash: await toHash(isoUint8Array.fromASCIIString('bad.url')),
flags: 0,
},
]),
@@ -186,22 +183,22 @@ Deno.test("should throw error if assertion RP ID is unexpected value", async ()
response: assertionResponse,
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
- expectedRPID: "dev.dontneeda.pw",
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
}),
Error,
- "RP ID",
+ 'RP ID',
);
mockParseAuthData.restore();
});
-Deno.test("should not compare counters if both are 0", async () => {
+Deno.test('should not compare counters if both are 0', async () => {
const verification = await verifyAuthenticationResponse({
response: assertionFirstTimeUsedResponse,
expectedChallenge: assertionFirstTimeUsedChallenge,
expectedOrigin: assertionFirstTimeUsedOrigin,
- expectedRPID: "dev.dontneeda.pw",
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticatorFirstTimeUsed,
requireUserVerification: false,
});
@@ -209,14 +206,14 @@ Deno.test("should not compare counters if both are 0", async () => {
assertEquals(verification.verified, true);
});
-Deno.test("should throw an error if user verification is required but user was not verified", async () => {
+Deno.test('should throw an error if user verification is required but user was not verified', async () => {
const actualData = parseAuthenticatorData(
isoBase64URL.toBuffer(assertionResponse.response.authenticatorData),
);
const mockParseAuthData = stub(
_parseAuthenticatorDataInternals,
- "stubThis",
+ 'stubThis',
// @ts-ignore: Only return the values that matter
returnsNext([
{
@@ -235,43 +232,43 @@ Deno.test("should throw an error if user verification is required but user was n
response: assertionResponse,
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
- expectedRPID: "dev.dontneeda.pw",
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
requireUserVerification: true,
}),
Error,
- "user could not be verified",
+ 'user could not be verified',
);
mockParseAuthData.restore();
});
// TODO: Get a real TPM authentication response in here
-Deno.test("should verify TPM assertion", { ignore: true }, async () => {
- const expectedChallenge = "dG90YWxseVVuaXF1ZVZhbHVlRXZlcnlBc3NlcnRpb24";
+Deno.test('should verify TPM assertion', { ignore: true }, async () => {
+ const expectedChallenge = 'dG90YWxseVVuaXF1ZVZhbHVlRXZlcnlBc3NlcnRpb24';
// jest.spyOn(isoBase64URL, "toString").mockReturnValueOnce(expectedChallenge);
const verification = await verifyAuthenticationResponse({
response: {
- id: "YJ8FMM-AmcUt73XPX341WXWd7ypBMylGjjhu0g3VzME",
- rawId: "YJ8FMM-AmcUt73XPX341WXWd7ypBMylGjjhu0g3VzME",
+ id: 'YJ8FMM-AmcUt73XPX341WXWd7ypBMylGjjhu0g3VzME',
+ rawId: 'YJ8FMM-AmcUt73XPX341WXWd7ypBMylGjjhu0g3VzME',
response: {
- authenticatorData: "PdxHEOnAiLIp26idVjIguzn3Ipr_RlsKZWsa-5qK-KAFAAAAAQ",
+ authenticatorData: 'PdxHEOnAiLIp26idVjIguzn3Ipr_RlsKZWsa-5qK-KAFAAAAAQ',
clientDataJSON:
- "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiZEc5MFlXeHNlVlZ1YVhGMVpWWmhiSFZsUlhabGNubEJjM05sY25ScGIyNCIsIm9yaWdpbiI6Imh0dHBzOi8vZGV2LmRvbnRuZWVkYS5wdyIsImNyb3NzT3JpZ2luIjpmYWxzZX0",
+ 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiZEc5MFlXeHNlVlZ1YVhGMVpWWmhiSFZsUlhabGNubEJjM05sY25ScGIyNCIsIm9yaWdpbiI6Imh0dHBzOi8vZGV2LmRvbnRuZWVkYS5wdyIsImNyb3NzT3JpZ2luIjpmYWxzZX0',
signature:
- "T6nS6IDnfXmt_f2BEzIvw86RrHCpmf_OQIbiY-OBgk4jyKakYF34tnpdajQnIHTCa3-56RWDa_tZGQwZopEcrWRgSONKnMEboNhsw0aTYDo2q4fICD33qVFUuBIEcWJJyv1RqfW3uvPZAq1yvif81xPWYgF796fx7fFZzbBQARbUjNPudBuwgONljRbDstRhqnrP_b7h0-_CQ8EBJIR7Bor-R5I6JYsNWeR9r0wRPkpIhNRND-y6or6Shm2NXhr-ovLtnzpdouzlrJUJWnBJquWAjtiXKZsGfsY9Srh7jduoyKyPkwItPewcdlV30uUFCtPMepaJ5lUwbBtRE0NsXg",
- userHandle: "aW50ZXJuYWxVc2VySWQ",
+ 'T6nS6IDnfXmt_f2BEzIvw86RrHCpmf_OQIbiY-OBgk4jyKakYF34tnpdajQnIHTCa3-56RWDa_tZGQwZopEcrWRgSONKnMEboNhsw0aTYDo2q4fICD33qVFUuBIEcWJJyv1RqfW3uvPZAq1yvif81xPWYgF796fx7fFZzbBQARbUjNPudBuwgONljRbDstRhqnrP_b7h0-_CQ8EBJIR7Bor-R5I6JYsNWeR9r0wRPkpIhNRND-y6or6Shm2NXhr-ovLtnzpdouzlrJUJWnBJquWAjtiXKZsGfsY9Srh7jduoyKyPkwItPewcdlV30uUFCtPMepaJ5lUwbBtRE0NsXg',
+ userHandle: 'aW50ZXJuYWxVc2VySWQ',
},
- type: "public-key",
+ type: 'public-key',
clientExtensionResults: {},
},
expectedChallenge,
expectedOrigin: assertionOrigin,
- expectedRPID: "dev.dontneeda.pw",
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: {
- credentialPublicKey: isoBase64URL.toBuffer("BAEAAQ"),
+ credentialPublicKey: isoBase64URL.toBuffer('BAEAAQ'),
credentialID: isoBase64URL.toBuffer(
- "YJ8FMM-AmcUt73XPX341WXWd7ypBMylGjjhu0g3VzME",
+ 'YJ8FMM-AmcUt73XPX341WXWd7ypBMylGjjhu0g3VzME',
),
counter: 0,
},
@@ -280,12 +277,12 @@ Deno.test("should verify TPM assertion", { ignore: true }, async () => {
assert(verification.verified);
});
-Deno.test("should support multiple possible origins", async () => {
+Deno.test('should support multiple possible origins', async () => {
const verification = await verifyAuthenticationResponse({
response: assertionResponse,
expectedChallenge: assertionChallenge,
- expectedOrigin: ["https://simplewebauthn.dev", assertionOrigin],
- expectedRPID: "dev.dontneeda.pw",
+ expectedOrigin: ['https://simplewebauthn.dev', assertionOrigin],
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
requireUserVerification: false,
});
@@ -294,66 +291,66 @@ Deno.test("should support multiple possible origins", async () => {
assertEquals(verification.authenticationInfo?.origin, assertionOrigin);
});
-Deno.test("should throw an error if origin not in list of expected origins", async () => {
+Deno.test('should throw an error if origin not in list of expected origins', async () => {
await assertRejects(
() =>
verifyAuthenticationResponse({
response: assertionResponse,
expectedChallenge: assertionChallenge,
- expectedOrigin: ["https://simplewebauthn.dev", "https://fizz.buzz"],
- expectedRPID: "dev.dontneeda.pw",
+ expectedOrigin: ['https://simplewebauthn.dev', 'https://fizz.buzz'],
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
}),
Error,
- "Unexpected authentication response origin",
+ 'Unexpected authentication response origin',
);
});
-Deno.test("should support multiple possible RP IDs", async () => {
+Deno.test('should support multiple possible RP IDs', async () => {
const verification = await verifyAuthenticationResponse({
response: assertionResponse,
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
- expectedRPID: ["dev.dontneeda.pw", "simplewebauthn.dev"],
+ expectedRPID: ['dev.dontneeda.pw', 'simplewebauthn.dev'],
authenticator: authenticator,
requireUserVerification: false,
});
assert(verification.verified);
- assertEquals(verification.authenticationInfo?.rpID, "dev.dontneeda.pw");
+ assertEquals(verification.authenticationInfo?.rpID, 'dev.dontneeda.pw');
});
-Deno.test("should throw an error if RP ID not in list of possible RP IDs", async () => {
+Deno.test('should throw an error if RP ID not in list of possible RP IDs', async () => {
await assertRejects(
() =>
verifyAuthenticationResponse({
response: assertionResponse,
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
- expectedRPID: ["simplewebauthn.dev"],
+ expectedRPID: ['simplewebauthn.dev'],
authenticator: authenticator,
}),
Error,
- "Unexpected RP ID",
+ 'Unexpected RP ID',
);
});
-Deno.test("should pass verification if custom challenge verifier returns true", async () => {
+Deno.test('should pass verification if custom challenge verifier returns true', async () => {
const verification = await verifyAuthenticationResponse({
response: {
id:
- "AaIBxnYfL2pDWJmIii6CYgHBruhVvFGHheWamphVioG_TnEXxKA9MW4FWnJh21zsbmRpRJso9i2JmAtWOtXfVd4oXTgYVusXwhWWsA",
+ 'AaIBxnYfL2pDWJmIii6CYgHBruhVvFGHheWamphVioG_TnEXxKA9MW4FWnJh21zsbmRpRJso9i2JmAtWOtXfVd4oXTgYVusXwhWWsA',
rawId:
- "AaIBxnYfL2pDWJmIii6CYgHBruhVvFGHheWamphVioG_TnEXxKA9MW4FWnJh21zsbmRpRJso9i2JmAtWOtXfVd4oXTgYVusXwhWWsA",
+ 'AaIBxnYfL2pDWJmIii6CYgHBruhVvFGHheWamphVioG_TnEXxKA9MW4FWnJh21zsbmRpRJso9i2JmAtWOtXfVd4oXTgYVusXwhWWsA',
response: {
- authenticatorData: "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFYftypQ",
+ authenticatorData: 'SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFYftypQ',
clientDataJSON:
- "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiZXlKaFkzUjFZV3hEYUdGc2JHVnVaMlVpT2lKTE0xRjRUMnB1VmtwTWFVZHNibFpGY0RWMllUVlJTbVZOVmxkT1psODNVRmxuZFhSbllrRjBRVlZCSWl3aVlYSmlhWFJ5WVhKNVJHRjBZU0k2SW5OcFoyNU5aVkJzWldGelpTSjkiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjgwMDAiLCJjcm9zc09yaWdpbiI6ZmFsc2V9",
+ 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiZXlKaFkzUjFZV3hEYUdGc2JHVnVaMlVpT2lKTE0xRjRUMnB1VmtwTWFVZHNibFpGY0RWMllUVlJTbVZOVmxkT1psODNVRmxuZFhSbllrRjBRVlZCSWl3aVlYSmlhWFJ5WVhKNVJHRjBZU0k2SW5OcFoyNU5aVkJzWldGelpTSjkiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjgwMDAiLCJjcm9zc09yaWdpbiI6ZmFsc2V9',
signature:
- "MEUCIByFAVGfkoKPEzynp-37BX_HOXSaC6-58-ELjB7BG9opAiEAyD_1mN9YAPrphcwpzK3ym2Xx8EjAapgQ326mKgQ1pW0",
- userHandle: "internalUserId",
+ 'MEUCIByFAVGfkoKPEzynp-37BX_HOXSaC6-58-ELjB7BG9opAiEAyD_1mN9YAPrphcwpzK3ym2Xx8EjAapgQ326mKgQ1pW0',
+ userHandle: 'internalUserId',
},
- type: "public-key",
+ type: 'public-key',
clientExtensionResults: {},
},
expectedChallenge: (challenge: string) => {
@@ -364,16 +361,16 @@ Deno.test("should pass verification if custom challenge verifier returns true",
isoBase64URL.toString(challenge),
);
return parsedChallenge.actualChallenge ===
- "K3QxOjnVJLiGlnVEp5va5QJeMVWNf_7PYgutgbAtAUA";
+ 'K3QxOjnVJLiGlnVEp5va5QJeMVWNf_7PYgutgbAtAUA';
},
- expectedOrigin: "http://localhost:8000",
- expectedRPID: "localhost",
+ expectedOrigin: 'http://localhost:8000',
+ expectedRPID: 'localhost',
authenticator: {
credentialID: isoBase64URL.toBuffer(
- "AaIBxnYfL2pDWJmIii6CYgHBruhVvFGHheWamphVioG_TnEXxKA9MW4FWnJh21zsbmRpRJso9i2JmAtWOtXfVd4oXTgYVusXwhWWsA",
+ 'AaIBxnYfL2pDWJmIii6CYgHBruhVvFGHheWamphVioG_TnEXxKA9MW4FWnJh21zsbmRpRJso9i2JmAtWOtXfVd4oXTgYVusXwhWWsA',
),
credentialPublicKey: isoBase64URL.toBuffer(
- "pQECAyYgASFYILTrxTUQv3X4DRM6L_pk65FSMebenhCx3RMsTKoBm-AxIlggEf3qk5552QLNSh1T1oQs7_2C2qysDwN4r4fCp52Hsqs",
+ 'pQECAyYgASFYILTrxTUQv3X4DRM6L_pk65FSMebenhCx3RMsTKoBm-AxIlggEf3qk5552QLNSh1T1oQs7_2C2qysDwN4r4fCp52Hsqs',
),
counter: 0,
},
@@ -382,49 +379,47 @@ Deno.test("should pass verification if custom challenge verifier returns true",
assert(verification.verified);
});
-Deno.test("should fail verification if custom challenge verifier returns false", async () => {
+Deno.test('should fail verification if custom challenge verifier returns false', async () => {
await assertRejects(
() =>
verifyAuthenticationResponse({
response: assertionResponse,
- expectedChallenge: (challenge) => challenge === "willNeverMatch",
+ expectedChallenge: (challenge) => challenge === 'willNeverMatch',
expectedOrigin: assertionOrigin,
- expectedRPID: "dev.dontneeda.pw",
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
}),
Error,
- "Custom challenge verifier returned false",
+ 'Custom challenge verifier returned false',
);
});
-Deno.test("should return authenticator extension output", async () => {
+Deno.test('should return authenticator extension output', async () => {
const verification = await verifyAuthenticationResponse({
response: {
response: {
clientDataJSON:
- "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiaVpzVkN6dHJEVzdEMlVfR0hDSWxZS0x3VjJiQ3NCVFJxVlFVbkpYbjlUayIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9",
+ 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiaVpzVkN6dHJEVzdEMlVfR0hDSWxZS0x3VjJiQ3NCVFJxVlFVbkpYbjlUayIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9',
authenticatorData:
- "DXX8xWP9p3nbLjQ-6kiYiHWLeFSdSTpP2-oc2WqjHMSFAAAAAKFsZGV2aWNlUHViS2V5pWNkcGtYTaUBAgMmIAEhWCCZGqvtneQnGp7erYgG-dyW1tzNDEdiU6VRBInsg3m-WyJYIKCXPP3tu3nif-9O50gWc_szElBN3KVDTP0jQx1q0p7aY3NpZ1hHMEUCIElSbNKK72tOYhp9WTbStQSVL8CuIxOk8DV6r_-uqWR0AiEAnVE6yu-wsyx2Wq5v66jClGhe_2P_HL8R7PIQevT-uPhlbm9uY2VAZXNjb3BlQQBmYWFndWlkULk_2WHy5kYvsSKCACJH3ng",
+ 'DXX8xWP9p3nbLjQ-6kiYiHWLeFSdSTpP2-oc2WqjHMSFAAAAAKFsZGV2aWNlUHViS2V5pWNkcGtYTaUBAgMmIAEhWCCZGqvtneQnGp7erYgG-dyW1tzNDEdiU6VRBInsg3m-WyJYIKCXPP3tu3nif-9O50gWc_szElBN3KVDTP0jQx1q0p7aY3NpZ1hHMEUCIElSbNKK72tOYhp9WTbStQSVL8CuIxOk8DV6r_-uqWR0AiEAnVE6yu-wsyx2Wq5v66jClGhe_2P_HL8R7PIQevT-uPhlbm9uY2VAZXNjb3BlQQBmYWFndWlkULk_2WHy5kYvsSKCACJH3ng',
signature:
- "MEYCIQDlRuxY7cYre0sb3T6TovQdfYIUb72cRZYOQv_zS9wN_wIhAOvN-fwjtyIhWRceqJV4SX74-z6oALERbC7ohk8EdVPO",
- userHandle:
- "b2FPajFxcmM4MWo3QkFFel9RN2lEakh5RVNlU2RLNDF0Sl92eHpQYWV5UQ==",
+ 'MEYCIQDlRuxY7cYre0sb3T6TovQdfYIUb72cRZYOQv_zS9wN_wIhAOvN-fwjtyIhWRceqJV4SX74-z6oALERbC7ohk8EdVPO',
+ userHandle: 'b2FPajFxcmM4MWo3QkFFel9RN2lEakh5RVNlU2RLNDF0Sl92eHpQYWV5UQ==',
},
- id: "E_Pko4wN1BXE23S0ftN3eQ",
- rawId: "E_Pko4wN1BXE23S0ftN3eQ",
- type: "public-key",
+ id: 'E_Pko4wN1BXE23S0ftN3eQ',
+ rawId: 'E_Pko4wN1BXE23S0ftN3eQ',
+ type: 'public-key',
clientExtensionResults: {},
},
- expectedOrigin:
- "android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q",
- expectedRPID: "try-webauthn.appspot.com",
- expectedChallenge: "iZsVCztrDW7D2U_GHCIlYKLwV2bCsBTRqVQUnJXn9Tk",
+ expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q',
+ expectedRPID: 'try-webauthn.appspot.com',
+ expectedChallenge: 'iZsVCztrDW7D2U_GHCIlYKLwV2bCsBTRqVQUnJXn9Tk',
authenticator: {
credentialID: isoBase64URL.toBuffer(
- "AaIBxnYfL2pDWJmIii6CYgHBruhVvFGHheWamphVioG_TnEXxKA9MW4FWnJh21zsbmRpRJso9i2JmAtWOtXfVd4oXTgYVusXwhWWsA",
+ 'AaIBxnYfL2pDWJmIii6CYgHBruhVvFGHheWamphVioG_TnEXxKA9MW4FWnJh21zsbmRpRJso9i2JmAtWOtXfVd4oXTgYVusXwhWWsA',
),
credentialPublicKey: isoBase64URL.toBuffer(
- "pQECAyYgASFYILTrxTUQv3X4DRM6L_pk65FSMebenhCx3RMsTKoBm-AxIlggEf3qk5552QLNSh1T1oQs7_2C2qysDwN4r4fCp52Hsqs",
+ 'pQECAyYgASFYILTrxTUQv3X4DRM6L_pk65FSMebenhCx3RMsTKoBm-AxIlggEf3qk5552QLNSh1T1oQs7_2C2qysDwN4r4fCp52Hsqs',
),
counter: 0,
},
@@ -435,42 +430,42 @@ Deno.test("should return authenticator extension output", async () => {
{
devicePubKey: {
dpk: isoUint8Array.fromHex(
- "A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA",
+ 'A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA',
),
sig: isoUint8Array.fromHex(
- "3045022049526CD28AEF6B4E621A7D5936D2B504952FC0AE2313A4F0357AAFFFAEA964740221009D513ACAEFB0B32C765AAE6FEBA8C294685EFF63FF1CBF11ECF2107AF4FEB8F8",
+ '3045022049526CD28AEF6B4E621A7D5936D2B504952FC0AE2313A4F0357AAFFFAEA964740221009D513ACAEFB0B32C765AAE6FEBA8C294685EFF63FF1CBF11ECF2107AF4FEB8F8',
),
- nonce: isoUint8Array.fromHex(""),
- scope: isoUint8Array.fromHex("00"),
- aaguid: isoUint8Array.fromHex("B93FD961F2E6462FB12282002247DE78"),
+ nonce: isoUint8Array.fromHex(''),
+ scope: isoUint8Array.fromHex('00'),
+ aaguid: isoUint8Array.fromHex('B93FD961F2E6462FB12282002247DE78'),
},
},
);
});
-Deno.test("should return credential backup info", async () => {
+Deno.test('should return credential backup info', async () => {
const verification = await verifyAuthenticationResponse({
response: assertionResponse,
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
- expectedRPID: "dev.dontneeda.pw",
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
requireUserVerification: false,
});
assertEquals(
verification.authenticationInfo?.credentialDeviceType,
- "singleDevice",
+ 'singleDevice',
);
assertEquals(verification.authenticationInfo?.credentialBackedUp, false);
});
-Deno.test("should return user verified flag after successful auth", async () => {
+Deno.test('should return user verified flag after successful auth', async () => {
const verification = await verifyAuthenticationResponse({
response: assertionResponse,
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
- expectedRPID: "dev.dontneeda.pw",
+ expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
requireUserVerification: false,
});
@@ -484,34 +479,30 @@ Deno.test("should return user verified flag after successful auth", async () =>
*/
const assertionResponse: AuthenticationResponseJSON = {
- id:
- "KEbWNCc7NgaYnUyrNeFGX9_3Y-8oJ3KwzjnaiD1d1LVTxR7v3CaKfCz2Vy_g_MHSh7yJ8yL0Pxg6jo_o0hYiew",
- rawId:
- "KEbWNCc7NgaYnUyrNeFGX9_3Y-8oJ3KwzjnaiD1d1LVTxR7v3CaKfCz2Vy_g_MHSh7yJ8yL0Pxg6jo_o0hYiew",
+ id: 'KEbWNCc7NgaYnUyrNeFGX9_3Y-8oJ3KwzjnaiD1d1LVTxR7v3CaKfCz2Vy_g_MHSh7yJ8yL0Pxg6jo_o0hYiew',
+ rawId: 'KEbWNCc7NgaYnUyrNeFGX9_3Y-8oJ3KwzjnaiD1d1LVTxR7v3CaKfCz2Vy_g_MHSh7yJ8yL0Pxg6jo_o0hYiew',
response: {
- authenticatorData: "PdxHEOnAiLIp26idVjIguzn3Ipr_RlsKZWsa-5qK-KABAAAAkA==",
- clientDataJSON:
- "eyJjaGFsbGVuZ2UiOiJkRzkwWVd4c2VWVnVhWEYxWlZaaGJIVmxSWFpsY25sVWFXMWwiLCJj" +
- "bGllbnRFeHRlbnNpb25zIjp7fSwiaGFzaEFsZ29yaXRobSI6IlNIQS0yNTYiLCJvcmlnaW4iOiJodHRwczovL2Rldi5k" +
- "b250bmVlZGEucHciLCJ0eXBlIjoid2ViYXV0aG4uZ2V0In0=",
- signature:
- "MEUCIQDYXBOpCWSWq2Ll4558GJKD2RoWg958lvJSB_GdeokxogIgWuEVQ7ee6AswQY0OsuQ6y8Ks6" +
- "jhd45bDx92wjXKs900=",
+ authenticatorData: 'PdxHEOnAiLIp26idVjIguzn3Ipr_RlsKZWsa-5qK-KABAAAAkA==',
+ clientDataJSON: 'eyJjaGFsbGVuZ2UiOiJkRzkwWVd4c2VWVnVhWEYxWlZaaGJIVmxSWFpsY25sVWFXMWwiLCJj' +
+ 'bGllbnRFeHRlbnNpb25zIjp7fSwiaGFzaEFsZ29yaXRobSI6IlNIQS0yNTYiLCJvcmlnaW4iOiJodHRwczovL2Rldi5k' +
+ 'b250bmVlZGEucHciLCJ0eXBlIjoid2ViYXV0aG4uZ2V0In0=',
+ signature: 'MEUCIQDYXBOpCWSWq2Ll4558GJKD2RoWg958lvJSB_GdeokxogIgWuEVQ7ee6AswQY0OsuQ6y8Ks6' +
+ 'jhd45bDx92wjXKs900=',
},
clientExtensionResults: {},
- type: "public-key",
+ type: 'public-key',
};
const assertionChallenge = isoBase64URL.fromString(
- "totallyUniqueValueEveryTime",
+ 'totallyUniqueValueEveryTime',
);
-const assertionOrigin = "https://dev.dontneeda.pw";
+const assertionOrigin = 'https://dev.dontneeda.pw';
const authenticator: AuthenticatorDevice = {
credentialPublicKey: isoBase64URL.toBuffer(
- "pQECAyYgASFYIIheFp-u6GvFT2LNGovf3ZrT0iFVBsA_76rRysxRG9A1Ilgg8WGeA6hPmnab0HAViUYVRkwTNcN77QBf_RR0dv3lIvQ",
+ 'pQECAyYgASFYIIheFp-u6GvFT2LNGovf3ZrT0iFVBsA_76rRysxRG9A1Ilgg8WGeA6hPmnab0HAViUYVRkwTNcN77QBf_RR0dv3lIvQ',
),
credentialID: isoBase64URL.toBuffer(
- "KEbWNCc7NgaYnUyrNeFGX9_3Y-8oJ3KwzjnaiD1d1LVTxR7v3CaKfCz2Vy_g_MHSh7yJ8yL0Pxg6jo_o0hYiew",
+ 'KEbWNCc7NgaYnUyrNeFGX9_3Y-8oJ3KwzjnaiD1d1LVTxR7v3CaKfCz2Vy_g_MHSh7yJ8yL0Pxg6jo_o0hYiew',
),
counter: 143,
};
@@ -520,30 +511,28 @@ const authenticator: AuthenticatorDevice = {
* Represented a device that's being used on the website for the first time
*/
const assertionFirstTimeUsedResponse: AuthenticationResponseJSON = {
- id:
- "wSisR0_4hlzw3Y1tj4uNwwifIhRa-ZxWJwWbnfror0pVK9qPdBPO5pW3gasPqn6wXHb0LNhXB_IrA1nFoSQJ9A",
- rawId:
- "wSisR0_4hlzw3Y1tj4uNwwifIhRa-ZxWJwWbnfror0pVK9qPdBPO5pW3gasPqn6wXHb0LNhXB_IrA1nFoSQJ9A",
+ id: 'wSisR0_4hlzw3Y1tj4uNwwifIhRa-ZxWJwWbnfror0pVK9qPdBPO5pW3gasPqn6wXHb0LNhXB_IrA1nFoSQJ9A',
+ rawId: 'wSisR0_4hlzw3Y1tj4uNwwifIhRa-ZxWJwWbnfror0pVK9qPdBPO5pW3gasPqn6wXHb0LNhXB_IrA1nFoSQJ9A',
response: {
- authenticatorData: "PdxHEOnAiLIp26idVjIguzn3Ipr_RlsKZWsa-5qK-KABAAAAAA",
+ authenticatorData: 'PdxHEOnAiLIp26idVjIguzn3Ipr_RlsKZWsa-5qK-KABAAAAAA',
clientDataJSON:
- "eyJjaGFsbGVuZ2UiOiJkRzkwWVd4c2VWVnVhWEYxWlZaaGJIVmxSWFpsY25sQmMzTmxjblJwYjI0IiwiY2xpZW50RXh0ZW5zaW9ucyI6e30sImhhc2hBbGdvcml0aG0iOiJTSEEtMjU2Iiwib3JpZ2luIjoiaHR0cHM6Ly9kZXYuZG9udG5lZWRhLnB3IiwidHlwZSI6IndlYmF1dGhuLmdldCJ9",
+ 'eyJjaGFsbGVuZ2UiOiJkRzkwWVd4c2VWVnVhWEYxWlZaaGJIVmxSWFpsY25sQmMzTmxjblJwYjI0IiwiY2xpZW50RXh0ZW5zaW9ucyI6e30sImhhc2hBbGdvcml0aG0iOiJTSEEtMjU2Iiwib3JpZ2luIjoiaHR0cHM6Ly9kZXYuZG9udG5lZWRhLnB3IiwidHlwZSI6IndlYmF1dGhuLmdldCJ9',
signature:
- "MEQCIBu6M-DGzu1O8iocGHEj0UaAZm0HmxTeRIE6-nS3_CPjAiBDsmIzy5sacYwwzgpXqfwRt_2vl5yiQZ_OAqWJQBGVsQ",
+ 'MEQCIBu6M-DGzu1O8iocGHEj0UaAZm0HmxTeRIE6-nS3_CPjAiBDsmIzy5sacYwwzgpXqfwRt_2vl5yiQZ_OAqWJQBGVsQ',
},
- type: "public-key",
+ type: 'public-key',
clientExtensionResults: {},
};
const assertionFirstTimeUsedChallenge = isoBase64URL.fromString(
- "totallyUniqueValueEveryAssertion",
+ 'totallyUniqueValueEveryAssertion',
);
-const assertionFirstTimeUsedOrigin = "https://dev.dontneeda.pw";
+const assertionFirstTimeUsedOrigin = 'https://dev.dontneeda.pw';
const authenticatorFirstTimeUsed: AuthenticatorDevice = {
credentialPublicKey: isoBase64URL.toBuffer(
- "pQECAyYgASFYIGmaxR4mBbukc2QhtW2ldhAAd555r-ljlGQN8MbcTnPPIlgg9CyUlE-0AB2fbzZbNgBvJuRa7r6o2jPphOmtyNPR_kY",
+ 'pQECAyYgASFYIGmaxR4mBbukc2QhtW2ldhAAd555r-ljlGQN8MbcTnPPIlgg9CyUlE-0AB2fbzZbNgBvJuRa7r6o2jPphOmtyNPR_kY',
),
credentialID: isoBase64URL.toBuffer(
- "wSisR0_4hlzw3Y1tj4uNwwifIhRa-ZxWJwWbnfror0pVK9qPdBPO5pW3gasPqn6wXHb0LNhXB_IrA1nFoSQJ9A",
+ 'wSisR0_4hlzw3Y1tj4uNwwifIhRa-ZxWJwWbnfror0pVK9qPdBPO5pW3gasPqn6wXHb0LNhXB_IrA1nFoSQJ9A',
),
counter: 0,
};