From 2774a5722708faa05de1e49874721291279a88b8 Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 5 Dec 2025 13:31:18 -0700 Subject: [PATCH 1/3] fix: Gracefully handle missing native BetaflightSerial plugin Ensure CapacitorSerial instance is fully initialized even without the native plugin, preventing runtime errors when methods are called. All native calls are now guarded. --- src/js/protocols/CapacitorSerial.js | 34 ++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/js/protocols/CapacitorSerial.js b/src/js/protocols/CapacitorSerial.js index ed9a37bad8..2c013fba8b 100644 --- a/src/js/protocols/CapacitorSerial.js +++ b/src/js/protocols/CapacitorSerial.js @@ -12,9 +12,10 @@ class CapacitorSerial extends EventTarget { constructor() { super(); - if (!BetaflightSerial) { + this.pluginAvailable = !!BetaflightSerial; + + if (!this.pluginAvailable) { console.error(`${logHead} Native BetaflightSerial plugin is not available`); - return; } this.connected = false; @@ -36,15 +37,15 @@ class CapacitorSerial extends EventTarget { this.handleDeviceAttached = this.handleDeviceAttached.bind(this); this.handleDeviceDetached = this.handleDeviceDetached.bind(this); - // Listen for data received from native plugin - BetaflightSerial.addListener("dataReceived", this.handleDataReceived); - - // Listen for device attach/detach events - BetaflightSerial.addListener("deviceAttached", this.handleDeviceAttached); - BetaflightSerial.addListener("deviceDetached", this.handleDeviceDetached); + // Listen for data received from native plugin and load devices if plugin is available + if (this.pluginAvailable) { + BetaflightSerial.addListener("dataReceived", this.handleDataReceived); + BetaflightSerial.addListener("deviceAttached", this.handleDeviceAttached); + BetaflightSerial.addListener("deviceDetached", this.handleDeviceDetached); - // Load initial device list - this.loadDevices(); + // Load initial device list + this.loadDevices(); + } console.log(`${logHead} CapacitorSerial initialized`); } @@ -125,6 +126,8 @@ class CapacitorSerial extends EventTarget { } async loadDevices() { + if (!this.pluginAvailable) return; + try { const result = await BetaflightSerial.getDevices(); this.ports = result.devices.map((device) => this.createPort(device)); @@ -137,6 +140,8 @@ class CapacitorSerial extends EventTarget { async requestPermissionDevice() { let newPermissionPort = null; + if (!this.pluginAvailable) return null; + try { console.log(`${logHead} Requesting USB permissions...`); const userSelectedPort = await BetaflightSerial.requestPermission(); @@ -159,6 +164,8 @@ class CapacitorSerial extends EventTarget { } async connect(path, options) { + if (!this.pluginAvailable) return false; + const baudRate = options?.baudRate ?? 115200; // Prevent double connections if (this.connected) { @@ -232,6 +239,8 @@ class CapacitorSerial extends EventTarget { } async disconnect() { + if (!this.pluginAvailable) return true; + if (!this.connected) { return true; } @@ -255,6 +264,11 @@ class CapacitorSerial extends EventTarget { } async send(data, callback) { + if (!this.pluginAvailable) { + if (callback) callback({ bytesSent: 0 }); + return { bytesSent: 0 }; + } + if (!this.connected) { console.error(`${logHead} Failed to send data, not connected`); if (callback) { From b1626550701e44574da79703a68284622a996e79 Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 5 Dec 2025 13:32:35 -0700 Subject: [PATCH 2/3] fix: Add validation to hexStringToUint8Array in CapacitorSerial Validate input hex strings: strip '0x', enforce even length, and check character validity before parsing, throwing descriptive errors on failure. --- src/js/protocols/CapacitorSerial.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/js/protocols/CapacitorSerial.js b/src/js/protocols/CapacitorSerial.js index 2c013fba8b..94df09cb7c 100644 --- a/src/js/protocols/CapacitorSerial.js +++ b/src/js/protocols/CapacitorSerial.js @@ -309,6 +309,21 @@ class CapacitorSerial extends EventTarget { return new Uint8Array(0); } + // Strip 0x prefix + if (hexString.startsWith("0x") || hexString.startsWith("0X")) { + hexString = hexString.slice(2); + } + + // Validate characters + if (!/^[0-9a-fA-F]+$/.test(hexString)) { + throw new Error(`Invalid hex string: contains non-hex characters`); + } + + // Validate length + if (hexString.length % 2 !== 0) { + throw new Error(`Invalid hex string: odd length (${hexString.length})`); + } + const bytes = new Uint8Array(hexString.length / 2); for (let i = 0; i < hexString.length; i += 2) { bytes[i / 2] = Number.parseInt(hexString.substring(i, i + 2), 16); From 61f5c65887576b56b4a09aa748a27f5374029383 Mon Sep 17 00:00:00 2001 From: Eric Date: Sun, 7 Dec 2025 11:19:33 -0700 Subject: [PATCH 3/3] style: Apply lint fixes to CapacitorSerial --- src/js/protocols/CapacitorSerial.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/js/protocols/CapacitorSerial.js b/src/js/protocols/CapacitorSerial.js index 94df09cb7c..2a21944d9f 100644 --- a/src/js/protocols/CapacitorSerial.js +++ b/src/js/protocols/CapacitorSerial.js @@ -126,7 +126,9 @@ class CapacitorSerial extends EventTarget { } async loadDevices() { - if (!this.pluginAvailable) return; + if (!this.pluginAvailable) { + return; + } try { const result = await BetaflightSerial.getDevices(); @@ -140,7 +142,9 @@ class CapacitorSerial extends EventTarget { async requestPermissionDevice() { let newPermissionPort = null; - if (!this.pluginAvailable) return null; + if (!this.pluginAvailable) { + return null; + } try { console.log(`${logHead} Requesting USB permissions...`); @@ -164,7 +168,9 @@ class CapacitorSerial extends EventTarget { } async connect(path, options) { - if (!this.pluginAvailable) return false; + if (!this.pluginAvailable) { + return false; + } const baudRate = options?.baudRate ?? 115200; // Prevent double connections @@ -239,7 +245,9 @@ class CapacitorSerial extends EventTarget { } async disconnect() { - if (!this.pluginAvailable) return true; + if (!this.pluginAvailable) { + return true; + } if (!this.connected) { return true; @@ -265,7 +273,9 @@ class CapacitorSerial extends EventTarget { async send(data, callback) { if (!this.pluginAvailable) { - if (callback) callback({ bytesSent: 0 }); + if (callback) { + callback({ bytesSent: 0 }); + } return { bytesSent: 0 }; }