Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ jobs:
file "$APP_PATH/Contents/MacOS/Space" | grep -q "$WANT_ARCH" || { echo "ERROR: wrong architecture"; file "$APP_PATH/Contents/MacOS/Space"; exit 1; }
/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$APP_PATH/Contents/Info.plist" | grep -qx "de.studiofritzgnad.space" || { echo "ERROR: bundle id not patched"; exit 1; }
grep -q "hasVisibleWindows && mainWindow" "$APP_PATH/Contents/Resources/app/lib/main.js" || { echo "ERROR: activate-handler guard not patched"; exit 1; }
echo "Verified: arch, bundle id, and activate-handler patch OK"
grep -q "Reset Cache and Cookies" "$APP_PATH/Contents/Resources/app/lib/main.js" || { echo "ERROR: app-menu reset item not patched"; exit 1; }
echo "Verified: arch, bundle id, activate-handler, and app-menu patches OK"
- name: Import signing certificate (optional)
if: env.MAC_CERT_P12_BASE64 != ''
run: |
Expand Down
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Create Nativefier desktop apps for `https://space.studiofritzgnad.de` for:
- **macOS Apple Silicon (arm64)**
- **macOS Intel (x64)**

**Current Version**: 1.8.5
**Current Version**: 1.8.6

Icons live in `assets/`:

Expand All @@ -22,12 +22,21 @@ All builds use persistent session storage so you stay logged in across app resta

**Important**: Cookies persist automatically - no special configuration needed. The app uses Electron's built-in cookie storage which saves cookies to disk in the user data directory.

To clear login data and cookies, delete the respective directory:
- macOS: `rm -rf ~/Library/Application\ Support/Space`
- Windows: Delete `%APPDATA%\Space` folder

The app will remember your login as long as the website sets persistent cookies (typically when "Remember me" is checked during login).

#### Resetting cache and cookies

On macOS, **Space → Reset Cache and Cookies…** clears the HTTP cache, deletes cookies (which signs you out), and reloads the window. It asks for confirmation first. Use it when the app serves stale assets or a login gets stuck.

The menu item is injected into the nativefier-built app by `scripts/patch-app-menu.mjs`, which runs from `scripts/patch-mac-plist.sh` during the macOS build. Nativefier is archived upstream, so the bundled `main.js` is patched post-build rather than forked; the patch fails the build if nativefier's menu template ever moves.

Other ways to clear state, on either platform:

- **Edit → Clear App Data** (built into nativefier) wipes *everything* — cookies, local storage, IndexedDB, service workers — after a confirmation prompt.
- Delete the user data directory:
- macOS: `rm -rf ~/Library/Application\ Support/Space`
- Windows: Delete `%APPDATA%\Space` folder

### Camera & microphone (macOS)

The build patches the app's `Info.plist` with `NSCameraUsageDescription`/`NSMicrophoneUsageDescription`, sets the stable bundle id `de.studiofritzgnad.space`, and re-signs the bundle ad-hoc (`scripts/patch-mac-plist.sh`). All three steps are required: without a valid signature covering the patched plist, macOS silently denies camera/mic access without ever showing a prompt, and the app never appears under System Settings → Privacy & Security → Camera/Microphone.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "space-nativefier",
"version": "1.8.5",
"version": "1.8.6",
"private": true,
"description": "Nativefier desktop apps for space.studiofritzgnad.de",
"license": "MIT",
Expand Down
83 changes: 83 additions & 0 deletions scripts/patch-app-menu.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env node
// Adds a "Reset Cache and Cookies…" item to the top of the macOS app menu
// (the "Space" menu) in a built app's bundled main.js.
//
// Nativefier only offers Edit → Clear App Data, which wipes *all* site data
// (local storage, IndexedDB, service workers, …) and leaves the page running
// on the now-stale state. The item added here does the narrower, far more
// common thing: drop the HTTP cache, delete cookies (signing the user out),
// and reload. Nativefier is archived upstream, so we patch its bundled
// main.js after the build rather than carrying a fork.
//
// Usage: node scripts/patch-app-menu.mjs <path-to-app/lib/main.js>

import { readFile, writeFile } from 'node:fs/promises';

// Also grepped for by the CI "Verify app arch and patches" step, so a silently
// unpatched build can never ship.
const MARKER = 'Reset Cache and Cookies';

// Nativefier builds the macOS app menu as `electronMenu`; macOS renders its
// label as the app name, which is why this shows up as the "Space" menu.
const ANCHOR =
/(const electronMenu\s*=\s*\{\s*label:\s*'E&lectron',\s*submenu:\s*\[)/;

// Sits above Services, where macOS apps put app-level actions. `mainWindow`,
// `electron_1` and `log` are all in scope at this point in generateMenu().
const MENU_ITEM = `
{
label: 'Reset Cache and Cookies…',
click: (item, focusedWindow) => {
const targetWindow = focusedWindow || mainWindow;
if (!targetWindow) {
log.error('Reset Cache and Cookies: no window available');
return;
}
(async () => {
const { response } = await electron_1.dialog.showMessageBox(targetWindow, {
type: 'warning',
buttons: ['Reset', 'Cancel'],
defaultId: 1,
cancelId: 1,
title: 'Reset cache and cookies',
message: 'Reset cache and delete cookies?',
detail: 'This clears cached files and signs you out of Space. The window reloads afterwards.',
});
if (response !== 0) {
return;
}
const { session } = targetWindow.webContents;
await session.clearCache();
await session.clearStorageData({ storages: ['cookies'] });
targetWindow.webContents.reloadIgnoringCache();
})().catch((err) => log.error('Reset Cache and Cookies ERROR', err));
},
},
{
type: 'separator',
},`;

const mainJsPath = process.argv[2];
if (!mainJsPath) {
console.error('Usage: patch-app-menu.mjs <path-to-app/lib/main.js>');
process.exit(1);
}

const source = await readFile(mainJsPath, 'utf8');

if (source.includes(MARKER)) {
console.log(`App menu already patched, nothing to do: ${mainJsPath}`);
process.exit(0);
}

if (!ANCHOR.test(source)) {
console.error(
`ERROR: macOS app menu template not found in ${mainJsPath}. ` +
'Nativefier likely changed its menu code — update the anchor in scripts/patch-app-menu.mjs.',
);
process.exit(1);
}

await writeFile(mainJsPath, source.replace(ANCHOR, `$1${MENU_ITEM}`), 'utf8');

console.log(`Added "Reset Cache and Cookies…" to the app menu in: ${mainJsPath}`);
5 changes: 5 additions & 0 deletions scripts/patch-mac-plist.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ set -euo pipefail
# Usage: patch-mac-plist.sh /path/to/Space-darwin-<arch>

APP_PARENT="${1:?Usage: patch-mac-plist.sh <app-output-dir>}"
SCRIPT_DIR="$(dirname "$(realpath "$0")")"

# Locate the .app bundle inside the given directory.
APP_BUNDLE=$(find "${APP_PARENT}" -maxdepth 1 -name "*.app" -type d | head -n 1)
Expand Down Expand Up @@ -60,6 +61,10 @@ if [[ -f "${MAIN_JS}" ]]; then
echo "ERROR: activate-handler pattern not found in ${MAIN_JS}"
exit 1
fi

# Add "Reset Cache and Cookies…" to the Space menu. Exits non-zero if the
# menu template moved, so an unpatched build fails here instead of shipping.
node "${SCRIPT_DIR}/patch-app-menu.mjs" "${MAIN_JS}"
fi

# Re-sign the whole bundle ad-hoc so the signature covers the patched plist.
Expand Down
2 changes: 1 addition & 1 deletion scripts/version.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Single source of truth for the app version.
# Sourced by build.sh and the per-platform build scripts.
VERSION="1.8.5"
VERSION="1.8.6"