From 407892ed9adc1cc9d6184ecfe564a455f7dc21ba Mon Sep 17 00:00:00 2001 From: PageZ948 Date: Wed, 3 Jun 2026 08:39:20 -0400 Subject: [PATCH] Fix Electron cloud cert verification (use Node https, not net.fetch) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Alta verify endpoint requests an optional TLS client certificate. Chromium's network stack (net.fetch) reacts by aborting the handshake with ERR_SSL_CLIENT_AUTH_CERT_NEEDED, and the select-client-certificate event never fires to let us proceed — so cloud verification silently failed only in the desktop build, looking like the app was offline. Issue the request via Node's https module instead, matching the Python app.py reference (urlopen) and curl, which ignore the optional client- cert request and proceed normally. Same 2xx-means-verified semantics, 10s timeout, and return shape. Co-Authored-By: Claude Opus 4.8 (1M context) --- electron/main.js | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/electron/main.js b/electron/main.js index ab62977..b97d95a 100644 --- a/electron/main.js +++ b/electron/main.js @@ -1,6 +1,7 @@ -const { app, BrowserWindow, ipcMain, net, protocol, shell } = require('electron'); +const { app, BrowserWindow, ipcMain, protocol, shell } = require('electron'); const fs = require('node:fs/promises'); const path = require('node:path'); +const https = require('node:https'); const APP_SCHEME = 'webavp'; const ROOT_DIR = path.resolve(__dirname, '..'); @@ -92,6 +93,24 @@ function registerAppProtocol() { }); } +// Issue the GET via Node's https stack (not Electron's net.fetch). The Alta +// endpoint requests an optional TLS client certificate; Chromium's net stack +// reacts by failing the handshake with ERR_SSL_CLIENT_AUTH_CERT_NEEDED, which +// made cloud verification appear "offline" in the desktop build. Node's TLS +// (like curl and the Python app.py reference) simply proceeds without one. +function httpsGetStatus(url, timeoutMs = 10000) { + return new Promise((resolve, reject) => { + const req = https.get(url, (res) => { + res.resume(); // drain so the socket is released + resolve(res.statusCode); + }); + req.on('error', reject); + req.setTimeout(timeoutMs, () => { + req.destroy(new Error('Certificate verification request timed out')); + }); + }); +} + async function verifyCertificateOnline(_event, { serial, certificateHash } = {}) { if (!serial || !certificateHash) { return { verified: false, error: 'Missing parameters' }; @@ -104,11 +123,11 @@ async function verifyCertificateOnline(_event, { serial, certificateHash } = {}) const url = `https://aware.avasecurity.com/api/v1/public/verifyServerCertificate?${params.toString()}`; try { - const response = await net.fetch(url, { method: 'GET' }); - if (response.ok) { + const status = await httpsGetStatus(url); + if (status >= 200 && status < 300) { return { verified: true }; } - return { verified: false, error: `HTTP ${response.status}` }; + return { verified: false, error: `HTTP ${status}` }; } catch (err) { return { verified: false, error: err.message || 'Certificate verification request failed' }; }