Commit Graph

61 Commits

Author SHA1 Message Date
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 159e02ae81 Fix double toast on single delete: pass noToast to delEntry. Remove auto-dismiss timeout on undo toasts (visible until clicked). 2026-05-12 19:55:30 +01:00
Zaki 73818e4e2e Add undo to drag-drop trash. Fix toast undo button visibility (darker bg, border, max-width). 2026-05-12 19:46:01 +01:00
Zaki ff9802e685 Add undo button in toast for trash actions (single + batch) 2026-05-12 19:40:23 +01:00
Zaki 617b8a7efe Hide FABs when auth visible (locked). Trash FAB glow shadow when active. 2026-05-12 19:36:35 +01:00
Zaki eb15d9e849 Trash FAB: always transparent background, no shadow 2026-05-12 15:49:40 +01:00
Zaki 59d407558b Trash FAB: always shows 🗑️; active mode has transparent background, no shadow 2026-05-12 15:33:12 +01:00
Zaki d1a26fc0d6 Add vault-error.log to .gitignore 2026-05-12 15:15:10 +01:00
Zaki f8c684669d Remove accidentally committed vault-error.log 2026-05-12 15:14:47 +01:00
Zaki 5836bd168d Fix dblclick: clear selection, select entry, render, open edit. closeEdit calls render. Trash FAB: moved from toolbar to floating button at bottom-left (like add FAB). 2026-05-12 15:14:39 +01:00
Zaki d55be5f19e Fix entry card contrast (lighter card, more visible border). Fix dblclick: force-select entry before opening edit. 2026-05-12 14:20:46 +01:00
Zaki b51e9c3a73 Theme: neutral dark gray, card shadows, accent-rgb vars. Fix: arrows skip when modals open. Fix: detail view respects folder filter.
Dark theme: neutral dark grays (#0e1015 bg, #6b7280 accent). Light theme: white cards, better contrast. Cards now have subtle shadows for separation. All hardcoded rgba(59,130,246) replaced with rgba(var(--accent-rgb), ...). Arrow key handler skips when add/edit modal is open. Detail view now uses getFilteredEntries() instead of getFilteredEntries(true) to respect folder selection.
2026-05-12 13:51:41 +01:00
Zaki dfcbc3f568 Theme: neutral dark gray, higher card contrast. Detail view: folder filtering works. Modals: arrow nav blocked when modal open, Enter saves from anywhere inside modal. 2026-05-12 13:35:46 +01:00
Zaki 194c11ece2 Fix Shift+arrow range selection: track anchor (fixed) and focus (moving) separately
Previous approach always started from the lowest-indexed selected entry, causing the range to snap to anchor on arrow reversal. Now arrowFocus tracks the moving end; arrowAnchor stays fixed. Non-Shift arrow resets both to the new position.
2026-05-09 23:36:39 +01:00
Zaki 0a0e380b95 Fix shift+arrow anchor and detail view arrow navigation
Shift+arrow now uses arrowAnchor (set on first arrow press) instead of lastSelectedId (which was updated on each non-Shift move). Fixes 'only 2 entries' bug. Detail view: fixed inverted auth check for ArrowLeft/Right; general arrow handler now excludes detail view.
2026-05-09 23:32:36 +01:00
Zaki 3802f1fc23 Grid view: arrow up/down moves vertically by column count; left/right moves linearly 2026-05-09 23:23:30 +01:00
Zaki b0785fbe8d Arrow left/right navigate entries; Shift+arrow extends multi-selection 2026-05-09 23:16:17 +01:00
Zaki 72d7d1015a Arrow up/down to navigate entries, Enter to open selected for editing 2026-05-09 23:12:09 +01:00
Zaki 52a4242a52 Auto-focus: loginUsername on load, website in add/edit modals. Enter saves from anywhere inside modals. 2026-05-09 22:41:52 +01:00
Zaki 49e1ab4730 Mark resolved issues in security-issues.md 2026-05-09 22:29:09 +01:00
Zaki 69b17e4505 Fix password generator modulo bias with rejection sampling
Use single-byte rejection sampling: generate byte, reject if >= largest multiple of charset length, then modulo. Eliminates bias from c.charAt(arr[i] % c.length).
2026-05-09 22:28:54 +01:00
Zaki 46d7ca3694 Add CSP header and session rotation on login
Content-Security-Policy: default-src 'self'; restricts external resource loading. Session rotation: delete all existing sessions for a user on login, so re-logging invalidates any leaked tokens.
2026-05-09 22:24:08 +01:00
Zaki 4ddf2e9be6 Fix Enter in edit modal: switch from keypress (deprecated) to keydown 2026-05-09 22:20:09 +01:00
Zaki 6915ce518b Rate-limit /reauth endpoint: 5 attempts per 15min 2026-05-09 22:17:03 +01:00
Zaki ca7555a603 Fix Enter key in add modal: password field id is addPassword, not passwordInput 2026-05-09 22:14:46 +01:00
Zaki f4a542885a Enter key saves in add/edit modals from any field
Pressing Enter in addSite, addUsername, passwordInput calls addEntry(). Enter in editSite, editUsername, editPassword calls saveEdit().
2026-05-09 21:27:59 +01:00
Zaki f00bb2cdeb Add double-click on entry to open edit modal
Double-click any entry card/row (all views incl. detail) opens the edit modal. Excluded from trash view.
2026-05-09 21:08:51 +01:00
Zaki 70c22ce153 Change shortcuts: Alt+N for new entry, Alt+T for toggle trash
Ctrl+N and Ctrl+T cannot be intercepted by Chrome (browser-level shortcuts). Replaced with Alt+N and Alt+T which work reliably. Updated keyboard shortcuts help.
2026-05-09 21:03:32 +01:00
Zaki eb82bd416d Fix Ctrl+N/T: use e.key instead of e.code, remove duplicate guard
Switched from e.code (physical key position) to e.key (character value) which is more reliable across keyboard layouts and browsers. Also removed duplicate Ctrl guard line.
2026-05-09 19:44:44 +01:00
Zaki bfe20d29ec Fix Ctrl+N/T: use window capture phase to intercept before browser chrome
document-level keydown bubbling phase is too late for browser-level shortcuts Ctrl+N (new window) and Ctrl+T (new tab). Moved handlers to a window.addEventListener('keydown', ..., true) capture-phase handler that fires before the browser chrome acts. Removed redundant document-level copies.
2026-05-09 19:24:36 +01:00
Zaki 03c20fcb8c Fix Ctrl+N/T opening browser windows instead of app actions
Moved Ctrl+N and Ctrl+T handlers before the generic Ctrl guard with their own e.preventDefault() and early return, matching the pattern used for Ctrl+A. Removed them from the old else-if chain and combined preventDefault block.
2026-05-09 19:22:15 +01:00
Zaki 37c15ecad6 Fix Ctrl+A: use e.key instead of e.code, move before generic Ctrl guard
Ctrl+A was selecting page text instead of entries. Switched from e.code === 'KeyA' (layout-dependent) to e.key === 'a'. Moved handler before the generic Ctrl+key else-if chain and before the combined preventDefault block, with its own e.preventDefault() and early return. Handles both 'a' and 'A' key values.
2026-05-09 19:13:58 +01:00
Zaki e414b4f600 Fix Ctrl+A and add Delete key shortcut
Ctrl+A auth check was inverted (!hidden instead of hidden), preventing selection in vault. Added Delete key shortcut: moves selected entries to trash (or batch permanent delete in trash view). Added Del to keyboard shortcuts help.
2026-05-09 19:04:36 +01:00
Zaki f40024cc67 Fix: mousedown clears selectedIds before batch callback runs
Document mousedown handler was clearing selectedIds when clicking 'Yes' (button element). Since mousedown fires before click, selectedIds was empty by the time the async callback read it, causing no-op deletes but still showing the toast. Added .batch-confirm-overlay to the mousedown exclusion list so clicking the confirm dialog won't trigger clearSelection().
2026-05-09 18:46:27 +01:00
Zaki 02e5868d66 Fix batch confirm: modal overlay + positioned beside button
Replace showCenterConfirm with showBatchConfirm(btn,message,callback) that creates a transparent modal overlay (z-index 9999) to block background clicks, positions the confirm dialog beside the trigger button. Updated all callers (batchDelete, batchPermanentDelete, permanentDelete, emptyTrash) to pass the clicked button. Added CSS for batch-confirm-overlay backdrop.
2026-05-09 18:37:57 +01:00
Zaki 131bb91cd2 Replace standard confirm() with custom centered confirm dialog
Add showCenterConfirm() function for dialogs without button anchor. Replaced all standard confirm() calls in batchDelete, batchPermanentDelete, permanentDelete, emptyTrash. Batch permanent delete shows single custom confirm with entry count, no nested dialogs. permanentDelete() accepts silent param to suppress UI for batch operations. Order cleanup added to permanentDelete.
2026-05-09 18:20:06 +01:00
Zaki 7e623067b0 Fix: batch toast spam on trash drag, restore icon, stale ref, reorder safety
Trash drop handler now uses noToast + single message. Restore button icon changed to ♻️. Removed stale .view-toggle reference in click-outside handler. Added safety check in reorder drop handler to prevent entries being lost from order array.
2026-05-09 17:55:52 +01:00
Zaki 0b3f886337 Fix batch toast spam and add Ctrl+A select all
Batch delete/restore now shows single toast with count instead of one per entry. delEntry() and restoreEntry() accept noToast param. Added Ctrl+A to select all visible entries. Updated keyboard shortcuts help.
2026-05-09 17:44:12 +01:00
Zaki d50aea6845 Add 3 new views (Card, Grouped, Detail) and view dropdown
Replace view toggle buttons with dropdown menu containing all 7 views. Card view: 2-column grid with bigger cards. Grouped view: entries grouped by folder with sticky headers. Detail view: single entry at a time, large text, prev/next navigation. Arrow key navigation for detail view.
2026-05-09 16:51:38 +01:00
Zaki 757efe0908 Prevent native text selection on .vault during rectangle selection 2026-05-09 16:30:20 +01:00
Zaki 6a26dd78cb Fix rect selection in table view: prevent native text drag/selection
Added user-select:none and -webkit-user-drag:none to #entriesContainer.
Also added a dragstart listener that prevents default for any element
that is not [draggable='true'], stopping the browser from creating drag
ghosts of selected table text/headers during rectangle selection.
2026-05-09 16:18:03 +01:00
Zaki efbf8f450a Replace count-badge drag ghost with stacked-card visual for multi-drag 2026-05-09 15:41:08 +01:00
Zaki 9cc4463177 Use CSS classes for drag-dim effect and DOM-appended canvas for drag ghost 2026-05-09 15:39:14 +01:00
Zaki ca159ec4f3 Add custom drag ghost showing selected count for multi-drag 2026-05-09 15:23:21 +01:00
Zaki f7db36d423 Dim all selected cards during drag, not just the dragged one 2026-05-09 15:15:17 +01:00
Zaki 34d20c5224 Fix rect selection to work on vault background, not just entriesContainer
The entriesContainer has no padding so cards fill the grid edge-to-edge;
there is no clickable empty space at the left/top/bottom of the card area
within entriesContainer.  Moved rect-selection initiation into the
document-level mousedown handler so it fires when clicking on ANY
non-interactive element inside .vault (padding, grid gaps, etc.).
Interactive elements (buttons, inputs, folders bar, toolbar, etc.)
still clear selection as expected.
2026-05-09 14:57:13 +01:00
Zaki f9707ebba8 Add click-outside deselection (clear selection on mousedown outside any entry card)
Document mousedown handler clears selection when clicking on any element
that is not an entry card, the batch bar, or an open modal/settings menu.
Works in tandem with entriesContainer rect-select handler: when clicking
inside entriesContainer on empty space the container handler runs first
(setting rectState.active=true) so the document handler skips;
when clicking outside entriesContainer the document handler fires alone
and calls clearSelection().
2026-05-09 14:42:17 +01:00
Zaki a97d05412e Fix duplicate trash drop listener and rectangle selection bugs
- Move trash button drop listener out of setupDrag() to an IIFE so it
  only registers once (was accumulating listeners on every render() call,
  causing multiple toast messages on single drop).
- Fix rectangle selection mousedown handler: use optional chaining on
  closest() for safety with text nodes; avoid calling render() inside
  mousedown (which would detach the event target's children mid-handler)
  and instead just remove .selected class directly from the DOM.
2026-05-09 14:34:20 +01:00
Zaki 5da0deaf94 Enhance selection visibility, add rectangle select, multi drag/drop
- Brighter selection highlight with stronger box-shadow, background, and left-border accent
- Rectangle/band selection: click-drag on empty space to select multiple entries via intersection test
- Drag selected entries to a folder chip to move all, or to trash button to multi-delete
- Multi-drag reorder: dragging a selected entry reorders all selected together
- Table view selection now highlights individual td cells (box-shadow on tr was invisible)
- Escape cancels rectangle selection in progress
2026-05-09 14:09:48 +01:00
Zaki eac02ed17c Replace batch mode toggle with click/Shift/Ctrl selection
- Remove separate 'select mode' toggle and checkbox UI
- Click any entry to select it (blue highlight border)
- Shift+click for range selection between two entries
- Ctrl/Cmd+click to toggle individual entries
- Click entry background or press Escape to clear selection
- Batch action bar appears automatically when items are selected
- Selected entries get accent-color border and highlight
- Single delEntry() cleans up selectedIds
- Shortcut help updated with selection tips
2026-05-09 13:48:22 +01:00