diff options
Diffstat (limited to 'packages/browser')
-rw-r--r-- | packages/browser/package-lock.json | 6 | ||||
-rw-r--r-- | packages/browser/package.json | 6 | ||||
-rw-r--r-- | packages/browser/src/helpers/toBase64String.test.ts | 15 | ||||
-rw-r--r-- | packages/browser/src/helpers/toBase64String.ts | 3 | ||||
-rw-r--r-- | packages/browser/src/helpers/toUint8Array.ts | 4 | ||||
-rw-r--r-- | packages/browser/src/methods/startAssertion.test.ts | 22 | ||||
-rw-r--r-- | packages/browser/src/methods/startAssertion.ts | 15 |
7 files changed, 50 insertions, 21 deletions
diff --git a/packages/browser/package-lock.json b/packages/browser/package-lock.json index 14d089e..7edf0fd 100644 --- a/packages/browser/package-lock.json +++ b/packages/browser/package-lock.json @@ -1,6 +1,6 @@ { "name": "@webauthntine/browser", - "version": "0.1.1", + "version": "0.1.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -185,6 +185,10 @@ "@xtuc/long": "4.2.2" } }, + "@webauthntine/typescript-types": { + "version": "file:../typescript-types", + "dev": true + }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", diff --git a/packages/browser/package.json b/packages/browser/package.json index 5bb63c0..9e5862a 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -1,6 +1,6 @@ { "name": "@webauthntine/browser", - "version": "0.1.1", + "version": "0.1.2", "description": "WebAuthntine for Browsers", "main": "dist/webauthntine-browser.min.js", "types": "dist/index.d.ts", @@ -15,7 +15,7 @@ "test": "jest", "test:watch": "jest --watch", "test:coverage": "npm test -- --coverage", - "prepare": "npm run build" + "prepublish": "npm run build" }, "keywords": [ "webauthn", @@ -26,7 +26,7 @@ }, "devDependencies": { "@types/base64-js": "^1.2.5", - "@webauthntine/typescript-types": "^0.1.1", + "@webauthntine/typescript-types": "file:../typescript-types", "ts-loader": "^7.0.4", "webpack": "^4.43.0", "webpack-auto-inject-version": "^1.2.2", diff --git a/packages/browser/src/helpers/toBase64String.test.ts b/packages/browser/src/helpers/toBase64String.test.ts new file mode 100644 index 0000000..bbcb11b --- /dev/null +++ b/packages/browser/src/helpers/toBase64String.test.ts @@ -0,0 +1,15 @@ +import toBase64String from './toBase64String'; + +import toUint8Array from './toUint8Array'; + +test('should convert a Buffer to a string with a length that is a multiple of 4', () => { + const base64 = toBase64String(Buffer.from('123456', 'ascii')); + + expect(base64.length % 4).toEqual(0); +}); + +test('should convert a Uint8Array to a string with a length that is a multiple of 4', () => { + const base64 = toBase64String(toUint8Array('123456')); + + expect(base64.length % 4).toEqual(0); +}); diff --git a/packages/browser/src/helpers/toBase64String.ts b/packages/browser/src/helpers/toBase64String.ts index 8234002..9c949be 100644 --- a/packages/browser/src/helpers/toBase64String.ts +++ b/packages/browser/src/helpers/toBase64String.ts @@ -4,6 +4,5 @@ export default function toBase64String(buffer: ArrayBuffer): string { // TODO: Make sure converting buffer to Uint8Array() is correct return base64js.fromByteArray(new Uint8Array(buffer)) .replace(/\+/g, "-") - .replace(/\//g, "_") - .replace(/=/g, ""); + .replace(/\//g, "_"); } diff --git a/packages/browser/src/helpers/toUint8Array.ts b/packages/browser/src/helpers/toUint8Array.ts index a807a88..ed4aa5d 100644 --- a/packages/browser/src/helpers/toUint8Array.ts +++ b/packages/browser/src/helpers/toUint8Array.ts @@ -1,6 +1,6 @@ /** - * A helper method to convert a string sent from the server to a Uint8Array the authenticator will - * expect. + * A helper method to convert an arbitrary string sent from the server to a Uint8Array the + * authenticator will expect. */ export default function toUint8Array(value: string): Uint8Array { return Uint8Array.from(value, c => c.charCodeAt(0)); diff --git a/packages/browser/src/methods/startAssertion.test.ts b/packages/browser/src/methods/startAssertion.test.ts index b069f60..4e3bb07 100644 --- a/packages/browser/src/methods/startAssertion.test.ts +++ b/packages/browser/src/methods/startAssertion.test.ts @@ -4,6 +4,7 @@ import { AssertionCredential, PublicKeyCredentialRequestOptionsJSON } from '@web import toUint8Array from '../helpers/toUint8Array'; import supportsWebauthn from '../helpers/supportsWebauthn'; +import toBase64String from '../helpers/toBase64String'; import startAssertion from './startAssertion'; @@ -12,10 +13,10 @@ jest.mock('../helpers/supportsWebauthn'); const mockNavigatorGet = (window.navigator.credentials.get as jest.Mock); const mockSupportsWebauthn = (supportsWebauthn as jest.Mock); -const mockAttestationObject = 'mockAsse'; -const mockClientDataJSON = 'mockClie'; -const mockSignature = 'mockSign'; -const mockUserHandle = 'mockUser'; +const mockAuthenticatorData = toBase64String(toUint8Array('mockAuthenticatorData')); +const mockClientDataJSON = toBase64String(toUint8Array('mockClientDataJSON')); +const mockSignature = toBase64String(toUint8Array('mockSignature')); +const mockUserHandle = toBase64String(toUint8Array('mockUserHandle')); const goodOpts1: PublicKeyCredentialRequestOptionsJSON = { publicKey: { @@ -49,9 +50,9 @@ test('should convert options before passing to navigator.credentials.get(...)', const argsPublicKey = mockNavigatorGet.mock.calls[0][0].publicKey; expect(argsPublicKey.challenge).toEqual(toUint8Array(goodOpts1.publicKey.challenge)); - expect(argsPublicKey.allowCredentials[0].id).toEqual( - toUint8Array(goodOpts1.publicKey.allowCredentials[0].id), - ); + // Make sure the credential ID is a proper base64 with a length that's a multiple of 4 + expect(argsPublicKey.allowCredentials[0].id.length % 4).toEqual(0); + expect(argsPublicKey.allowCredentials[0].id).toEqual(base64js.toByteArray('credId==')); done(); }); @@ -59,14 +60,16 @@ test('should convert options before passing to navigator.credentials.get(...)', test('should return base64-encoded response values', async (done) => { mockSupportsWebauthn.mockReturnValue(true); + const credentialID = 'foobar'; + mockNavigatorGet.mockImplementation((): Promise<AssertionCredential> => { return new Promise((resolve) => { resolve({ id: 'foobar', rawId: toUint8Array('foobar'), response: { + authenticatorData: base64js.toByteArray(mockAuthenticatorData), clientDataJSON: base64js.toByteArray(mockClientDataJSON), - authenticatorData: base64js.toByteArray(mockClientDataJSON), signature: base64js.toByteArray(mockSignature), userHandle: base64js.toByteArray(mockUserHandle), }, @@ -79,7 +82,8 @@ test('should return base64-encoded response values', async (done) => { const response = await startAssertion(goodOpts1); expect(response).toEqual({ - base64AuthenticatorData: mockClientDataJSON, + base64CredentialID: credentialID, + base64AuthenticatorData: mockAuthenticatorData, base64ClientDataJSON: mockClientDataJSON, base64Signature: mockSignature, base64UserHandle: mockUserHandle, diff --git a/packages/browser/src/methods/startAssertion.ts b/packages/browser/src/methods/startAssertion.ts index 603c6fb..8e411ec 100644 --- a/packages/browser/src/methods/startAssertion.ts +++ b/packages/browser/src/methods/startAssertion.ts @@ -3,6 +3,7 @@ import { AuthenticatorAssertionResponseJSON, AssertionCredential, } from '@webauthntine/typescript-types'; +import base64js from 'base64-js'; import toUint8Array from '../helpers/toUint8Array'; import toBase64String from '../helpers/toBase64String'; @@ -24,10 +25,15 @@ export default async function startAssertion( const publicKey: PublicKeyCredentialRequestOptions = { ...requestOptionsJSON.publicKey, challenge: toUint8Array(requestOptionsJSON.publicKey.challenge), - allowCredentials: requestOptionsJSON.publicKey.allowCredentials.map((cred) => ({ - ...cred, - id: toUint8Array(cred.id), - })) + allowCredentials: requestOptionsJSON.publicKey.allowCredentials.map((cred) => { + // Make sure the credential ID length is a multiple of 4 + let id = cred.id.padEnd(cred.id.length + (cred.id.length % 4), '='); + + return { + ...cred, + id: base64js.toByteArray(id), + }; + }) }; // Wait for the user to complete assertion @@ -46,6 +52,7 @@ export default async function startAssertion( // Convert values to base64 to make it easier to send back to the server return { + base64CredentialID: credential.id, base64AuthenticatorData: toBase64String(response.authenticatorData), base64ClientDataJSON: toBase64String(response.clientDataJSON), base64Signature: toBase64String(response.signature), |