Drivers: Add web debug logs (#314)

This commit is contained in:
Michał Leszczyński
2024-05-09 00:31:34 +02:00
committed by GitHub
parent b685128087
commit 8d573104e2
5 changed files with 113 additions and 4 deletions

View File

@@ -108,6 +108,15 @@ Please check [documentation of the available commands (HaLo Command Set)](/docs/
* **NFCOperationError**: There was a low-level failure during NFC interaction. Check `ex.message` for more details.
# Debugging through the developer's console
In case when you are suspecting some bugs related with LibHaLo or HaLo cards themselves and need a more detailed debugging, it is possible
to enable additional debug printouts for the web drivers.
Debug printouts are enabled by executing the following code, either in your application using LibHaLo or straight in the developer's console prompt itself:
```
localStorage.setItem('DEBUG_LIBHALO_WEB', '1')
```
# Helper methods exclusive to the web environment
## haloGetDefaultMethod()

View File

@@ -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({

View File

@@ -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 = {};

View File

@@ -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",

View File

@@ -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
};