Fix Electron cloud cert verification (use Node https, not net.fetch)

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) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 08:39:20 -04:00
parent e7dee4f5db
commit 407892ed9a
+23 -4
View File
@@ -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' };
}