mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-17 16:37:43 +00:00
* fix(sync): never upload plaintext ops for E2EE-mandatory providers SuperSync's first-time setup ran an initial sync (dialog-sync-cfg save -> sync(true)) BEFORE the user chose an encryption password, so all local ops (incl. issue-provider credentials) were uploaded to the server in cleartext. Completing setup deleted them; aborting left them stored indefinitely, breaking the E2EE promise (GHSA-9v8x-68pf-p5x7). Add an optional `isEncryptionMandatory` capability to OperationSyncCapable (true for SuperSync) and refuse to upload in the op-log upload path while no usable key is configured. Downloads still run (merge-first) and the encryption- enable flow performs the first, encrypted upload, so the setup flow and prompt are unchanged. File-based providers, where unencrypted sync is a legitimate user choice, leave the flag unset. * fix(sync): fail closed on plaintext snapshot for E2EE-mandatory providers Multi-review hardening for GHSA-9v8x-68pf-p5x7. The op-upload guard closes the reported leak, but SnapshotUploadService.deleteAndReuploadWithNewEncryption could still push a plaintext snapshot for SuperSync on two adjacent paths: the (today UI-unreachable) disable-encryption flow, and a keyless import declaring isEncryptionEnabled:true. Reject an unencrypted snapshot for an encryption- mandatory provider before any destructive deleteAllData, so the "never transmit plaintext" invariant holds regardless of caller. Also lower the mandatory-encryption upload-skip log from warn to normal: it is an expected by-design skip during the pre-encryption setup window and would otherwise fire on every auto-sync cycle. * fix(sync): consolidate op-log into the encryption-enable snapshot Follow-up to the GHSA-9v8x-68pf-p5x7 upload guard. With the guard, first-time SuperSync setup leaves the whole local history unsynced until encryption is enabled; the enable-snapshot then represents that full state, but the ops were re-uploaded incrementally on top of it on the next sync (redundant server op-log bloat, and previously untested at whole-history volume). deleteAndReuploadWithNewEncryption now captures the pending ops the snapshot subsumes (before the destructive delete, under runWithSyncBlocked + a modal dialog so the set is stable) and marks them synced after a successful upload — mirroring planRegularOpsAfterFullStateUpload in the op-log upload path, which this direct snapshot upload bypasses. Also fixes the same latent redundancy in the enable-from-settings-with-pending-ops flow. Adds a multi-client e2e: local task history exists before first-time encrypted setup, then a second client with the same password receives exactly those tasks with no duplicates, conflicts, or errors. * ci(e2e): add optional grep input to manual SuperSync e2e dispatch * fix(sync): capture subsumed ops before state snapshot to prevent mark-synced data loss deleteAndReuploadWithNewEncryption captured getUnsynced() AFTER the full-state snapshot, so an op created in that window was marked synced yet absent from the snapshot — silently lost. Capture the unsynced set first: every marked-synced op is then guaranteed present in the snapshot, and a concurrent op arriving after the capture is left unsynced and re-uploaded next sync (idempotent by op id). * test(sync): mock WebCrypto so mandatory-encryption guard test reaches the guard The 'enabling without a usable key' case passed isEncryptionEnabled: true but did not mock WebCrypto, so the availability check threw WebCryptoNotAvailableError in non-secure CI before the /unencrypted snapshot/ guard under test. |
||
|---|---|---|
| .. | ||
| actions | ||
| annotations | ||
| ISSUE_TEMPLATE | ||
| workflows | ||
| CODE_OF_CONDUCT.md | ||
| CODEOWNERS | ||
| CONTRIBUTING.md | ||
| dependabot.yml | ||
| FUNDING.yml | ||
| PULL_REQUEST_TEMPLATE.md | ||
| SECURITY-SETUP.md | ||