Encrypted, offline note-taking. A three-panel, OneNote-style app that keeps your data local and protected with AES-256-GCM encryption.
- 3-panel layout — Notebooks → Sections → Pages, just like OneNote.
- AES-256-GCM encryption — Master password encrypts all data at rest, with scrypt key derivation (N=65536, r=8, p=1).
- Per-notebook locks — Individual password for sensitive notebooks, on top of the master.
- Fully offline — All fonts, scripts, and dependencies are bundled in
lib/. The only network request is an optional update check against GitHub Releases on launch. - Rich text editor — Bold, italic, headings, lists, tables, code blocks, links, images, checklists.
- Find & Replace — Safe text-node walking that won't break HTML.
- Auto-lock — Configurable idle timeout (5 / 15 / 30 / 60 min) plus
Ctrl+Lmanual lock. - Encrypted backup — Export and restore
.encbackup files. - Auto-update — Checks GitHub Releases on launch and prompts to download and install when a new version is available. Can be disabled in settings.
- Dark & light themes — Persisted across sessions.
- Export — HTML and plain text, with warnings before writing unencrypted output.
Grab the latest installer from Releases:
NoteForge Setup x.x.x.exe— Standard Windows installer (recommended).NoteForge-x.x.x-portable.exe— Portable, no install needed.
Releases are built automatically by GitHub Actions — no manual build step on my end.
Note: Windows will show a SmartScreen warning because the app isn't code-signed yet. Click "More info" → "Run anyway" to proceed. The source is fully open for inspection.
Requires Node.js 20 LTS or 22 LTS. Node 22 is recommended (Electron's @electron/* packages are moving to Node 22 as the new minimum).
git clone https://github.com/jamesccupps/NoteForge.git
cd NoteForge
npm install
npm run build:jsx
npm startTo build the installer locally (or use Build.bat on Windows):
npm run distOutput goes to dist/.
This app exists specifically to keep notes private, so it's worth being specific about how.
| Layer | Algorithm | Key derivation |
|---|---|---|
| Master (file-level) | AES-256-GCM | scrypt N=65536, r=8, p=1 |
| Notebook locks | AES-256-GCM | scrypt N=65536, r=8, p=1 |
- Master password is never stored — only the derived key (
Buffer) lives in memory during the session. - Notebook passwords are never held in the renderer — after unlock, the renderer only has an opaque 128-bit handle to a session key that lives in the main process.
- Session keys are zeroed with
Buffer.fill(0)on lock, close, and idle timeout. - Locked notebook sections are stripped from disk on every write via
sanitizeForDiskSync()in the renderer, with a second-layersanitizeDataJson()safety net in the main process. Plaintext never reaches the data file even if the renderer is compromised. - KDF downgrade protection — decrypt rejects blobs with
N < 16384, non-power-of-2N, or malformed fields, so an attacker who can write the data file can't weaken the encryption header and then have you type your password into a weakened blob. - Rate limiting with exponential backoff on failed password attempts, persisted across restarts, with separate counters for master unlock and notebook unlock.
- Password strength enforcement: minimum 10 characters, at least 3 of 4 character classes (upper / lower / digit / symbol), dictionary check against 160 common passwords, and a low-entropy check that rejects passwords with fewer than 5 unique characters.
default-src 'none';
script-src 'self';
style-src 'self' 'unsafe-inline';
font-src 'self';
img-src 'self' data:;
connect-src 'none';
All scripts and fonts load from the local lib/ directory. Zero CDN dependencies at runtime. connect-src 'none' blocks any outbound fetch or XHR from the renderer, even if code is injected.
The auto-updater runs in the main process — not governed by the renderer's CSP — and makes a single HTTPS request to GitHub Releases on launch to check for new versions. Disable it in File → Settings if that matters to you.
- DOMPurify sanitizes all note content on load, paste, and export.
- Navigation guards block all non-
file://navigation.will-navigateandwill-redirectare both handled, andsetWindowOpenHandlerdenies every attempt to open a new window. contextIsolation: true,nodeIntegration: false.- All runtime permission requests denied —
setPermissionRequestHandlerreturnsfalsefor every permission. - DevTools menu item is removed from production builds.
- Export dialogs distinguish between generic unencrypted export and export from a password-protected notebook.
- Print dialogs show a warning when printing from a password-protected notebook.
- Backup restore validates
v=2,kdf=scrypt, andN>=16384before accepting anything. - Password hint inclusion in backups is opt-in via an explicit dialog. Default is exclude.
- Config keys are allowlisted — the renderer can only write a tiny whitelist of known settings.
- CI actions are pinned to commit SHAs so supply-chain attacks via tag-moves can't affect the build.
Security issues? See SECURITY.md for responsible disclosure.
NoteForge/
├── .github/
│ ├── ISSUE_TEMPLATE/ # Bug report and feature request templates
│ ├── pull_request_template.md
│ └── workflows/
│ └── build.yml # CI: auto-build and release on tag push
├── docs/
│ ├── CONTRIBUTING.md
│ └── screenshots/
├── app.jsx # React source (edit this)
├── app.js # Compiled output (generated)
├── main.js # Electron main process + crypto
├── preload.js # IPC bridge (contextBridge)
├── index.html # Shell with CSP
├── styles.css # All styling + @font-face
├── package.json # Scripts + electron-builder config
├── package-lock.json # Pinned dependency graph (committed for reproducibility)
├── lib/ # Bundled runtime dependencies
│ ├── react.min.js
│ ├── react-dom.min.js
│ ├── purify.min.js
│ └── *.woff2 # DM Sans + JetBrains Mono fonts
├── assets/
│ ├── icon.ico
│ └── icon.png
├── Build.bat # Windows build helper
├── NoteForge.bat # Windows dev launcher
├── CHANGELOG.md
├── SECURITY.md
├── LICENSE
└── README.md
- Edit
app.jsx(React/JSX source). - Compile:
npm run build:jsx. - Test:
npm start. - Build installer:
npm run dist.
| OS | Path |
|---|---|
| Windows | %APPDATA%\noteforge\ |
| macOS | ~/Library/Application Support/noteforge/ |
| Linux | ~/.config/noteforge/ |
Files written: noteforge-data.json (unencrypted) or noteforge-data.enc (encrypted), noteforge-config.json, window-state.json, ratelimit.json, and noteforge-hint.txt (optional password hint).
| Shortcut | Action |
|---|---|
Ctrl+N |
New Page |
Ctrl+Shift+N |
New Notebook |
Ctrl+B / I / U |
Bold / Italic / Underline |
Ctrl+D |
Duplicate Page |
Ctrl+F |
Find & Replace |
Ctrl+L |
Lock App |
Ctrl+Z / Ctrl+Y |
Undo / Redo |
Ctrl+= / Ctrl+- |
Zoom In / Out |
Ctrl+\ |
Toggle Sidebar |
Ctrl+Shift+D |
Toggle Theme |
Ctrl+P |
|
Ctrl+Shift+E |
Export HTML |
See docs/CONTRIBUTING.md.
Open an issue for bugs and feature requests. For security reports or general questions, email jamesccupps@proton.me.
See CHANGELOG.md.
MIT — James Cupps
