[eric] passkey: enable macOS Touch ID WebAuthn (electron 42.0.0->42.3.3 for the localizedReason crash fix + Developer ID provisioning profile + keychain entitlement; reject-shim now Windows-only)

This commit is contained in:
ciregenz
2026-06-28 15:10:59 -07:00
parent fc62986603
commit cfaddf1126
7 changed files with 59 additions and 11 deletions
Binary file not shown.
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>
+5
View File
@@ -16,5 +16,10 @@
<true/>
<key>com.apple.security.inherit</key>
<true/>
<!-- Secure-Enclave WebAuthn credential storage (Touch ID passkeys). Authorized by the embedded Developer ID provisioning profile (Y26NUZH4NG.* wildcard); must match the group passed to app.configureWebAuthn. Main app only, NOT the helper-inherit file. -->
<key>keychain-access-groups</key>
<array>
<string>Y26NUZH4NG.com.clusterlabs.openswarm.webauthn</string>
</array>
</dict>
</plist>
+23 -1
View File
@@ -1713,6 +1713,16 @@ app.whenReady().then(async () => {
// Off-window mouse-release crash dodge (macOS). Safe to call before windows exist.
installMacMouseClamp();
// PASSKEY SPIKE (macOS only): turn on the Secure-Enclave/Touch ID WebAuthn authenticator that Electron 42 added. Without this, isUserVerifyingPlatformAuthenticatorAvailable() is hardwired false (why the old reject-shim existed). keychainAccessGroup MUST match the keychain-access-groups entitlement (Y26NUZH4NG.<bundle>.webauthn) or this throws. Windows has no equivalent, so the reject-shim still runs there.
if (process.platform === 'darwin' && typeof app.configureWebAuthn === 'function') {
try {
app.configureWebAuthn({ touchID: { keychainAccessGroup: 'Y26NUZH4NG.com.clusterlabs.openswarm.webauthn', promptReason: 'sign in to $1' } });
console.log('[passkey] configureWebAuthn(touchID) enabled');
} catch (e) {
console.warn('[passkey] configureWebAuthn failed (entitlement missing? unsigned dev build?):', e && e.message);
}
}
// Cold-launch: if the OS opened us via openswarm:// (Windows/Linux it's
// in argv; macOS fires open-url AFTER whenReady which we handle above)
// route through forwardDeepLinkToRenderer so the URL gets stashed under
@@ -1780,6 +1790,17 @@ app.whenReady().then(async () => {
configureBrowsingSession(session.defaultSession);
configureBrowsingSession(session.fromPartition(BROWSER_PARTITION));
// PASSKEY SPIKE: when a site offers several discoverable passkeys, Electron fires this so we pick one; without a handler the WebAuthn flow stalls. For the spike just take the first; a real impl would surface a picker. macOS-only event (no-op elsewhere).
for (const ses of [session.defaultSession, session.fromPartition(BROWSER_PARTITION)]) {
try {
ses.on('select-webauthn-account', (event, accounts, callback) => {
console.log('[passkey] select-webauthn-account, n=', accounts && accounts.length);
event.preventDefault();
callback((accounts && accounts[0] && accounts[0].accountId) || null);
});
} catch (_) {}
}
// Add a "Google Chrome" brand to the browser partition's sec-ch-ua request hints so they match the navigator.userAgentData patch injected on dom-ready and the spoofed Chrome UA string; a Chrome UA paired with Chromium-only hints is the embedded-app tell aggressive anti-bot (Cloudflare) flags on a real human. Scoped to the browser partition, the app's own file:// + localhost traffic is untouched.
const addGoogleChromeBrand = (value) => {
if (typeof value !== 'string' || value.includes('"Google Chrome"')) return value;
@@ -2345,7 +2366,8 @@ app.on('web-contents-created', (_event, contents) => {
// navigator.credentials so passkey calls reject cleanly and post a
// tagged message back; webview-preload.js listens and forwards to the
// embedder, which surfaces the "Passkeys aren't supported" dialog.
contents.on('dom-ready', () => {
// PASSKEY SPIKE: Windows ONLY now. On macOS the real Secure-Enclave authenticator (app.configureWebAuthn above) handles passkeys, so rejecting would defeat the whole point; Windows still has no platform authenticator in Electron, so the reject-shim stays there.
if (process.platform === 'win32') contents.on('dom-ready', () => {
contents.executeJavaScript(`
(function() {
if (window.__openswarm_passkey_shim__) return;
+3 -7
View File
@@ -15,7 +15,7 @@
"devDependencies": {
"@electron/notarize": "3.1.1",
"cross-env": "7.0.3",
"electron": "github:castlabs/electron-releases#v42.0.0+wvcus",
"electron": "github:castlabs/electron-releases#v42.3.3+wvcus",
"electron-builder": "^26.8.1",
"electron-builder-squirrel-windows": "^26.8.1"
}
@@ -567,7 +567,6 @@
"integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -1435,7 +1434,6 @@
"integrity": "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"app-builder-lib": "26.8.1",
"builder-util": "26.8.1",
@@ -1535,8 +1533,8 @@
}
},
"node_modules/electron": {
"version": "42.0.0+wvcus",
"resolved": "git+ssh://git@github.com/castlabs/electron-releases.git#8cf1c79cc0a6aa09227513368166e5f67d2b680f",
"version": "42.3.3+wvcus",
"resolved": "git+ssh://git@github.com/castlabs/electron-releases.git#d2397960c342a332694ab6b059520439c8cdf49e",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1584,7 +1582,6 @@
"integrity": "sha512-o288fIdgPLHA76eDrFADHPoo7VyGkDCYbLV1GzndaMSAVBoZrGvM9m2IehdcVMzdAZJ2eV9bgyissQXHv5tGzA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"app-builder-lib": "26.8.1",
"builder-util": "26.8.1",
@@ -2888,7 +2885,6 @@
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
+6 -2
View File
@@ -24,7 +24,7 @@
"devDependencies": {
"@electron/notarize": "3.1.1",
"cross-env": "7.0.3",
"electron": "github:castlabs/electron-releases#v42.0.0+wvcus",
"electron": "github:castlabs/electron-releases#v42.3.3+wvcus",
"electron-builder": "^26.8.1",
"electron-builder-squirrel-windows": "^26.8.1"
},
@@ -58,8 +58,12 @@
"category": "public.app-category.developer-tools",
"hardenedRuntime": true,
"notarize": false,
"extendInfo": {
"NSFaceIDUsageDescription": "OpenSwarm uses Touch ID to sign you in to websites with passkeys."
},
"provisioningProfile": "build/embedded.provisionprofile",
"entitlements": "build/entitlements.mac.plist",
"entitlementsInherit": "build/entitlements.mac.plist",
"entitlementsInherit": "build/entitlements.mac.inherit.plist",
"extraResources": [
{
"from": "build-staging/mouseclamp/${arch}",
+2 -1
View File
@@ -5,9 +5,10 @@
set -euo pipefail
ARCH="${1:?usage: build-mouseclamp.sh <arm64|x64>}"
ELECTRON_TARGET="42.0.0"
HERE="$(cd "$(dirname "$0")/.." && pwd)" # electron/
# Derive the node-gyp header target from the actually-installed electron so a version bump (e.g. 42.0.0 -> 42.3.3) is auto-tracked instead of silently building against stale headers. Strip any +wvcus suffix; node-gyp wants a plain semver.
ELECTRON_TARGET="$(node -p "require('$HERE/node_modules/electron/package.json').version.split('+')[0]" 2>/dev/null || echo '42.3.3')"
SRC="$HERE/native/mouseclamp"
OUT="$HERE/build-staging/mouseclamp/$ARCH"
NODE_GYP="$HERE/node_modules/.bin/node-gyp"