diff --git a/scripts/windows.sh b/scripts/windows.sh new file mode 100755 index 0000000..10d2b42 --- /dev/null +++ b/scripts/windows.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# Windows installer (NSIS, x64) cross-built on macOS → ../release/desktop/Kestrove__x64-setup.exe +# +# Needs: brew install llvm lld nsis; cargo install --locked cargo-xwin; rustup target add x86_64-pc-windows-msvc; +# Docker. cargo-xwin downloads the Microsoft CRT and Windows SDK: setting XWIN_ACCEPT_LICENSE=1 accepts +# Microsoft's license for them (done only after the maintainer agreed to it). +# +# Homebrew's makensis 3.13 crashes on macOS (std::bad_alloc even for a trivial script), so Tauri's bundling +# step is expected to fail here; the generated installer.nsi is then compiled with NSIS 3.11 from Debian 13 +# in a container, with the same absolute paths mounted. +set -eu +cd "$(dirname "$0")/.." +: "${XWIN_ACCEPT_LICENSE:?set XWIN_ACCEPT_LICENSE=1 to accept the Microsoft CRT/SDK license used by cargo-xwin}" +export XWIN_ACCEPT_LICENSE PATH="/opt/homebrew/opt/llvm/bin:/opt/homebrew/opt/lld/bin:$PATH" +V=$(node -p 'require("./package.json").version') +T="$PWD/src-tauri/target/x86_64-pc-windows-msvc/release" +OUT="$PWD/../release/desktop" +mkdir -p "$OUT" +npm run tauri build -- --runner cargo-xwin --target x86_64-pc-windows-msvc --bundles nsis || true +[ -f "$T/nsis/x64/installer.nsi" ] || { echo "no installer.nsi: the app build failed" >&2; exit 1; } +CACHE="$HOME/Library/Caches/tauri" +docker run --rm --platform linux/arm64 -v "$PWD:$PWD" -v "$CACHE:$CACHE:ro" -w "$T/nsis/x64" debian:13 \ + sh -c 'apt-get update -qq >/dev/null && apt-get install -y -qq nsis >/dev/null && makensis -INPUTCHARSET UTF8 -V2 installer.nsi' +cp "$T/nsis/x64/nsis-output.exe" "$OUT/Kestrove_${V}_x64-setup.exe" +cp "$T/kestrove-nmh.exe" "$OUT/kestrove-nmh-windows-x86_64.exe" +ls -l "$OUT"/*.exe diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 6126e6b..81fbc03 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -290,13 +290,14 @@ fn copy_secret(app: State<'_, App>, id: String, field: Option) -> CmdRes } let cb = guard.as_mut().expect("clipboard initialized above"); #[cfg(windows)] - { + let copied = { // docs/04: keep secrets out of clipboard history, cloud sync and monitors. use arboard::SetExtWindows; cb.set().exclude_from_monitoring().exclude_from_cloud().exclude_from_history().text(secret.to_string()) - } + }; #[cfg(not(windows))] - { cb.set_text(secret.to_string()) }.map_err(|e| e.to_string())?; + let copied = cb.set_text(secret.to_string()); + copied.map_err(|e| e.to_string())?; drop(guard); thread::spawn(move || { thread::sleep(CLIPBOARD_CLEAR); diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 8fd236c..924f8e4 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -10,14 +10,42 @@ "frontendDist": "../dist" }, "app": { - "windows": [{ "title": "Kestrove", "width": 1040, "height": 680, "minWidth": 760, "minHeight": 480, "titleBarStyle": "Overlay", "hiddenTitle": true }], + "windows": [ + { + "title": "Kestrove", + "width": 1040, + "height": 680, + "minWidth": 760, + "minHeight": 480, + "titleBarStyle": "Overlay", + "hiddenTitle": true + } + ], "security": { "csp": "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src ipc: http://ipc.localhost" } }, "bundle": { "active": true, - "targets": ["msi", "nsis", "appimage", "deb"], - "icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico", "icons/icon.png"] + "targets": [ + "msi", + "nsis", + "appimage", + "deb" + ], + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico", + "icons/icon.png" + ], + "windows": { + "nsis": { + "installerHooks": "windows/hooks.nsh", + "installMode": "currentUser" + } + } } } diff --git a/src-tauri/windows/hooks.nsh b/src-tauri/windows/hooks.nsh new file mode 100644 index 0000000..b0392f3 --- /dev/null +++ b/src-tauri/windows/hooks.nsh @@ -0,0 +1,35 @@ +; Kestrove NSIS installer hooks (tauri.conf.json → bundle.windows.nsis.installerHooks). +; Registers the browser extension's native messaging host for the current user (HKCU, no admin), like +; native-messaging/install.ps1: a manifest next to kestrove-nmh.exe ("path" relative to the manifest, which +; Chrome and Firefox allow on Windows) and one registry key per browser. +; Extension ids: keep in sync with kestrove-apple/App/BrowserIntegration.swift (NativeHostRegistration). + +!define KV_HOST "app.kestrove.nmh" +!define KV_CHROME_ORIGINS '"chrome-extension://kogapfibnnpeapfcjkkpgjddbhnjfein/"' +!define KV_FIREFOX_IDS '"browser@kestrove.app"' + +!macro NSIS_HOOK_POSTINSTALL + FileOpen $0 "$INSTDIR\${KV_HOST}.chrome.json" w + FileWrite $0 '{"name": "${KV_HOST}", "description": "Kestrove", "path": "kestrove-nmh.exe", "type": "stdio", "allowed_origins": [${KV_CHROME_ORIGINS}]}' + FileClose $0 + FileOpen $0 "$INSTDIR\${KV_HOST}.firefox.json" w + FileWrite $0 '{"name": "${KV_HOST}", "description": "Kestrove", "path": "kestrove-nmh.exe", "type": "stdio", "allowed_extensions": [${KV_FIREFOX_IDS}]}' + FileClose $0 + WriteRegStr HKCU "Software\Google\Chrome\NativeMessagingHosts\${KV_HOST}" "" "$INSTDIR\${KV_HOST}.chrome.json" + WriteRegStr HKCU "Software\Chromium\NativeMessagingHosts\${KV_HOST}" "" "$INSTDIR\${KV_HOST}.chrome.json" + WriteRegStr HKCU "Software\Microsoft\Edge\NativeMessagingHosts\${KV_HOST}" "" "$INSTDIR\${KV_HOST}.chrome.json" + WriteRegStr HKCU "Software\BraveSoftware\Brave-Browser\NativeMessagingHosts\${KV_HOST}" "" "$INSTDIR\${KV_HOST}.chrome.json" + WriteRegStr HKCU "Software\Vivaldi\NativeMessagingHosts\${KV_HOST}" "" "$INSTDIR\${KV_HOST}.chrome.json" + WriteRegStr HKCU "Software\Mozilla\NativeMessagingHosts\${KV_HOST}" "" "$INSTDIR\${KV_HOST}.firefox.json" +!macroend + +!macro NSIS_HOOK_PREUNINSTALL + DeleteRegKey HKCU "Software\Google\Chrome\NativeMessagingHosts\${KV_HOST}" + DeleteRegKey HKCU "Software\Chromium\NativeMessagingHosts\${KV_HOST}" + DeleteRegKey HKCU "Software\Microsoft\Edge\NativeMessagingHosts\${KV_HOST}" + DeleteRegKey HKCU "Software\BraveSoftware\Brave-Browser\NativeMessagingHosts\${KV_HOST}" + DeleteRegKey HKCU "Software\Vivaldi\NativeMessagingHosts\${KV_HOST}" + DeleteRegKey HKCU "Software\Mozilla\NativeMessagingHosts\${KV_HOST}" + Delete "$INSTDIR\${KV_HOST}.chrome.json" + Delete "$INSTDIR\${KV_HOST}.firefox.json" +!macroend