From f943ef570afb39d22c2990b532d3c9610cb8ffac Mon Sep 17 00:00:00 2001 From: Michal Leszczynski Date: Wed, 8 May 2024 19:08:37 +0200 Subject: [PATCH] Drivers: Introduce console debug logs. --- drivers/credential.js | 30 ++++++++++++++++++-- drivers/web.js | 6 ++++ drivers/webnfc.js | 65 ++++++++++++++++++++++++++++++++++++++++++- halo/util.js | 7 ++++- 4 files changed, 104 insertions(+), 4 deletions(-) diff --git a/drivers/credential.js b/drivers/credential.js index 0d336f0..c181934 100644 --- a/drivers/credential.js +++ b/drivers/credential.js @@ -4,13 +4,19 @@ * License: MIT */ -const {HaloTagError, HaloLogicError, NFCOperationError, NFCMethodNotSupported} = require("../halo/exceptions"); +const {HaloTagError, NFCOperationError, NFCMethodNotSupported} = require("../halo/exceptions"); const {ERROR_CODES} = require("../halo/errors"); -const {arr2hex} = require("../halo/util"); +const {arr2hex, isWebDebugEnabled} = require("../halo/util"); const FLAG_USE_NEW_MODE = 0x00; async function execCredential(request, options) { + const webDebug = isWebDebugEnabled(); + + if (webDebug) { + console.log('[libhalo] execCredential() request:', arr2hex(request)); + } + if (!window.isSecureContext) { throw new NFCMethodNotSupported("This method can be invoked only in the secure context (HTTPS)."); } @@ -42,6 +48,10 @@ async function execCredential(request, options) { "signal": ctrl.signal }; + if (webDebug) { + console.log('[libhalo] execCredential() req:', u2fReq); + } + let u2fRes; options.statusCallback("init", { @@ -53,6 +63,10 @@ async function execCredential(request, options) { try { u2fRes = await navigator.credentials.get(u2fReq); } catch (e) { + if (webDebug) { + console.log('[libhalo] execCredential() exception:', e); + } + if (e.name === "NotSupportedError") { throw new NFCMethodNotSupported("The call threw NotSupportedError. Please update your browser."); } else { @@ -60,6 +74,10 @@ async function execCredential(request, options) { } } + if (webDebug) { + console.log('[libhalo] execCredential() res:', u2fRes); + } + options.statusCallback("scanned", { execMethod: "credential", execStep: "get-credential-done", @@ -70,6 +88,10 @@ async function execCredential(request, options) { let resBuf = new Uint8Array(res); if (resBuf.length === 2 && resBuf[0] === 0xE1) { + if (webDebug) { + console.log('[libhalo] execCredential() command fail:', arr2hex(resBuf)); + } + if (ERROR_CODES.hasOwnProperty(resBuf[1])) { let err = ERROR_CODES[resBuf[1]]; throw new HaloTagError(err[0], err[1]); @@ -78,6 +100,10 @@ async function execCredential(request, options) { } } + if (webDebug) { + console.log('[libhalo] execCredential() command result:', arr2hex(resBuf)); + } + return await new Promise((resolve, reject) => { setTimeout(() => { resolve({ diff --git a/drivers/web.js b/drivers/web.js index 3b177dc..ef40d95 100644 --- a/drivers/web.js +++ b/drivers/web.js @@ -3,6 +3,7 @@ const {execCredential} = require("./credential"); const {execWebNFC} = require("./webnfc"); const {execHaloCmd} = require("./common"); const {emulatedPromptStatusCallback} = require("../web/soft_prompt"); +const {isWebDebugEnabled} = require("../halo/util"); let isCallRunning = null; @@ -63,6 +64,11 @@ async function execHaloCmdWeb(command, options) { command = command ? Object.assign({}, command) : {}; + if (isWebDebugEnabled()) { + console.log('[libhalo] execHaloCmdWeb() command:', command); + console.log('[libhalo] execHaloCmdWeb() options:', options); + } + try { let cmdOpts = {}; diff --git a/drivers/webnfc.js b/drivers/webnfc.js index 152918a..65ab4b8 100644 --- a/drivers/webnfc.js +++ b/drivers/webnfc.js @@ -11,7 +11,7 @@ const { NFCPermissionRequestDenied, NFCAbortedError } = require("../halo/exceptions"); -const {arr2hex, hex2arr} = require("../halo/util"); +const {arr2hex, hex2arr, isWebDebugEnabled} = require("../halo/util"); let ndef = null; let ctrl = null; @@ -53,15 +53,30 @@ async function checkWebNFCPermission() { } async function execWebNFC(request, options) { + const webDebug = isWebDebugEnabled(); + + if (webDebug) { + console.log('[libhalo] execWebNFC() request:', arr2hex(request)); + console.log('[libhalo] execWebNFC() checking WebNFC permission') + } + let isWebNFCGranted; try { isWebNFCGranted = await checkWebNFCPermission(); } catch (e) { + if (webDebug) { + console.log('[libhalo] execWebNFC() internal error checking WebNFC permission:', e); + } + throw new NFCMethodNotSupported("Internal error when checking WebNFC permission: " + e.toString()); } if (!isWebNFCGranted) { + if (webDebug) { + console.log('[libhalo] execWebNFC() WebNFC permission is denied'); + } + throw new NFCPermissionRequestDenied("NFC permission request denied by the user."); } @@ -75,6 +90,10 @@ async function execWebNFC(request, options) { try { ndef = new NDEFReader(); } catch (e) { + if (webDebug) { + console.log('[libhalo] execWebNFC() failed createing NDEFReader'); + } + if (e instanceof ReferenceError) { throw new NFCMethodNotSupported("Method is not supported by the browser or device."); } else { @@ -112,6 +131,10 @@ async function execWebNFC(request, options) { }); } + if (webDebug) { + console.log('[libhalo] execWebNFC() performing write:', request); + } + await ndef.write({ records: [{recordType: "unknown", data: request}] }, { @@ -119,6 +142,10 @@ async function execWebNFC(request, options) { }); break; } catch (e) { + if (webDebug) { + console.log('[libhalo] execWebNFC() write exception:', e); + } + if (e.name === "NotAllowedError") { throw new NFCPermissionRequestDenied("NFC permission request denied by the user."); } else if (e.name === "AbortError") { @@ -129,6 +156,10 @@ async function execWebNFC(request, options) { } } + if (webDebug) { + console.log('[libhalo] execWebNFC() performing read'); + } + await ndef.scan({signal: ctrl.signal}); options.statusCallback("again", { @@ -139,14 +170,26 @@ async function execWebNFC(request, options) { return new Promise((resolve, reject) => { ctrl.signal.addEventListener('abort', () => { + if (webDebug) { + console.log('[libhalo] execWebNFC() operation aborted during read'); + } + reject(new NFCAbortedError("Operation restarted by the user or webpage minimized (during read).")); }); if (ctrl.signal.aborted) { + if (webDebug) { + console.log('[libhalo] execWebNFC() operation aborted during read'); + } + reject(new NFCAbortedError("Operation restarted by the user or webpage minimized (during read).")); } ndef.onreadingerror = (event) => { + if (webDebug) { + console.log('[libhalo] execWebNFC() read error'); + } + options.statusCallback("retry", { execMethod: "webnfc", execStep: "nfc-read-error", @@ -155,11 +198,19 @@ async function execWebNFC(request, options) { }; ndef.onreading = (event) => { + if (webDebug) { + console.log('[libhalo] execWebNFC() read event received, parsing'); + } + try { let out = {}; let decoded = new TextDecoder("utf-8").decode(event.message.records[0].data); let url = new URL(decoded); + if (webDebug) { + console.log('[libhalo] execWebNFC() read result url:', url); + } + for (let k of url.searchParams.keys()) { out[k] = url.searchParams.get(k); } @@ -167,6 +218,10 @@ async function execWebNFC(request, options) { let resBuf = hex2arr(out.res); if (resBuf[0] === 0xE1) { + if (webDebug) { + console.log('[libhalo] execWebNFC() command fail:', arr2hex(resBuf)); + } + if (ERROR_CODES.hasOwnProperty(resBuf[1])) { let err = ERROR_CODES[resBuf[1]]; ndef.onreading = () => null; @@ -192,6 +247,10 @@ async function execWebNFC(request, options) { delete out['res']; + if (webDebug) { + console.log('[libhalo] execWebNFC() command result:', arr2hex(resBuf)); + } + setTimeout(() => { resolve({ result: arr2hex(resBuf), @@ -199,6 +258,10 @@ async function execWebNFC(request, options) { }); }, 1); } catch (e) { + if (webDebug) { + console.log('[libhalo] execWebNFC() parse error:', e); + } + options.statusCallback("retry", { execMethod: "webnfc", execStep: "nfc-parse-error", diff --git a/halo/util.js b/halo/util.js index eabbc63..719ea50 100644 --- a/halo/util.js +++ b/halo/util.js @@ -187,6 +187,10 @@ function randomBuffer() { return Buffer.from(crypto.getRandomValues(new Uint8Array(32))); } +function isWebDebugEnabled() { + return window.localStorage.getItem("DEBUG_LIBHALO_WEB") === "1"; +} + module.exports = { SECP256k1_ORDER, BJJ_ORDER, @@ -198,5 +202,6 @@ module.exports = { parsePublicKeys, recoverPublicKey, mode, - randomBuffer + randomBuffer, + isWebDebugEnabled };