fix(ca): silent install to login keychain with SSL policy — no sudo or Terminal needed
CI / Build & Test (push) Successful in 2m29s

Made-with: Cursor
This commit is contained in:
Raven Scott
2026-02-27 19:51:01 -05:00
parent eecdc98cb2
commit b0b17e26df
2 changed files with 18 additions and 70 deletions
+18 -67
View File
@@ -173,69 +173,25 @@ function installRootCA(callback) {
}
function addToSystemKeychain(done) {
// The native host is a background daemon with no GUI session.
// osascript "with administrator privileges" and launchctl asuser both
// fail without root. Solution: write a .command file and open it with
// `open` — macOS launches it in Terminal.app inside the user's GUI
// session, which can show the sudo password prompt. Poll a flag file
// to know when it completes.
const home = process.env.HOME || '';
const tmpCmd = path.join(home, '.holesail-install-ca.command');
const tmpDone = path.join(home, '.holesail-ca-done');
const tmpErr = path.join(home, '.holesail-ca-err');
try { fs.unlinkSync(tmpDone); } catch (_) {}
try { fs.unlinkSync(tmpErr); } catch (_) {}
const script = [
'#!/bin/bash',
`sudo security add-trusted-cert -d -r trustRoot -k "${systemKeychain}" "${caPath}"`,
'if [ $? -eq 0 ]; then',
` echo ok > "${tmpDone}"`,
' echo ""',
' echo "Holesail Browser CA installed successfully. You can close this window."',
'else',
` echo fail > "${tmpErr}"`,
' echo ""',
' echo "Installation failed. Please try again."',
'fi',
'sleep 3',
`rm -f "${tmpCmd}"`,
].join('\n');
try {
fs.writeFileSync(tmpCmd, script, { mode: 0o755 });
} catch (e) {
done(new Error('Could not write install script: ' + e.message));
// Install to the user's login keychain with explicit SSL trust policy.
// This requires no sudo/admin password and Chrome respects it because
// it evaluates TLS trust using the SSL policy against all user keychains.
// The -p ssl flag sets the correct policy OID that Chrome checks.
const loginKc = home ? path.join(home, 'Library', 'Keychains', 'login.keychain-db') : null;
if (!loginKc) {
done(new Error('HOME not set; cannot determine login keychain path'));
return;
}
runCommand(`open "${tmpCmd}"`, (errOpen) => {
if (errOpen) {
try { fs.unlinkSync(tmpCmd); } catch (_) {}
done(new Error('Could not open Terminal to install CA: ' + errOpen.message));
const cmd = `security add-trusted-cert -r trustRoot -p ssl -k "${loginKc}" "${caPath}"`;
runCommand(cmd, (err, _stdout, stderr) => {
if (!err) {
logInfo('CA', 'Root CA installed to login keychain with SSL trust (trusted by Chrome).');
done(null);
return;
}
// Poll for completion flag (up to 120s for user to enter password)
let waited = 0;
const interval = setInterval(() => {
waited += 1000;
if (fs.existsSync(tmpDone)) {
clearInterval(interval);
try { fs.unlinkSync(tmpDone); } catch (_) {}
logInfo('CA', 'Root CA installed to System keychain.');
done(null);
} else if (fs.existsSync(tmpErr)) {
clearInterval(interval);
try { fs.unlinkSync(tmpErr); } catch (_) {}
done(new Error('CA installation failed. Make sure you entered the correct password.'));
} else if (waited >= 120000) {
clearInterval(interval);
try { fs.unlinkSync(tmpCmd); } catch (_) {}
done(new Error('Timed out waiting for CA installation.'));
}
}, 1000);
const msg = (stderr || err.message || '').trim();
logError('CA', 'add-trusted-cert failed: ' + msg);
done(new Error('Could not install CA: ' + msg));
});
}
@@ -387,15 +343,10 @@ function getCertsDir() {
function isRootCAInstalled(callback) {
if (platform === 'darwin') {
// Use verify-cert which checks actual trust evaluation (not just presence in keychain).
// Exit 0 = trusted, non-zero = not trusted or not found.
// verify-cert -p ssl checks the SSL trust policy across all keychains
// (system + login). Exit 0 = trusted, non-zero = not trusted.
runCommand(`security verify-cert -p ssl -c "${caCertPath}" 2>/dev/null`, (err) => {
if (!err) { callback(true); return; }
// Also check the system domain trust settings directly as a fallback
runCommand(`security dump-trust-settings -d 2>/dev/null | grep -c "${CA_COMMON_NAME}"`, (err2, stdout) => {
const count = parseInt((stdout || '').trim(), 10);
callback(!isNaN(count) && count > 0);
});
callback(!err);
});
} else if (platform === 'win32') {
// On Windows, match by the SHA-1 fingerprint of the current CA on disk