Commit Graph

13 Commits

Author SHA1 Message Date
r-zakarya 3e0bc7bd84 build(android): build and sign a release, without the password touching anything
build-apk.ps1 -Release builds the Release configuration and signs with the
user's keystore. Not through Delphi's Provisioning page, for three reasons:
the .dproj is versioned, paclient --apksign puts the password ON THE COMMAND
LINE where any process on the machine reads it, and tooling belongs in the
repository rather than hidden in an IDE setting. apksigner called directly
accepts --ks-pass env:.

The password is asked for with Read-Host -AsSecureString - nothing echoed,
nothing left in console history - handed over through an environment
variable, and removed in a finally even when the script fails.

It prints the certificate it signed with. A release signed by accident with
the debug key installs and runs: nothing tells it apart in use, and one finds
out only when the first update is refused.

It does not install the release. Android refuses a different signature on an
existing package, and uninstalling would wipe the local cache and the
device's settings - a deliberate act, not a script's side effect.

Keystores are gitignored. The debug path is unchanged and still builds.
2026-08-22 01:05:42 +01:00
r-zakarya 8c1cabb5bd feat(android): the list and the detail move to HTML
The FMX controls lost this one on merit. Every screen re-taught the same lessons: a template missing from the loaded style, an alignment order left to chance, a HitTest swallowing a tap, a native view painting over everything. The engine draws the same interface in forty lines of CSS and shapes Arabic on its own.

The bridge needs no local server, so no port is open on the device: evaluateJavascript carries the data down, an intercepted cmd:// navigation carries the actions up. Through a throwaway iframe - FMX always tells the engine it did not handle the navigation, which on an unknown scheme replaces the page with an error screen.

Secrets do not travel over that bridge. The list gets names, sites and usernames, which are already on screen; copying from a row sends an index and Delphi reads the vault itself. Only the open entry has its values in the JS heap, and PM.wipe clears them on lock.

Folders become a row of chips with counts instead of a full-screen panel: one tap, and the count says what to expect.

Also gone: about eight hundred lines of the screen this replaces.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 23:57:46 +01:00
r-zakarya fdeb870541 chore: track the launcher icons, the blanket *.png rule was swallowing them
The rule exists for screenshots dropped in the repo root during dev. Launcher icons are content: they regenerate from make-icons.ps1, but tracking them means not having to know that - nor depending on System.Drawing to build an APK.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 16:12:08 +01:00
r-zakarya 49efccdd59 feat(android): settings live on the device, dark theme, and the app is called Coffre
URL and token are no longer constants. They sit in settings.bin, sealed with the no-auth Keystore AES key - deliberately weaker than the vault: they must be readable to rebuild a vault that no longer exists, and a bearer token only opens ENCRYPTED data, worthless without the sync password that stays in the guarded vault. Retyping 64 hex characters after every cache purge was the real risk: the risk of writing them down elsewhere. They are saved only after a fetch that worked - proven settings, not typed ones.

The token and sync password moved to the gitignored local include, as first-run defaults only. Tracked source now carries no secret, and leaving them empty is a viable configuration: the app asks.

Theme: Delphi's Dark.style, copied into the repo and linked as a resource rather than deployed as a file - this project's deployment puts nothing beside the app, which is the same hole that forces the manifest and dex staging. A failure to load is never fatal; the default look is ugly but works.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 15:33:56 +01:00
r-zakarya 4effc3611d feat(android): prefill the sync password from a local, untracked include
Asked for, but it opens the whole vault once the container is downloaded, so it does not belong in a versioned file - even in a repo with no remote. It lives in PMA.LocalConfig.inc, gitignored, with a template checked in so a fresh clone knows what to create.
2026-08-15 01:04:08 +01:00
r-zakarya 307bbeae83 chore: ignore the generated project resource too 2026-08-14 23:23:28 +01:00
r-zakarya ec4fa433a9 feat(sync): read-only PHP endpoint serving the encrypted snapshot
Alternative to WebDAV, and the base for an Android client. The server never decrypts: it stores and serves opaque bytes, so a compromise yields ciphertext plus size and mtime.

GET only for now, with a strong ETag and If-None-Match; PUT answers 405 explicitly so a client fails loudly rather than believing it wrote. A bad token answers 404 like a missing snapshot, so an unauthenticated caller learns nothing. HTTPS is required - the bearer token rides a header on every call.
2026-08-14 17:41:34 +01:00
r-zakarya 982b7c082c chore: stop tracking generated embedded-asset artifacts
assets.res/.rc/.inc are regenerated by BuildAssets before every Delphi build
and linked into the exe — tracking them just churned a binary each session.
Untrack + gitignore (matches the intent already stated in CLAUDE.md). A fresh
clone runs BuildAssets first anyway (documented build step 1).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 18:35:28 +01:00
r-zakarya 5fc07aed7a refactor(js): extract TOTP module + add RFC 6238 tests (§3.1)
Fourth slice of the app.js split. Moves TOTP (base32Decode, generateTOTP,
parseOtpAuthUri) plus the TOTP-secret and custom-field AES-GCM wrappers to
js/app.totp.js. Loads before app.js (pure declarations), after app.crypto.js
(uses encryptPwd/decryptPwd). Also called by app.import.js and app.sync.js
via shared global scope.

- Byte-for-byte identical extraction; no duplicate const; syntax OK on all
  five app parts.
- NEW: js/tests/totp.test.js — 13 tests including the 5 RFC 6238 Appendix B
  reference vectors (generateTOTP reads Date.now(), so each case stubs the
  sandbox clock to the vector's fixed time), base32 decode edge cases, and
  parseOtpAuthUri. Extraction AND new coverage in one slice.
- Suite: 42 → 55 tests, all green.
- Assets regenerated (manifest now embeds all 6 ordered JS files:
  argon2 → crypto → totp → import → app → sync); also fixes the previous
  import commit's not-yet-rebuilt manifest.
- Delphi build artifacts (*.vrc, *.$manifest) gitignored.

app.js: 11936 → 10138 lines (4 modules extracted, ~1800 lines).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 16:35:29 +01:00
r-zakarya 1f56a03492 chore: ignore local-only debug + packaging artefacts
build.log, config.txt, PMServer.rar, quickunlock.bin, vault copies and
screenshot drops were cluttering `git status`. None of these belong in
the repo: build/config/rar are per-machine, quickunlock.bin is a DPAPI
blob bound to the dev user's Windows account, vault copies are personal
data, screenshots are scratch.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-26 21:22:02 +01:00
Zaki 519e8fbd48 chore: untrack vault.db (contains user secrets)
vault.db was tracked from the start of the repo, meaning every commit
since the initial import has captured snapshots of the user's password
data. Even though entries are AES-GCM encrypted in the DB, the file
also contains:
  - PBKDF2 salt + hash of the master password (offline-crackable)
  - Audit log with timestamps + IP addresses
  - Session tokens (transient but historical)
  - Login attempt counters per username

Future commits no longer include vault.db. The Delphi/PHP backend
auto-creates the schema via CREATE TABLE IF NOT EXISTS on first run,
so a fresh clone needs no migration step.

Also ignore the SQLite sidecar files (-journal, -wal, -shm).

NOTE: this only stops future leaks. The historical commits still
contain old snapshots. Purging history requires git filter-repo +
force-push, which rewrites every commit hash and breaks existing
clones. See README for instructions if a history purge is desired.
2026-05-23 00:07:00 +01:00
Zaki 506aee7e6f feat: Delphi backend + JS↔Delphi bridge (clipboard, tray, auto-lock)
Introduces the Delphi 12 FMX backend (PMServer) that hosts the embedded
WebView2 vault on 127.0.0.1, and a native bridge between JS and Delphi
that wires three privacy-focused features:

1. Secure clipboard
   Copying a password registers the Win32 "ExcludeClipboardContentFromMonitorProcessing"
   format alongside CF_UNICODETEXT, so Win+V clipboard history never sees
   the value. Auto-clears after 30s via TTimer. Bridge.copySecure() in
   app.js routes all password/username/secret copy paths through the
   native layer when running inside the Delphi WebView2 (falls back to
   navigator.clipboard for the PHP standalone).

2. Tray icon (X-to-tray when server running)
   Closing the dev panel hides both the form HWND and the TFMAppClass
   per-process proxy window that owns the FMX taskbar entry — the form's
   HWND alone is not the taskbar-visible one in FMX (took some iteration
   to discover). Tray menu: Open, Lock vault, Quit. Clipboard is force-
   cleared on minimize as extra safety. First-time minimize fires a
   balloon notification so the user knows the app is still running.

3. Auto-lock on Windows session lock (Win+L)
   wtsapi32.dll!WTSRegisterSessionNotification on a dedicated message-only
   window. On WM_WTSSESSION_CHANGE / WTS_SESSION_LOCK, the bridge calls
   ExecuteJavaScript('lockVault()'). Same path used by the tray "Lock vault"
   menu item.

Bridge architecture:
 - JS → Delphi via cmd:// URLs intercepted in OnBeforeNavigate
   (pattern lifted from DeskInsight Monaco). Currently exposes
   cmd://clipboard/copy?text=...&clear=... and cmd://clipboard/clear.
 - Delphi → JS via TTMSFNCWebBrowser.ExecuteJavaScript with guarded
   calls (typeof check) so the bridge degrades cleanly if app.js isn't
   loaded yet.

Files:
 - Source/PM.Bridge.pas (new) — TSecureClipboard + TPMBridge
 - UMainForm.pas/.fmx — bridge wiring, FormCloseQuery intercept, tray
   callbacks (BridgeTrayRestore / BridgeLockRequest / BridgeQuit)
 - js/app.js — Bridge object, 5 navigator.clipboard sites migrated to
   Bridge.copySecure with PHP-compatible fallback, Bridge.onTrayRestore
   handler that resets the auto-lock timer

.gitignore extended with Delphi build artifacts (*.dcu, Win32/, Win64/,
__history/, __recovery/, *.identcache, *.dsk, *.local, etc.) so source
checkouts stay clean.
2026-05-22 23:47:57 +01:00
Zaki d1a26fc0d6 Add vault-error.log to .gitignore 2026-05-12 15:15:10 +01:00