Skip to content

Harden WebDAV chat sync#3769

Open
NewstarDevelop wants to merge 6 commits into
chatboxai:mainfrom
NewstarDevelop:webdav-chat-sync-hardening
Open

Harden WebDAV chat sync#3769
NewstarDevelop wants to merge 6 commits into
chatboxai:mainfrom
NewstarDevelop:webdav-chat-sync-hardening

Conversation

@NewstarDevelop

@NewstarDevelop NewstarDevelop commented Jun 21, 2026

Copy link
Copy Markdown

Summary

  • Add WebDAV chat-history sync with HTTPS-only fixed endpoint validation across renderer, desktop IPC, and mobile transport.
  • Validate decrypted sync snapshots, migrate legacy chat sessions, and limit sync scope to chat sessions/metas only.
  • Preserve local data on same-ID content conflicts by importing remote content as a synced copy, while handling metadata-only updates without creating copies.
  • Address review feedback by merging the remote snapshot before upload, stripping local-only blob references and derived file attachment ids from synced snapshots, and encoding Basic Auth credentials as UTF-8.
  • Redact WebDAV password and sync encryption password from normal Settings exports unless API KEY & License export is selected.
  • Protect WebDAV uploads with conditional writes: create with If-None-Match: *, overwrite with If-Match ETags, retry after 412 conflicts, and refuse unsafe overwrites when an existing remote snapshot has no ETag.

Test Plan

  • git diff --check
  • corepack pnpm vitest run src/renderer/packages/sync/service.test.ts src/renderer/packages/sync/webdav.test.ts
  • corepack pnpm vitest run src/renderer/packages/sync src/renderer/packages/settings-export.test.ts
  • corepack pnpm biome check src/shared/sync-webdav.ts src/renderer/packages/sync/service.ts src/renderer/packages/sync/service.test.ts src/renderer/packages/sync/webdav.test.ts
  • corepack pnpm biome check src/renderer/packages/sync/types.ts src/renderer/packages/sync/snapshot.ts src/renderer/packages/sync/service.ts src/renderer/packages/sync/snapshot.test.ts src/renderer/packages/sync/service.test.ts
  • corepack pnpm biome check src/renderer/packages/settings-export.ts src/renderer/packages/settings-export.test.ts src/renderer/routes/settings/general.tsx
  • corepack pnpm biome check src/renderer/pages/SettingDialog/AdvancedSettingTab.tsx
  • corepack pnpm check

Notes

  • WebDAV sync still intentionally excludes local attachment/blob contents; local-only file/image references are stripped from synced snapshots.

Contributor Agreement

I agree to contribute all code submitted in this PR to the open-source community edition licensed under GPLv3 and the proprietary official edition without compensation.
I grant the official edition development team the rights to freely use, modify, and distribute this code, including for commercial purposes.
I confirm that this code is my original work, or I have obtained the appropriate authorization from the copyright holder to submit this code under these terms.
I understand that the submitted code will be publicly released under the GPLv3 license, and may also be used in the proprietary official edition.

  • I have read and agree with the above statement.

Constrain WebDAV transport to HTTPS-only fixed sync endpoints, validate decrypted snapshots, and keep sync scope limited to chat sessions while preserving local conflict safety.

Constraint: Desktop IPC must not become a generic HTTP proxy and mobile/desktop sync behavior must stay consistent.

Rejected: Allowing renderer-provided WebDAV targets through platform transports | preserves SSRF and redirect bypass risk.

Confidence: high

Scope-risk: moderate

Directive: Keep future sync expansion out of settings, credentials, license, OAuth, and provider-token storage unless a new reviewed snapshot contract is added.

Tested: git diff --check; vitest run src/shared/sync-settings.test.ts src/renderer/packages/sync/*.test.ts; biome lint src/shared/sync-settings.test.ts src/shared/sync-webdav.ts src/renderer/packages/sync; tsc --noEmit

Not-tested: Full app packaging and live third-party WebDAV interoperability matrix
@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7915ef81-7940-41aa-b907-e020349f90a8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@itxaiohanglover

Copy link
Copy Markdown

Solid implementation! Using Electron's net.fetch for WebDAV requests bypasses CORS issues. The crypto test for encrypt/decrypt envelope is a good addition. Hardening chat sync is important for reliability.

@themez themez left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the hardening work here. The transport boundary is much safer than a generic renderer-driven fetch, but I found two data-integrity issues that should be fixed before merge, plus one credential compatibility issue.

const webdav = getWebDAVSettings(settings)
await ensureWebDAVCollections(settings, deps.platform)

const [sessions, metas, deviceName] = await Promise.all([

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This upload path overwrites the remote snapshot with only the current device's local sessions/metas. If device A has already uploaded conversation A, then device B with only conversation B clicks Upload Now, the remote snapshot becomes B-only and A disappears from the sync source. Upload should first download and merge the existing remote snapshot, or the UI should make this an explicit destructive overwrite with confirmation.

Comment thread src/renderer/packages/sync/snapshot.ts Outdated
deviceName: string
exportedAt?: string
}): SyncSnapshot {
const sessions = input.sessions.filter(isChatSession)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The snapshot includes whole Session objects, but this PR only syncs sessions/metas and not the local blobs referenced by storageKey fields in messages, pictures, files, links, avatars, etc. Importing this snapshot on another device will create sessions with dangling local references, so image/file/link-backed history appears synced but cannot render or be reused. Either include the referenced blobs in the WebDAV sync contract or strip/mark these references during export/import.

webdavRequest?: (request: WebDAVRequest, baseUrl: string) => Promise<WebDAVResponse>
}

export function buildBasicAuthHeader(username: string, password: string): string {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btoa() only accepts Latin-1 input. WebDAV usernames or app passwords containing non-ASCII characters will throw before the request is sent. Please encode username:password as UTF-8 bytes before base64 encoding.

@themez themez left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One process item before this can move forward: the repository PR template includes a Contributor Agreement section, but this PR body does not include the checkbox confirmation.

Please update the PR description to include and check the template confirmation:

[x] I have read and agree with the above statement.

This confirms the submitted code is authorized for both the GPLv3 community edition and the proprietary official edition under the terms in .github/PULL_REQUEST_TEMPLATE.md.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants