summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAntoine Cormouls <contact.antoine.cormouls@gmail.com>2020-12-04 15:01:35 +0100
committerAntoine Cormouls <contact.antoine.cormouls@gmail.com>2020-12-04 15:01:35 +0100
commit5f508216dc3ee38a7f17c038b367e8575ab14929 (patch)
treebf95db1232a6aa8dba52eea31ec6840d3eaca977
parent4f1a0ab1225a34788d3c1f9bf4a9c0b7cc31b17b (diff)
Optional Allow Credential
-rw-r--r--README.md6
-rw-r--r--package.json4
-rw-r--r--packages/browser/src/methods/startAssertion.test.ts25
-rw-r--r--packages/browser/src/methods/startAssertion.ts7
-rw-r--r--packages/server/src/assertion/generateAssertionOptions.test.ts19
-rw-r--r--packages/server/src/assertion/generateAssertionOptions.ts7
6 files changed, 56 insertions, 12 deletions
diff --git a/README.md b/README.md
index b476f8d..1b5f260 100644
--- a/README.md
+++ b/README.md
@@ -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,