Skip to content

feat: rclone-crypt folder vault PoC#2566

Draft
dschmidt wants to merge 6 commits into
mainfrom
feat/e2ee
Draft

feat: rclone-crypt folder vault PoC#2566
dschmidt wants to merge 6 commits into
mainfrom
feat/e2ee

Conversation

@dschmidt
Copy link
Copy Markdown
Contributor

@dschmidt dschmidt commented May 20, 2026

⚠️ This PR explores feasibility. Nothing here is set in stone.
Function names, type names, extension point IDs, file layout, the shape of
the public surface, all of it is subject to change. DRY was explicitly not
an objective for this PoC, the goal was wiring the vault story end to end
to learn where the seams actually fall. Treat this as a proposal, not a
proposed merge.

Summary

Adds a folderVault extension type and the first implementation
(web-app-rclone-crypt) that surfaces rclone-crypt
compatible vaults in the OpenCloud Web UI under cleartext names. End users see
a *.vault folder, unlock it once per session via a passphrase, and read,
edit, upload and delete content as if it were unencrypted, all crypto happens
in the browser.

Plugin surface

  • FolderVaultExtension, pluggable filename/path/content (de)cryption engine
  • ResourceIndicatorExtension, pluggable per resource status indicators
  • in memory passphrase store (lost on reload, by design)
  • router level unlock guard mirroring the public link flow
  • empty vault create passphrase UX
  • lock vault / unlock vault context actions

Cross cutting integrations

Vault awareness wired into listing (loaderSpace), AppWrapper (load/save),
single file upload, drag drop directory tree upload, create file,
create folder, delete, SSE postprocessing, route guard.

Test coverage

Cucumber scenarios under tests/e2e/cucumber/features/rclone-crypt/ drive an
rclone CLI fixture to verify read, edit save, single file upload and drag
drop upload, all decrypt back to expected cleartext via the rclone CLI as a
ground truth oracle.

Notes

Known FIXMEs scattered:

  • content encrypt/decrypt buffers the entire payload before emitting
  • vault awareness lives in every caller rather than behind a single
    decorator layer
  • hardcoded foobar is gone but the unlock flow could grow more checks

With the touch points now known, the right helpers and abstractions (likely a
webdav decorator or folder service decorator layer that absorbs the path /
content translation) will be evaluated next.

dschmidt added 2 commits May 20, 2026 12:46
Introduces a `folderVault` extension type so apps can transparently encrypt
and decrypt the names and contents of folders flagged as vaults, plus the
first implementation (`web-app-rclone-crypt`) that surfaces rclone-crypt
compatible vaults under cleartext names.

Wires vault-awareness into listing, AppWrapper, single-file and drag-drop
upload, create-file, create-folder and delete. Adds a runtime-level unlock
guard that mirrors the public-link flow, an in-memory passphrase store,
empty-vault create-passphrase UX and a lock-vault context action. Covered
by cucumber e2e scenarios that drive an rclone CLI fixture.
dschmidt added 4 commits May 20, 2026 12:58
Replaces the hand-rolled collectStream loops and single-emit ReadableStream
wrappings in every vault encrypt/decrypt call site with two small helpers
(streamToArrayBuffer, streamToBlob) plus Blob.stream() for input. The
engine's streaming contract stays unchanged; only the call sites get tidier
and the future "swap engine for real block streaming" lands without
touching them.
- useResourceIndicators: tolerate test mocks that omit requestExtensions
- useFileActions: silently bail in openEditor when no route exists
  (instead of filtering the action out, which broke route-null tests)
- useFileActionsCreateNewFile: null-safe appFileExtension access
- useFileActionsDeleteResources: drop the sync/async zalgo path, always
  return Promises; matching tests now await
- web-test-helpers defaultComponentMocks: hasRoute defaults to true so
  the overwhelming majority of suites get the expected behaviour
- web-app-preview: only opt out of preview service on explicit
  hasPreview() === false, preserve legacy behaviour for missing method
- web-app-rclone-crypt: drop unused imports
…c DragEvent

Headless Chrome silently swallows `new DragEvent(...).dispatchEvent(...)`
fired from inside `page.evaluate`, so the drag-drop upload scenario
worked headed and failed headless. Switching the helper to
`locator.dispatchEvent('drop', { dataTransfer })` routes the event
through CDP, where both modes behave the same way.

dataTransfer is built in the page via `evaluateHandle(new DataTransfer())`
so File objects and webkitRelativePath stay intact.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant