Files
kandev/docs/plans/secure-context-browser-fallbacks/plan.md
T
2026-08-24 11:09:03 +00:00

143 lines
6.4 KiB
Markdown

---
spec: docs/specs/auth/requirements/secure-context-browser-fallbacks.md
created: 2026-08-02
status: implemented
---
# Implementation Plan: Secure-context browser fallbacks
## Overview
Route every client-only UUID through the existing guarded generator, then
extract the existing clipboard fallback into a shared utility and migrate
direct Clipboard API call sites to it. The audit confirms that file hashing,
voice input, notifications, and sound already check capability boundaries; the
focused tests will preserve those fallbacks while covering the newly repaired
workflow, layout, and copy paths.
## Root cause
`useWorkflowCreation`, workflow step creation, and layout profile creation call
`crypto.randomUUID()` directly. On a non-localhost HTTP origin the browser
exposes `crypto` but not `randomUUID`, so Add Workflow throws before its draft
state is updated. The shared `generateUUID()` helper already handles that
condition, but those call sites bypass it. Several copy actions similarly call
`navigator.clipboard.writeText()` directly even though the existing copy hook
has a DOM fallback for insecure contexts.
## Frontend — client-only UUIDs
- `apps/web/app/settings/workspace/use-workflow-creation.ts`: use
`generateUUID()` for temporary workflow IDs.
- `apps/web/components/settings/workflow-card-actions.ts`: use
`generateUUID()` for temporary step IDs.
- `apps/web/lib/layout/layout-profiles.ts`: use `generateUUID()` for layout
profile IDs.
- `apps/web/app/settings/workspace/use-workflow-creation.test.ts`,
`apps/web/components/settings/workflow-card-actions.test.ts`, and
`apps/web/lib/layout/layout-profiles.test.ts`: add insecure-context coverage
with `crypto` missing `randomUUID`.
- Keep `apps/web/lib/utils/file-diff.ts` unchanged unless its existing guarded
fallback needs a test adjustment; it already degrades to `djb2Hash` when
`crypto.subtle` is unavailable.
## Frontend — clipboard fallback
- Add `apps/web/lib/utils/copy-to-clipboard.ts` with the existing dialog-aware
DOM fallback and a promise-returning `copyToClipboard(text)` function.
- Refactor `apps/web/hooks/use-copy-to-clipboard.ts` to use the shared utility,
preserving its copied state and timing.
- Migrate direct Clipboard API calls in the settings, onboarding, task,
diff/editor, review, and share surfaces to the shared utility. Preserve each
caller's current success state, toast, and error behavior.
- The audited call sites are `apps/web/app/settings/agents/page.tsx`,
`apps/web/app/settings/agents/[agentId]/profiles/[profileId]/command-preview-card.tsx`,
`apps/web/components/settings/external-mcp-settings.tsx`,
`apps/web/components/automations/trigger-configs/webhook-config.tsx`,
`apps/web/components/task/executor-environment-info.tsx`,
`apps/web/components/task/port-forward-dialog.tsx`,
`apps/web/components/task/simple/OfficeSimplePane.tsx`,
`apps/web/components/task/inspector/annotations-panel.tsx`,
`apps/web/components/task/share/share-dialog.tsx`,
`apps/web/components/task/chat/messages/auth-methods-panel.tsx`,
`apps/web/components/task/chat/messages/tool-edit-message.tsx`,
`apps/web/components/editors/file-actions-dropdown.tsx`,
`apps/web/components/editors/monaco/use-diff-viewer-comments.ts`,
`apps/web/components/editors/monaco/diff-viewer-context-menu.tsx`,
`apps/web/components/editors/monaco/monaco-diff-viewer.tsx`,
`apps/web/components/diff/diff-header-toolbar.tsx`,
`apps/web/components/review/review-diff-toolbar.tsx`,
`apps/web/components/onboarding/step-agents.tsx`,
`apps/web/components/settings/account/api-tokens.tsx`,
`apps/web/components/settings/system/log-viewer.tsx`,
`apps/web/components/settings/system/invite-dialog.tsx`, and
`apps/web/components/settings/ssh-agent-readiness-card.tsx`.
- Add `apps/web/lib/utils/copy-to-clipboard.test.ts` covering modern success,
missing API, rejected API, and dialog focus containment. Update the hook test
only where its implementation seam changes.
## Existing capability audit
- `apps/web/lib/utils/file-diff.ts` already guards `crypto.subtle` and falls
back to `djb2Hash`.
- Voice input gates its UI on secure-context/capability checks and catches
capture failures; notification permission actions check `Notification`
before use; sound creation checks `AudioContext` before construction.
- No behavior change is planned for those already guarded paths; their
existing tests remain part of focused frontend verification.
## Tests
- **UUID regression:** no `randomUUID` must not prevent workflow creation,
step addition, or layout profile creation. Files listed above; Vitest hook and
pure-function tests.
- **Clipboard regression:** missing/rejected Clipboard API uses the DOM
fallback without an uncaught rejection. New utility test plus existing hook
tests.
- **Existing fallbacks:** run the file-diff, voice, notification, and sound
tests selected by the focused test command where applicable.
## E2E and mobile parity
This repair changes shared state/utility behavior, not layout, navigation,
touch targets, scrolling, or mobile composition. The existing workflow settings
desktop/mobile E2E coverage remains the rendered regression path; no new mobile
scenario is required for this data-normalization change. A browser-level
insecure-origin smoke run is optional if an isolated HTTP instance is already
available.
## Risks and out of scope
- The DOM copy fallback depends on `document.execCommand("copy")`, which is
deprecated but is the compatibility path already used by Kandev.
- Fallback UUIDs are not cryptographically secure and must stay limited to
client-only identifiers.
- Backend/API contracts, TLS setup, and security-token generation are out of
scope.
## Implementation waves
Wave 1 (sequential):
- [x] [Task 01: UUID fallback audit](task-01-uuid-fallback.md)
Wave 2 (sequential; depends on Task 01):
- [x] [Task 02: Clipboard fallback migration](task-02-clipboard-fallback.md)
## Verification Results
### Task 01 — UUID fallback audit
- Focused Vitest: 4 files, 78 tests passed.
- Web typecheck passed.
- Static search found only the guarded `generateUUID()` implementation.
### Task 02 — Clipboard fallback migration
- Focused utility/hook Vitest: 3 files, 21 tests passed.
- Broader task-defined Vitest: 360 files, 2,647 tests passed, 4 skipped.
- Web typecheck, targeted ESLint, Prettier, and `i18n:ratchet` passed.
- Static search found no direct application Clipboard API calls outside the
shared guarded utility.