From 075b8821f212b3e7076a21fb69d42779e79d66e6 Mon Sep 17 00:00:00 2001 From: Hexagon Date: Tue, 28 Dec 2021 21:59:59 +0100 Subject: [PATCH] Replace @hexagon/base64-arraybuffer with @hexagon/base64 --- package-lock.json | 77 +++++++++++++++---------------- package.json | 4 +- public/static/index.html | 2 +- public/static/js/utils.js | 12 ++--- public/static/js/webauthn.auth.js | 6 +-- routes/webauthn.js | 16 +++---- utils/fido2.js | 6 +-- utils/token.js | 8 ++-- 8 files changed, 64 insertions(+), 67 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1fc632e..ca4a988 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { - "name": "webauthn-skeleton-koa", - "version": "0.0.9", + "name": "webauthn-skeleton", + "version": "0.9.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "webauthn-skeleton-koa", - "version": "0.0.9", + "name": "webauthn-skeleton", + "version": "0.9.0", "license": "MIT", "dependencies": { - "@hexagon/base64-arraybuffer": "^2.0.1", + "@hexagon/base64": "^1.0.11", "@koa/router": "^10.1.1", "fido2-lib": "^2.6.8", "koa": "^2.13.4", @@ -41,13 +41,10 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@hexagon/base64-arraybuffer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@hexagon/base64-arraybuffer/-/base64-arraybuffer-2.0.2.tgz", - "integrity": "sha512-c5UfXUzRstXiG8hhoF2hLi5bo9zuVQUAsOPwV4HIwRCUnZ0VXqYJDY3IQyDGiueoPbTJgwCJQQ9mqEjxH041SA==", - "engines": { - "node": ">= 0.6.0" - } + "node_modules/@hexagon/base64": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@hexagon/base64/-/base64-1.0.11.tgz", + "integrity": "sha512-MWzUVnLoj1XrXC5giDR2mwyp6uUYH6bjulIcvjiG/uyS/0mOdd4rbl9dslBbtO4j89Ke5Dj8D00IkVHPlrB85A==" }, "node_modules/@humanwhocodes/config-array": { "version": "0.9.2", @@ -139,9 +136,9 @@ } }, "node_modules/acorn": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", - "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -226,9 +223,9 @@ } }, "node_modules/asn1js": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-2.1.1.tgz", - "integrity": "sha512-t9u0dU0rJN4ML+uxgN6VM2Z4H5jWIYm0w8LsZLzMJaQsgL3IJNbxHgmbWDvJAwspyHpDFuzUaUFh4c05UB4+6g==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-2.2.0.tgz", + "integrity": "sha512-oagLNqpfNv7CvmyMoexMDNyVDSiq1rya0AEUgcLlNHdHgNl6U/hi8xY370n5y+ZIFEXOx0J4B1qF2NDjMRxklA==", "dependencies": { "pvutils": "latest" }, @@ -657,9 +654,9 @@ } }, "node_modules/eslint": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.4.1.tgz", - "integrity": "sha512-TxU/p7LB1KxQ6+7aztTnO7K0i+h0tDi81YRY9VzB6Id71kNz+fFYnf5HD5UOQmxkzcoa0TlVZf9dpMtUv0GpWg==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.5.0.tgz", + "integrity": "sha512-tVGSkgNbOfiHyVte8bCM8OmX+xG9PzVG/B4UCF60zx7j61WIVY/AqJECDgpLD4DbbESD0e174gOg3ZlrX15GDg==", "dev": true, "dependencies": { "@eslint/eslintrc": "^1.0.5", @@ -1533,9 +1530,9 @@ } }, "node_modules/object-inspect": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", - "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2098,10 +2095,10 @@ "strip-json-comments": "^3.1.1" } }, - "@hexagon/base64-arraybuffer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@hexagon/base64-arraybuffer/-/base64-arraybuffer-2.0.2.tgz", - "integrity": "sha512-c5UfXUzRstXiG8hhoF2hLi5bo9zuVQUAsOPwV4HIwRCUnZ0VXqYJDY3IQyDGiueoPbTJgwCJQQ9mqEjxH041SA==" + "@hexagon/base64": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@hexagon/base64/-/base64-1.0.11.tgz", + "integrity": "sha512-MWzUVnLoj1XrXC5giDR2mwyp6uUYH6bjulIcvjiG/uyS/0mOdd4rbl9dslBbtO4j89Ke5Dj8D00IkVHPlrB85A==" }, "@humanwhocodes/config-array": { "version": "0.9.2", @@ -2178,9 +2175,9 @@ } }, "acorn": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", - "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "dev": true }, "acorn-jsx": { @@ -2241,9 +2238,9 @@ } }, "asn1js": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-2.1.1.tgz", - "integrity": "sha512-t9u0dU0rJN4ML+uxgN6VM2Z4H5jWIYm0w8LsZLzMJaQsgL3IJNbxHgmbWDvJAwspyHpDFuzUaUFh4c05UB4+6g==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-2.2.0.tgz", + "integrity": "sha512-oagLNqpfNv7CvmyMoexMDNyVDSiq1rya0AEUgcLlNHdHgNl6U/hi8xY370n5y+ZIFEXOx0J4B1qF2NDjMRxklA==", "requires": { "pvutils": "latest" } @@ -2559,9 +2556,9 @@ "dev": true }, "eslint": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.4.1.tgz", - "integrity": "sha512-TxU/p7LB1KxQ6+7aztTnO7K0i+h0tDi81YRY9VzB6Id71kNz+fFYnf5HD5UOQmxkzcoa0TlVZf9dpMtUv0GpWg==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.5.0.tgz", + "integrity": "sha512-tVGSkgNbOfiHyVte8bCM8OmX+xG9PzVG/B4UCF60zx7j61WIVY/AqJECDgpLD4DbbESD0e174gOg3ZlrX15GDg==", "dev": true, "requires": { "@eslint/eslintrc": "^1.0.5", @@ -3249,9 +3246,9 @@ "integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==" }, "object-inspect": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", - "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==" + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" }, "on-finished": { "version": "2.3.0", diff --git a/package.json b/package.json index e8a5628..d386271 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "webauthn-skeleton", - "version": "0.9.0", + "version": "0.9.1", "description": "Skeleton for a Node.js powered Web Authentication API enabled website", "main": "app.js", "scripts": { @@ -32,7 +32,7 @@ "homepage": "https://github.com/hexagon/webauthn-skeleton#readme", "license": "MIT", "dependencies": { - "@hexagon/base64-arraybuffer": "^2.0.1", + "@hexagon/base64": "^1.0.11", "@koa/router": "^10.1.1", "fido2-lib": "^2.6.8", "koa": "^2.13.4", diff --git a/public/static/index.html b/public/static/index.html index 64a61b2..e653577 100644 --- a/public/static/index.html +++ b/public/static/index.html @@ -69,7 +69,7 @@

Your credentials

- + diff --git a/public/static/js/utils.js b/public/static/js/utils.js index 28fee6c..a57dc33 100644 --- a/public/static/js/utils.js +++ b/public/static/js/utils.js @@ -17,7 +17,7 @@ const publicKeyCredentialToJSON = (pubKeyCred) => { } if(pubKeyCred instanceof ArrayBuffer) { - return base64.encode(pubKeyCred,true); + return base64.fromArrayBuffer(pubKeyCred,true); } if(pubKeyCred instanceof Object) { @@ -37,12 +37,12 @@ const publicKeyCredentialToJSON = (pubKeyCred) => { * Decodes arrayBuffer required fields. */ let preformatMakeCredReq = (makeCredReq) => { - makeCredReq.challenge = base64.decode(makeCredReq.challenge,true); - makeCredReq.user.id = base64.decode(makeCredReq.user.id,true); + makeCredReq.challenge = base64.toArrayBuffer(makeCredReq.challenge,true); + makeCredReq.user.id = base64.toArrayBuffer(makeCredReq.user.id,true); // Decode id of each excludeCredentials if (makeCredReq.excludeCredentials) { - makeCredReq.excludeCredentials = makeCredReq.excludeCredentials.map((e) => { return { id: base64.decode(e.id, true), type: e.type };}); + makeCredReq.excludeCredentials = makeCredReq.excludeCredentials.map((e) => { return { id: base64.toArrayBuffer(e.id, true), type: e.type };}); } return makeCredReq; @@ -52,11 +52,11 @@ let preformatMakeCredReq = (makeCredReq) => { * Decodes arrayBuffer required fields. */ let preformatGetAssertReq = (getAssert) => { - getAssert.challenge = base64.decode(getAssert.challenge,true); + getAssert.challenge = base64.toArrayBuffer(getAssert.challenge,true); // Allow any credential, this will be handled later for(let allowCred of getAssert.allowCredentials) { - allowCred.id = base64.decode(allowCred.id,true); + allowCred.id = base64.toArrayBuffer(allowCred.id,true); } return getAssert; diff --git a/public/static/js/webauthn.auth.js b/public/static/js/webauthn.auth.js index 8add114..8f4d2f3 100644 --- a/public/static/js/webauthn.auth.js +++ b/public/static/js/webauthn.auth.js @@ -67,10 +67,10 @@ function register (username, additional) { .then((response) => { let makeCredResponse = { id: response.id, - rawId: base64.encode(response.rawId,true), + rawId: base64.fromArrayBuffer(response.rawId,true), response: { - attestationObject: base64.encode(response.response.attestationObject,true), - clientDataJSON: base64.encode(response.response.clientDataJSON,true) + attestationObject: base64.fromArrayBuffer(response.response.attestationObject,true), + clientDataJSON: base64.fromArrayBuffer(response.response.clientDataJSON,true) }, type: response.type }; diff --git a/routes/webauthn.js b/routes/webauthn.js index b293be6..3560554 100644 --- a/routes/webauthn.js +++ b/routes/webauthn.js @@ -4,7 +4,7 @@ const crypto = require("crypto"), database = require("../db/db"), username = require("../utils/username"), - base64url = require("@hexagon/base64-arraybuffer"), + base64 = require("@hexagon/base64"), router = require("@koa/router")({ prefix: "/webauthn" }), @@ -18,7 +18,7 @@ const let randomBase64URLBuffer = (len) => { len = len || 32; let buff = crypto.randomBytes(len); - return base64url.encode(buff, true); + return base64.fromArrayBuffer(buff, true); }; router.post("/register", async (ctx) => { @@ -93,7 +93,7 @@ router.post("/add", async (ctx) => { ctx.session.challenge = challengeMakeCred.challenge; // Exclude existing credentials - challengeMakeCred.excludeCredentials = database.users[ctx.session.username].authenticators.map((e) => { return { id: base64url.encode(e.credId, true), type: e.type }; }); + challengeMakeCred.excludeCredentials = database.users[ctx.session.username].authenticators.map((e) => { return { id: base64.fromArrayBuffer(e.credId, true), type: e.type }; }); // Respond with credentials return ctx.body = challengeMakeCred; @@ -128,7 +128,7 @@ router.post("/login", async (ctx) => { for(let authr of database.users[ctx.session.username].authenticators) { allowCredentials.push({ type: authr.type, - id: base64url.encode(authr.credId, true), + id: base64.fromArrayBuffer(authr.credId, true), transports: ["usb", "nfc", "ble","internal"] }); } @@ -152,8 +152,8 @@ router.post("/response", async (ctx) => { let webauthnResp = ctx.request.body; if(webauthnResp.response.attestationObject !== undefined) { /* This is create cred */ - webauthnResp.rawId = base64url.decode(webauthnResp.rawId, true); - webauthnResp.response.attestationObject = base64url.decode(webauthnResp.response.attestationObject, true); + webauthnResp.rawId = base64.toArrayBuffer(webauthnResp.rawId, true); + webauthnResp.response.attestationObject = base64.toArrayBuffer(webauthnResp.response.attestationObject, true); const result = await f2l.attestation(webauthnResp, config.origin, ctx.session.challenge); const token = { @@ -179,8 +179,8 @@ router.post("/response", async (ctx) => { // save the challenge in the session information... // send authnOptions to client and pass them in to `navigator.credentials.get()`... // get response back from client (clientAssertionResponse) - webauthnResp.rawId = base64url.decode(webauthnResp.rawId, true); - webauthnResp.response.userHandle = base64url.decode(webauthnResp.rawId, true); + webauthnResp.rawId = base64.toArrayBuffer(webauthnResp.rawId, true); + webauthnResp.response.userHandle = base64.toArrayBuffer(webauthnResp.rawId, true); let validAuthenticators = database.users[ctx.session.username].authenticators, winningAuthenticator; for(let authrIdx in validAuthenticators) { diff --git a/utils/fido2.js b/utils/fido2.js index cb00c55..a2d735d 100644 --- a/utils/fido2.js +++ b/utils/fido2.js @@ -1,6 +1,6 @@ const { Fido2Lib } = require("fido2-lib"), - base64url = require("@hexagon/base64-arraybuffer"); + base64 = require("@hexagon/base64"); class Fido2 { constructor(rpId, rpName, rpIcon, timeout) { @@ -29,7 +29,7 @@ class Fido2 { registrationOptions.status = "ok"; - registrationOptions.challenge = base64url.encode(registrationOptions.challenge, true); + registrationOptions.challenge = base64.fromArrayBuffer(registrationOptions.challenge, true); return registrationOptions; } @@ -46,7 +46,7 @@ class Fido2 { async login() { let assertionOptions = await this.f2l.assertionOptions(); - assertionOptions.challenge = base64url.encode(assertionOptions.challenge, true); + assertionOptions.challenge = base64.fromArrayBuffer(assertionOptions.challenge, true); assertionOptions.status = "ok"; return assertionOptions; } diff --git a/utils/token.js b/utils/token.js index 22e3a9b..b2c30c3 100644 --- a/utils/token.js +++ b/utils/token.js @@ -1,5 +1,5 @@ const - base64 = require("@hexagon/base64-arraybuffer"), + base64 = require("@hexagon/base64"), username = require("./username"), crypto = require("crypto"); @@ -9,7 +9,7 @@ const validate = (usernameInput, token, tokenValidator) => { // Try decoding token from base64url let tokenDecoded; try { - tokenDecoded = base64.decode(token, true); + tokenDecoded = base64.toArrayBuffer(token, true); } catch (e) { return false; } @@ -22,7 +22,7 @@ const validate = (usernameInput, token, tokenValidator) => { return false; } else if (tokenValidator.expires < timeNow) { return false; - } else if (base64.encode(tokenValidator.token,true) !== base64.encode(tokenDecoded, true)) { + } else if (base64.fromArrayBuffer(tokenValidator.token,true) !== base64.fromArrayBuffer(tokenDecoded, true)) { return false; } else { // Success! @@ -59,7 +59,7 @@ const generate = (usernameInput, expireMs) => { // Encode token to base64url format const encode = (token) => { - return base64.encode(token, true); + return base64.fromArrayBuffer(token, true); }; module.exports = {