Hi Joplin maintainers,
I have implemented a working prototype for desktop-side local profile protection and would like to ask whether this direction is acceptable before opening any pull request.
I am aware of the current pause on PRs from new contributors, so I am not opening a PR directly. This post is for direction review first.
Prototype branch:
Prototype commit:
8d494187b56b8924af1ab2e894a3d52b90beed69
Motivation
A desktop app lock alone does not provide meaningful protection if the local Joplin profile can still be read directly from disk. This was also pointed out in the desktop lock discussion: on desktop, local data encryption is needed for a stronger privacy model.
The prototype therefore focuses on database-at-rest protection for the desktop profile, with App Lock as a secondary UI-layer feature.
What the prototype implements
-
Desktop App Lock
- startup lock
- idle lock
- manual lock command
- command/navigation guard while locked
- password hash and cooldown handling
-
Encrypted Profile
- startup gate before opening
database.sqlite - SQLCipher-backed encryption for
database.sqlite profile-encryption.jsonmetadata- scrypt-based password key derivation
- AES-256-GCM wrapping of the generated database key
- migration from plaintext
database.sqliteto encrypted SQLCipher database - plaintext backup retention during migration
- migration failure handling and rollback path
- backup deletion UI
- startup gate before opening
-
Database integration
- optional
databaseKeyHexpassed into application startup - SQLCipher
PRAGMA keyinjection in the database driver - database readability verification after key injection
- optional
-
Tests
- encrypted profile metadata/key wrapping tests
- migration and rollback tests
- backup handling tests
- desktop startup scheduling tests
- App Lock reducer/service tests
- SQLCipher E2E test
Current protection boundary
This is not full-profile encryption.
The current prototype protects:
database.sqlite, after migration has completed and SQLCipher is available.
It does not currently protect:
resources/- attachments
- settings files
- cache
- logs
- plugins
- plugin data
- temporary files
- the plaintext migration backup until the user deletes it
The UI warns users about this boundary before enabling the feature.
Validation already performed
On the prototype branch:
yarn install --immutablepassedyarn workspace @joplin/lib tscpassedyarn workspace @joplin/app-desktop tscpassed- encryptedProfile lib tests passed
- encryptedProfile desktop tests passed
- App Lock tests passed
- SQLCipher E2E test passed
- desktop build passed
Question
Would this direction be acceptable for Joplin Desktop?
If yes, I can split the prototype into smaller reviewable PRs, for example:
- SQLCipher capability probe and native module loading
- encrypted profile metadata and key wrapping service
- optional database key support in
DatabaseDriverNode - plaintext-to-SQLCipher migration helper
- desktop startup unlock gate
- settings UI
- App Lock as a separate follow-up
I mainly want to know whether SQLCipher-backed local database-at-rest encryption is an acceptable direction before spending time splitting this into upstream-ready patches.