Electron wrapper for Notion Calendar: minimize to tray, native desktop notifications (via notify-send / libnotify), and persisted window size and position.
Linux only — there are no macOS or Windows builds here; anything outside Linux is untested and unsupported.
Tested environment: Ubuntu 24.04 with KDE Plasma (including correct window icon grouping via StartupWMClass in packaged builds). Other distros or desktops may work but have not been validated.
This repo (opsmachine/notion-calendar) is a fork of dusansimic/notion-calendar. Thanks to the original author for the app baseline and MIT license.
Upstream is a minimal Linux-friendly wrapper; this fork adds updated dependencies, stricter Electron defaults, tray behavior, and Linux-native notification actions.
- Tray — Closing the window minimizes to the system tray instead of quitting. Tray menu: show/hide, quit, developer tools. Single-instance: launching again focuses the existing window.
- Native notifications (Linux) — Calendar alerts are not shown with Electron’s built-in
NotificationAPI. The main process runsnotify-send(from libnotify) so notifications match your desktop environment (e.g. KDE), including critical urgency and action buttons where supported.- Click the notification body → focuses the app (freedesktop
defaultaction). - Join / meeting link → when a URL is detected in the payload, a single Join-style action opens that link in the default browser.
- Reminder timing (e.g. 10 minutes vs 1 minute before) comes from Source Calendar / per-calendar settings, not from this wrapper.
- Click the notification body → focuses the app (freedesktop
- Bridging — The page main world and service worker contexts are patched so
NotificationandServiceWorkerRegistration.showNotificationforward to the main process over validated IPC (preload + dedicated service-worker preload). - Window state — Last width, height, and position are restored via
electron-store. - Chrome-like user agent — A pinned Chrome-on-Linux user agent is applied (see
CHROME_UAinsrc/main/index.ts) so the embedded site behaves like a normal desktop browser session. - Packaging —
npm run build:linuxbuilds a.deb.electron-builder.yamlalso lists rpm/flatpak targets, but the npm script is wired to Debian only right now. Icons and Freedesktop metadata (includingStartupWMClass) are set so the app groups correctly in the taskbar and launcher on KDE and similar desktops. - Developer experience — Application menu (with Alt to reveal the menu bar on Linux when it is hidden), F12 / Ctrl+Shift+I to toggle DevTools, tray entry for DevTools. The main process logs each notification payload and extracted join URL to stdout whenever a notification is dispatched—useful when you run
npm run devornpm startfrom a terminal.
- Linux with a notification server that supports
notify-sendfrom libnotify (standard on Ubuntu and KDE Plasma). - Install if missing, e.g.
sudo apt install libnotify-bin.
These are defense-in-depth measures; they do not replace a formal audit and do not imply the app is “fully secure.”
| Area | Implementation |
|---|---|
| Renderer | contextIsolation: true, nodeIntegration: false, nodeIntegrationInSubFrames: false, sandbox: true |
| Navigation | In-window navigation is limited to allowed hostnames (calendar.notion.so, calendar-api.notion.so), matched with URL / hostname checks (not raw string prefixes, so lookalike domains cannot spoof the list). Other URLs open in the system default browser |
| New windows | Same hostname allowlist as navigation; external targets are not kept as captive Electron windows |
| IPC | Renderer notification IPC requires the sender frame URL to use an allowed hostname; about:blank / empty senders are rejected. Service-worker IPC checks the worker scope the same way. Payloads are validated and title/body lengths are capped before notify-send runs |
| Permissions | Session permission handlers only grant notifications; other permission requests are denied |
| Native notify | notify-send is invoked with execFile (no shell), with bounded arguments |
Repository hygiene: .env files, *.pem / *.key, and similar patterns are in .gitignore to reduce the risk of committing secrets or keys by mistake.
- Email / password sign-in — Signing in with email and password in the main calendar page works in typical use.
- OAuth / social sign-in — Third-party login often relies on popups or extra windows to identity providers (e.g. Google). This wrapper’s window and navigation rules treat those flows in ways that do not complete inside the app today, so OAuth-based sign-in may not work.
- Notification appearance — Action styling and colors follow your Plasma / desktop theme, not the Notion web app.
If you need OAuth in-app, it would require a dedicated, reviewed approach (e.g. carefully scoped window.open / redirect handling for provider URLs), not a quick toggle.
npm install
npm run devPreview production bundle:
npm startLinux package (see electron-builder.yaml):
npm run build:linuxMIT — see LICENSE.
Last updated: 2026-04-03 (Europe/Vienna)