notion-calendar-electron-fixed

maintainer Ishan-Parihar · 0 votes · scanned 2026-08-03 00:08:14.047287
MEDIUM
View on AUR ↗
Why flagged The package downloads a prebuilt Windows installer EXE from calendar-desktop-release.notion-static.com, which is Notion's own CDN (notion-static.com is the official Notion static asset host used for their desktop releases). The sha256sum for the EXE is pinned (4256d294...), which mitigates substitution attacks. The PKGBUILD extracts the NSIS installer, unpacks the app.asar, applies well-understood JS patches to make the Windows Electron app run on Linux, then repacks and installs it. The concern is that this is a prebuilt proprietary binary from a vendor CDN rather than a source build — the inner native .node modules are executed as-is without verification beyond the outer EXE checksum. The host is plausibly official (Notion uses notion-static.com for assets), but it is not a standard Linux package distribution channel. The other sources (launcher script, .desktop, .png) have SKIP checksums which is sloppy but low risk for non-executable assets. Overall this is a legitimate but supply-chain-risky pattern: executing vendor-provided prebuilt binaries from a CDN with only a single outer checksum, which is the canonical MEDIUM scenario.

Triggered rules

MEDIUM source=() URL on a non-standard host source_untrusted_domain

One or more source=() URLs point to a host outside the trusted allowlist (github.com, gitlab.com, codeberg.org, pypi.org, …).

  • PKGBUILD:28 "https://calendar-desktop-release.notion-static.com/Notion%20Calendar%20Setup%20${pkgver}.exe"
MEDIUM AI review llm_review

An AI model (anthropic/claude-4.6-sonnet-20260217) reviewed this and agrees it is MEDIUM (confidence 78%): The package downloads a prebuilt Windows installer EXE from calendar-desktop-release.notion-static.com, which is Notion's own CDN (notion-static.com is the official Notion static asset host used for their desktop releases). The sha256sum for the EXE is pinned (4256d294...), which mitigates substitution attacks. The PKGBUILD extracts the NSIS installer, unpacks the app.asar, applies well-understood JS patches to make the Windows Electron app run on Linux, then repacks and installs it. The concern is that this is a prebuilt proprietary binary from a vendor CDN rather than a source build — the inner native .node modules are executed as-is without verification beyond the outer EXE checksum. The host is plausibly official (Notion uses notion-static.com for assets), but it is not a standard Linux package distribution channel. The other sources (launcher script, .desktop, .png) have SKIP checksums which is sloppy but low risk for non-executable assets. Overall this is a legitimate but supply-chain-risky pattern: executing vendor-provided prebuilt binaries from a CDN with only a single outer checksum, which is the canonical MEDIUM scenario.

PKGBUILD

1 offending line(s) highlighted
1# Maintainer: Ishan Parihar <ishanparihar@gmail.com>
2# Contributor: Stoffi05
3
4pkgname=notion-calendar-electron-fixed
5pkgver=1.133.0
6pkgrel=3
7pkgdesc="Notion Calendar Desktop Client - your calendar, tasks, and schedule in one place (official installer, electron39)"
8arch=(x86_64)
9url=https://www.notion.so/product/calendar
10license=(custom)
11depends=(
12 bash
13 electron39
14 gcc-libs
15 glibc
16 hicolor-icon-theme
17)
18makedepends=(
19 7zip
20 asar
21 python
22)
23provides=('notion-calendar-electron')
24conflicts=('notion-calendar-electron')
25install=.install
26
27source=(
28 "https://calendar-desktop-release.notion-static.com/Notion%20Calendar%20Setup%20${pkgver}.exe"
29 notion-calendar
30 notion-calendar.desktop
31 notion-calendar.png
32)
33sha256sums=('4256d294aec58932b1723760d19d97528a20bf89922db88e66e3931962d63c36'
34 'SKIP'
35 'SKIP'
36 'SKIP')
37
38options=(!emptydirs)
39
40prepare() {
41 # bsdtar (makepkg) already extracted the NSIS installer; app.asar is in resources/
42 # Clean up Windows-specific files left by the extraction
43 rm -f "$srcdir/Notion Calendar Setup ${pkgver}.exe" "$srcdir/Notion Calendar.exe"
44 rm -rf "$srcdir/\$PLUGINSDIR" 2>/dev/null || true
45 rm -rf "$srcdir/asar_patched" 2>/dev/null || true
46
47 # extracting resources from app.asar
48 asar e "$srcdir/resources/app.asar" "$srcdir/asar_patched"
49
50 # Use Python for patching to avoid sed issues with minified JS
51 python3 << 'PYEOF'
52import sys
53import os
54
55main_js = os.path.join(os.getcwd(), 'asar_patched/build/main/main.js')
56if not os.path.exists(main_js):
57 # Fallback: walk from srcdir env or cwd
58 search_root = os.environ.get('srcdir') or os.getcwd()
59 for root, dirs, files in os.walk(search_root):
60 for f in files:
61 if f == 'main.js':
62 main_js = os.path.join(root, f)
63 break
64
65with open(main_js, 'r', encoding='utf-8') as f:
66 content = f.read()
67
68patches = [
69 # Patch 1: disable auto updates (Windows-only Squirrel)
70 ('if("win32"===process.platform&&!d.default().wasBuiltByUs&&s.existsSync(c.join(a.app.getAppPath(),"../Update.exe")))', 'if(!1)'),
71 # Patch 2: fix single instance lock for linux
72 ('"win32"!==process.platform||qf||u().app.quit()', 'qf||u().app.quit()'),
73 # Patch 3: fix second-instance event to handle linux
74 ('"win32"===process.platform&&(tS(),kS(t))', 'tS(),kS(t)'),
75 # Patch 4: fix argv protocol handler for linux
76 ('"win32"===process.platform&&kS(process.argv)', 'kS(process.argv)'),
77 # Patch 5: fix protocol registration for linux
78 (',Mf&&"win32"===process.platform', ',Mf'),
79 # Patch 6: fix app user model id (not needed on linux)
80 ('"win32"===process.platform&&u().app.setAppUserModelId("com.cron.electron");', 'true;'),
81 # Patch 7: fix tray popup menu for linux (use win32 pattern instead of darwin)
82 ('NS)if("darwin"===process.platform)NS.popUpContextMenu();else{', 'NS)if(false)NS.popUpContextMenu();else{'),
83 # Patch 8: fix kS function to work on linux (remove win32-only check)
84 ('function kS(e){if("win32"!==process.platform)return;', 'function kS(e){'),
85 # Patch 9: prevent URLs from being treated as file paths in kS function
86 ('const n=e.slice(1).find((e=>D().existsSync(e)));', 'const n=e.slice(1).find((e=>!e.includes("://")&&D().existsSync(e)));'),
87 # Patch 10: disable crash reporter on linux (provide fake DSN to skip throw)
88 ('if(!(e=this._options.dsn))throw new ae("Attempted to enable Electron native crash reporter but no DSN was supplied");', 'e=this._options.dsn||"https://fake@sentry.io/0";'),
89 # Patch 11: disable autoUpdater on linux (a.autoUpdater is undefined)
90 ('_subscribeToElectronEvents(){a.autoUpdater.on("before-quit-for-update",((...e)=>{this._log("info","before-quit-for-update",...e),this.emit("before-quit-for-update",...e)})),i.autoUpdater.on("checking-for-update",((...e)=>{this._log("info","checking-for-update",...e),this.emit("checking-for-update",...e)})),i.autoUpdater.on("download-progress",((...e)=>{this._log("info","download-progress",...e),this.emit("download-progress",...e)})),i.autoUpdater.on("update-available",((...e)=>{this._log("info","update-available",...e),this.emit("update-available",...e)})),i.autoUpdater.on("update-not-available",((...e)=>{this._log("info","update-not-available",...e),this.emit("update-not-available",...e)}))}}', '_subscribeToElectronEvents(){if("linux"===process.platform)return;a.autoUpdater.on("before-quit-for-update",((...e)=>{this._log("info","before-quit-for-update",...e),this.emit("before-quit-for-update",...e)})),i.autoUpdater.on("checking-for-update",((...e)=>{this._log("info","checking-for-update",...e),this.emit("checking-for-update",...e)})),i.autoUpdater.on("download-progress",((...e)=>{this._log("info","download-progress",...e),this.emit("download-progress",...e)})),i.autoUpdater.on("update-available",((...e)=>{this._log("info","update-available",...e),this.emit("update-available",...e)})),i.autoUpdater.on("update-not-available",((...e)=>{this._log("info","update-not-available",...e),this.emit("update-not-available",...e)}))}}'),
91 # Patch 12: disable second autoUpdater subscription on linux (Nf.autoUpdater is undefined)
92 ('pT=async()=>{Nf.autoUpdater.on("before-quit-for-update",(()=>{bS=!0,SS(),lT="before-quit-for-update",uT(lT)})),Nf.autoUpdater.on("update-available",(()=>{lT="update-available",uT(lT)})),"latest"!==Wf&&sT(Wf),mT(),setInterval(mT,9e5)}', 'pT=async()=>{if("linux"===process.platform)return;Nf.autoUpdater.on("before-quit-for-update",(()=>{bS=!0,SS(),lT="before-quit-for-update",uT(lT)})),Nf.autoUpdater.on("update-available",(()=>{lT="update-available",uT(lT)})),"latest"!==Wf&&sT(Wf),mT(),setInterval(mT,9e5)}'),
93]
94
95applied = 0
96for old, new in patches:
97 if old in content:
98 content = content.replace(old, new, 1)
99 print(f'Applied: {old[:60]}...')
100 applied += 1
101 else:
102 print(f'WARNING: Not found: {old[:60]}...', file=sys.stderr)
103
104if applied < len(patches):
105 print(f'ERROR: Only {applied}/{len(patches)} patches applied!', file=sys.stderr)
106 sys.exit(1)
107
108with open(main_js, 'w', encoding='utf-8') as f:
109 f.write(content)
110
111print(f'All {applied} patches applied successfully')
112PYEOF
113
114 # repacking asar with all the patches
115 asar p "$srcdir/asar_patched" "$srcdir/app.asar" --unpack *.node
116}
117
118package() {
119 local usr="$pkgdir/usr"
120 local share="$usr/share"
121 local lib="$usr/lib/notion-calendar"
122
123 install -d "$lib"
124 cp "$srcdir/app.asar" "$lib"
125 cp -r "$srcdir/app.asar.unpacked" "$lib" 2>/dev/null || true
126 install -vDm755 notion-calendar -t "$usr/bin"
127 install -vDm644 "$srcdir/notion-calendar.desktop" -t "$share/applications"
128 install -vDm644 "$srcdir/notion-calendar.png" -t "$share/icons/hicolor/256x256/apps"
129}
130

Scan history

Scanned at (UTC)SeverityRules
2026-08-03 00:08:14 MEDIUM 2
2026-08-02 00:16:08 MEDIUM 2
2026-08-01 00:11:18 MEDIUM 2
2026-07-31 00:14:10 MEDIUM 2
2026-07-30 00:17:23 MEDIUM 2
2026-07-29 00:25:53 MEDIUM 2
2026-07-28 00:07:28 MEDIUM 2
2026-07-27 00:24:32 MEDIUM 2
2026-07-26 00:07:32 MEDIUM 2
2026-07-25 00:13:44 MEDIUM 2
2026-07-24 00:02:28 MEDIUM 2
2026-07-23 00:14:47 MEDIUM 2
2026-07-22 00:29:32 MEDIUM 2
2026-07-21 00:24:15 MEDIUM 2
2026-07-20 00:19:49 MEDIUM 2
2026-07-19 00:17:08 MEDIUM 2
2026-07-18 00:14:48 MEDIUM 2
2026-07-17 00:06:16 MEDIUM 2
2026-07-16 00:05:41 MEDIUM 2
2026-07-15 00:09:25 MEDIUM 2

Report a package

Reports go to the AURWatch maintainer (one person) and are read by hand. No login required.

0 / 4000
Your suggestion