diff options
author | Antoine Cormouls <contact.antoine.cormouls@gmail.com> | 2020-12-04 15:01:35 +0100 |
---|---|---|
committer | Antoine Cormouls <contact.antoine.cormouls@gmail.com> | 2020-12-04 15:01:35 +0100 |
commit | 5f508216dc3ee38a7f17c038b367e8575ab14929 (patch) | |
tree | bf95db1232a6aa8dba52eea31ec6840d3eaca977 | |
parent | 4f1a0ab1225a34788d3c1f9bf4a9c0b7cc31b17b (diff) |
Optional Allow Credential
-rw-r--r-- | README.md | 6 | ||||
-rw-r--r-- | package.json | 4 | ||||
-rw-r--r-- | packages/browser/src/methods/startAssertion.test.ts | 25 | ||||
-rw-r--r-- | packages/browser/src/methods/startAssertion.ts | 7 | ||||
-rw-r--r-- | packages/server/src/assertion/generateAssertionOptions.test.ts | 19 | ||||
-rw-r--r-- | packages/server/src/assertion/generateAssertionOptions.ts | 7 |
6 files changed, 56 insertions, 12 deletions
@@ -49,3 +49,9 @@ Running Jest in watch mode for a specific project requires the use of `lerna exe ```sh $> npx lerna exec npm run test:watch --scope=@simplewebauthn/server ``` + +Dev on the server package with jest watch target + +```sh +$> npm run dev:server aFileNameHere.js +``` diff --git a/package.json b/package.json index c3618f1..cb57499 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ "test": "lerna run test", "build:types": "lerna bootstrap --scope=@simplewebauthn/typescript-types", "build:browser": "lerna bootstrap --scope=@simplewebauthn/browser", - "build:server": "lerna bootstrap --scope=@simplewebauthn/server" + "build:server": "lerna bootstrap --scope=@simplewebauthn/server", + "dev:server": "lerna exec npm run test:watch --scope=@simplewebauthn/server", + "dev:browser": "lerna exec npm run test:watch --scope=@simplewebauthn/browser" }, "devDependencies": { "@simplewebauthn/typescript-types": "^0.10.0", diff --git a/packages/browser/src/methods/startAssertion.test.ts b/packages/browser/src/methods/startAssertion.test.ts index 996f66a..656c419 100644 --- a/packages/browser/src/methods/startAssertion.test.ts +++ b/packages/browser/src/methods/startAssertion.test.ts @@ -39,6 +39,12 @@ const goodOpts2UTF8: PublicKeyCredentialRequestOptionsJSON = { timeout: 1, }; +// Without allow credentials +const goodOpts3: PublicKeyCredentialRequestOptionsJSON = { + challenge: bufferToBase64URLString(toUint8Array('fizz')), + timeout: 1, +}; + beforeEach(() => { mockNavigatorGet.mockReset(); mockSupportsWebauthn.mockReset(); @@ -59,15 +65,20 @@ test('should convert options before passing to navigator.credentials.get(...)', }, ); - await startAssertion(goodOpts1); + const checkWithOpts = async (opts: PublicKeyCredentialRequestOptionsJSON) => { + await startAssertion(opts); - const argsPublicKey = mockNavigatorGet.mock.calls[0][0].publicKey; - const credId = argsPublicKey.allowCredentials[0].id; + const argsPublicKey = mockNavigatorGet.mock.calls[0][0].publicKey; + const credId = argsPublicKey.allowCredentials[0].id; + + expect(new Uint8Array(argsPublicKey.challenge)).toEqual(new Uint8Array([102, 105, 122, 122])); + // Make sure the credential ID is an ArrayBuffer with a length of 64 + expect(credId instanceof ArrayBuffer).toEqual(true); + expect(credId.byteLength).toEqual(64); + }; - expect(new Uint8Array(argsPublicKey.challenge)).toEqual(new Uint8Array([102, 105, 122, 122])); - // Make sure the credential ID is an ArrayBuffer with a length of 64 - expect(credId instanceof ArrayBuffer).toEqual(true); - expect(credId.byteLength).toEqual(64); + await checkWithOpts(goodOpts1); + await checkWithOpts(goodOpts3); done(); }); diff --git a/packages/browser/src/methods/startAssertion.ts b/packages/browser/src/methods/startAssertion.ts index 09e416f..fbc6f59 100644 --- a/packages/browser/src/methods/startAssertion.ts +++ b/packages/browser/src/methods/startAssertion.ts @@ -25,7 +25,12 @@ export default async function startAssertion( const publicKey: PublicKeyCredentialRequestOptions = { ...requestOptionsJSON, challenge: base64URLStringToBuffer(requestOptionsJSON.challenge), - allowCredentials: requestOptionsJSON.allowCredentials.map(toPublicKeyCredentialDescriptor), + // We need to avoid passing empty array to avoid blocking retrieval + // of public key + allowCredentials: + requestOptionsJSON.allowCredentials?.length === 0 + ? undefined + : requestOptionsJSON.allowCredentials?.map(toPublicKeyCredentialDescriptor), }; // Wait for the user to complete assertion diff --git a/packages/server/src/assertion/generateAssertionOptions.test.ts b/packages/server/src/assertion/generateAssertionOptions.test.ts index 70a72db..24253bf 100644 --- a/packages/server/src/assertion/generateAssertionOptions.test.ts +++ b/packages/server/src/assertion/generateAssertionOptions.test.ts @@ -65,6 +65,25 @@ test('should not set userVerification if not specified', () => { expect(options.userVerification).toEqual(undefined); }); +test('should not set allowCredentials if not specified', () => { + const options = generateAssertionOptions({ rpID: 'test' }); + + expect(options.allowCredentials).toEqual(undefined); +}); + +test('should generate without params', () => { + const options = generateAssertionOptions(); + const { challenge, ...otherFields } = options; + expect(otherFields).toEqual({ + allowCredentials: undefined, + extensions: undefined, + rpId: undefined, + timeout: 60000, + userVerification: undefined, + }); + expect(typeof challenge).toEqual('string'); +}); + test('should set userVerification if specified', () => { const options = generateAssertionOptions({ challenge: 'totallyrandomvalue', diff --git a/packages/server/src/assertion/generateAssertionOptions.ts b/packages/server/src/assertion/generateAssertionOptions.ts index d05dc00..79ff6f8 100644 --- a/packages/server/src/assertion/generateAssertionOptions.ts +++ b/packages/server/src/assertion/generateAssertionOptions.ts @@ -9,7 +9,7 @@ import base64url from 'base64url'; import generateChallenge from '../helpers/generateChallenge'; type Options = { - allowCredentials: PublicKeyCredentialDescriptorJSON[]; + allowCredentials?: PublicKeyCredentialDescriptorJSON[]; challenge?: string | Buffer; timeout?: number; userVerification?: UserVerificationRequirement; @@ -20,7 +20,8 @@ type Options = { /** * Prepare a value to pass into navigator.credentials.get(...) for authenticator "login" * - * @param allowCredentials Authenticators previously registered by the user + * @param allowCredentials Authenticators previously registered by the user, if not provided + * device can ask user which credential he wants to use * @param challenge Random value the authenticator needs to sign and pass back * user for assertion * @param timeout How long (in ms) the user can take to complete assertion @@ -30,7 +31,7 @@ type Options = { * @param rpID Valid domain name (after `https://`) */ export default function generateAssertionOptions( - options: Options, + options: Options = {}, ): PublicKeyCredentialRequestOptionsJSON { const { allowCredentials, |