From a1f0da668d54cb4b1119a61c6f48c9ba613c50ab Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Wed, 7 Oct 2020 23:12:04 -0700 Subject: Add extensions placeholder in startAttestation --- packages/browser/src/methods/startAttestation.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'packages/browser/src/methods') diff --git a/packages/browser/src/methods/startAttestation.ts b/packages/browser/src/methods/startAttestation.ts index 0b2235d..5bc58ee 100644 --- a/packages/browser/src/methods/startAttestation.ts +++ b/packages/browser/src/methods/startAttestation.ts @@ -51,6 +51,7 @@ export default async function startAttestation( clientDataJSON: bufferToBase64URLString(response.clientDataJSON), }, type, + // clientExtensionResults: credential.getClientExtensionResults(), }; /** -- cgit v1.2.3 From 53778eabe4c8790f4efd904c4ff38809a5236565 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Fri, 5 Feb 2021 10:20:19 -0800 Subject: Send back extension results from Browser --- packages/browser/src/methods/startAssertion.ts | 1 + packages/browser/src/methods/startAttestation.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'packages/browser/src/methods') diff --git a/packages/browser/src/methods/startAssertion.ts b/packages/browser/src/methods/startAssertion.ts index e02e577..fa25f47 100644 --- a/packages/browser/src/methods/startAssertion.ts +++ b/packages/browser/src/methods/startAssertion.ts @@ -60,5 +60,6 @@ export default async function startAssertion( userHandle, }, type, + clientExtensionResults: credential.getClientExtensionResults(), }; } diff --git a/packages/browser/src/methods/startAttestation.ts b/packages/browser/src/methods/startAttestation.ts index 5bc58ee..22ebe64 100644 --- a/packages/browser/src/methods/startAttestation.ts +++ b/packages/browser/src/methods/startAttestation.ts @@ -51,7 +51,7 @@ export default async function startAttestation( clientDataJSON: bufferToBase64URLString(response.clientDataJSON), }, type, - // clientExtensionResults: credential.getClientExtensionResults(), + clientExtensionResults: credential.getClientExtensionResults(), }; /** -- cgit v1.2.3 From 05ab3d655ff565ccb9e2718cf206d6cb7a902003 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Fri, 5 Feb 2021 11:08:18 -0800 Subject: Add extension tests for startAttestation --- .../browser/src/methods/startAttestation.test.ts | 87 +++++++++++++++++++--- 1 file changed, 75 insertions(+), 12 deletions(-) (limited to 'packages/browser/src/methods') diff --git a/packages/browser/src/methods/startAttestation.test.ts b/packages/browser/src/methods/startAttestation.test.ts index 0723213..b4cfa52 100644 --- a/packages/browser/src/methods/startAttestation.test.ts +++ b/packages/browser/src/methods/startAttestation.test.ts @@ -1,5 +1,7 @@ import { AttestationCredential, + AuthenticationExtensionsClientInputs, + AuthenticationExtensionsClientOutputs, PublicKeyCredentialCreationOptionsJSON, } from '@simplewebauthn/typescript-types'; @@ -46,22 +48,24 @@ const goodOpts1: PublicKeyCredentialCreationOptionsJSON = { }; beforeEach(() => { - mockNavigatorCreate.mockReset(); - mockSupportsWebauthn.mockReset(); -}); - -test('should convert options before passing to navigator.credentials.create(...)', async done => { - mockSupportsWebauthn.mockReturnValue(true); - // Stub out a response so the method won't throw mockNavigatorCreate.mockImplementation( (): Promise => { return new Promise(resolve => { - resolve({ response: {} }); + resolve({ response: {}, getClientExtensionResults: () => ({}) }); }); }, ); + mockSupportsWebauthn.mockReturnValue(true); +}); + +afterEach(() => { + mockNavigatorCreate.mockReset(); + mockSupportsWebauthn.mockReset(); +}); + +test('should convert options before passing to navigator.credentials.create(...)', async done => { await startAttestation(goodOpts1); const argsPublicKey = mockNavigatorCreate.mock.calls[0][0].publicKey; @@ -81,8 +85,6 @@ test('should convert options before passing to navigator.credentials.create(...) }); test('should return base64url-encoded response values', async done => { - mockSupportsWebauthn.mockReturnValue(true); - mockNavigatorCreate.mockImplementation( (): Promise => { return new Promise(resolve => { @@ -120,8 +122,6 @@ test("should throw error if WebAuthn isn't supported", async done => { }); test('should throw error if attestation is cancelled for some reason', async done => { - mockSupportsWebauthn.mockReturnValue(true); - mockNavigatorCreate.mockImplementation( (): Promise => { return new Promise(resolve => { @@ -134,3 +134,66 @@ test('should throw error if attestation is cancelled for some reason', async don done(); }); + +test('should send extensions to authenticator if present in options', async done => { + const extensions: AuthenticationExtensionsClientInputs = { + credProps: true, + appid: 'appidHere', + uvm: true, + appidExclude: 'appidExcludeHere', + }; + const optsWithExts: PublicKeyCredentialCreationOptionsJSON = { + ...goodOpts1, + extensions, + }; + await startAttestation(optsWithExts); + + const argsExtensions = mockNavigatorCreate.mock.calls[0][0].publicKey.extensions; + + expect(argsExtensions).toEqual(extensions); + + done(); +}); + +test('should not set any extensions if not present in options', async done => { + await startAttestation(goodOpts1); + + const argsExtensions = mockNavigatorCreate.mock.calls[0][0].publicKey.extensions; + + expect(argsExtensions).toEqual(undefined); + + done(); +}); + +test('should include extension results', async done => { + const extResults: AuthenticationExtensionsClientOutputs = { + appid: true, + credProps: { + rk: true, + }, + }; + + // Mock extension return values from authenticator + mockNavigatorCreate.mockImplementation( + (): Promise => { + return new Promise(resolve => { + resolve({ response: {}, getClientExtensionResults: () => extResults }); + }); + }, + ); + + // Extensions aren't present in this object, but it doesn't matter since we're faking the response + const response = await startAttestation(goodOpts1); + + expect(response.clientExtensionResults).toEqual(extResults); + + done(); +}); + +test('should include extension results when no extensions specified', async done => { + const response = await startAttestation(goodOpts1); + + expect(response.clientExtensionResults).toEqual({}); + + done(); +}); -- cgit v1.2.3 From 6ee57742475044ed60edd97a1114837aac925ebb Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Fri, 5 Feb 2021 11:12:08 -0800 Subject: Add extension tests for startAssertion --- .../browser/src/methods/startAssertion.test.ts | 127 ++++++++++++--------- 1 file changed, 74 insertions(+), 53 deletions(-) (limited to 'packages/browser/src/methods') diff --git a/packages/browser/src/methods/startAssertion.test.ts b/packages/browser/src/methods/startAssertion.test.ts index c74b88f..c077219 100644 --- a/packages/browser/src/methods/startAssertion.test.ts +++ b/packages/browser/src/methods/startAssertion.test.ts @@ -1,6 +1,8 @@ import { AssertionCredential, PublicKeyCredentialRequestOptionsJSON, + AuthenticationExtensionsClientInputs, + AuthenticationExtensionsClientOutputs, } from '@simplewebauthn/typescript-types'; import supportsWebauthn from '../helpers/supportsWebauthn'; @@ -40,13 +42,6 @@ const goodOpts2UTF8: PublicKeyCredentialRequestOptionsJSON = { }; beforeEach(() => { - mockNavigatorGet.mockReset(); - mockSupportsWebauthn.mockReset(); -}); - -test('should convert options before passing to navigator.credentials.get(...)', async done => { - mockSupportsWebauthn.mockReturnValue(true); - // Stub out a response so the method won't throw mockNavigatorGet.mockImplementation( (): Promise => { @@ -59,6 +54,15 @@ test('should convert options before passing to navigator.credentials.get(...)', }, ); + mockSupportsWebauthn.mockReturnValue(true); +}); + +afterEach(() => { + mockNavigatorGet.mockReset(); + mockSupportsWebauthn.mockReset(); +}); + +test('should convert options before passing to navigator.credentials.get(...)', async done => { await startAssertion(goodOpts1); const argsPublicKey = mockNavigatorGet.mock.calls[0][0].publicKey; @@ -73,20 +77,6 @@ test('should convert options before passing to navigator.credentials.get(...)', }); test('should support optional allowCredential', async () => { - mockSupportsWebauthn.mockReturnValue(true); - - // Stub out a response so the method won't throw - mockNavigatorGet.mockImplementation( - (): Promise => { - return new Promise(resolve => { - resolve({ - response: {}, - getClientExtensionResults: () => ({}), - }); - }); - }, - ); - await startAssertion({ challenge: bufferToBase64URLString(toUint8Array('fizz')), timeout: 1, @@ -96,20 +86,6 @@ test('should support optional allowCredential', async () => { }); test('should convert allow allowCredential to undefined when empty', async () => { - mockSupportsWebauthn.mockReturnValue(true); - - // Stub out a response so the method won't throw - mockNavigatorGet.mockImplementation( - (): Promise => { - return new Promise(resolve => { - resolve({ - response: {}, - getClientExtensionResults: () => ({}), - }); - }); - }, - ); - await startAssertion({ challenge: bufferToBase64URLString(toUint8Array('fizz')), timeout: 1, @@ -119,8 +95,6 @@ test('should convert allow allowCredential to undefined when empty', async () => }); test('should return base64url-encoded response values', async done => { - mockSupportsWebauthn.mockReturnValue(true); - mockNavigatorGet.mockImplementation( (): Promise => { return new Promise(resolve => { @@ -162,8 +136,6 @@ test("should throw error if WebAuthn isn't supported", async done => { }); test('should throw error if assertion is cancelled for some reason', async done => { - mockSupportsWebauthn.mockReturnValue(true); - mockNavigatorGet.mockImplementation( (): Promise => { return new Promise(resolve => { @@ -178,20 +150,6 @@ test('should throw error if assertion is cancelled for some reason', async done }); test('should handle UTF-8 challenges', async done => { - mockSupportsWebauthn.mockReturnValue(true); - - // Stub out a response so the method won't throw - mockNavigatorGet.mockImplementation( - (): Promise => { - return new Promise(resolve => { - resolve({ - response: {}, - getClientExtensionResults: () => ({}), - }); - }); - }, - ); - await startAssertion(goodOpts2UTF8); const argsPublicKey = mockNavigatorGet.mock.calls[0][0].publicKey; @@ -221,3 +179,66 @@ test('should handle UTF-8 challenges', async done => { done(); }); + +test('should send extensions to authenticator if present in options', async done => { + const extensions: AuthenticationExtensionsClientInputs = { + credProps: true, + appid: 'appidHere', + uvm: true, + appidExclude: 'appidExcludeHere', + }; + const optsWithExts: PublicKeyCredentialRequestOptionsJSON = { + ...goodOpts1, + extensions, + }; + await startAssertion(optsWithExts); + + const argsExtensions = mockNavigatorGet.mock.calls[0][0].publicKey.extensions; + + expect(argsExtensions).toEqual(extensions); + + done(); +}); + +test('should not set any extensions if not present in options', async done => { + await startAssertion(goodOpts1); + + const argsExtensions = mockNavigatorGet.mock.calls[0][0].publicKey.extensions; + + expect(argsExtensions).toEqual(undefined); + + done(); +}); + +test('should include extension results', async done => { + const extResults: AuthenticationExtensionsClientOutputs = { + appid: true, + credProps: { + rk: true, + }, + }; + + // Mock extension return values from authenticator + mockNavigatorGet.mockImplementation( + (): Promise => { + return new Promise(resolve => { + resolve({ response: {}, getClientExtensionResults: () => extResults }); + }); + }, + ); + + // Extensions aren't present in this object, but it doesn't matter since we're faking the response + const response = await startAssertion(goodOpts1); + + expect(response.clientExtensionResults).toEqual(extResults); + + done(); +}); + +test('should include extension results when no extensions specified', async done => { + const response = await startAssertion(goodOpts1); + + expect(response.clientExtensionResults).toEqual({}); + + done(); +}); -- cgit v1.2.3