Skip to content

fix(frontend): copy to clipboard fails over HTTP (non-secure context)#9242

Merged
dgarros merged 3 commits into
opsmill:stablefrom
DharmaBytesX:fix/8857-copy-id-hfid
May 19, 2026
Merged

fix(frontend): copy to clipboard fails over HTTP (non-secure context)#9242
dgarros merged 3 commits into
opsmill:stablefrom
DharmaBytesX:fix/8857-copy-id-hfid

Conversation

@DharmaBytesX

@DharmaBytesX DharmaBytesX commented May 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • navigator.clipboard is unavailable in non-secure contexts (HTTP, non-localhost); previous code attempted it unconditionally, causing silent failures.
  • Added an explicit window.isSecureContext guard: when the Clipboard API is unavailable, a synchronous document.createRange() + window.getSelection() + execCommand("copy") fallback is used instead.
  • Replaced the previous textarea-based fallback, which was broken by React Aria's Popover focus trap — the textarea could not receive focus while the menu was open, so execCommand("copy") had no selection to act on.

Fixes #8857

Test plan

  • Open Infrahub over HTTP (non-localhost IP)
  • Navigate to any object detail page → Actions → Copy ID: verify clipboard contains the UUID
  • Actions → Copy HFID: verify clipboard contains the human-friendly ID
  • Profile → Tokens → create a new token → click copy: verify clipboard contains the token value
  • Verify all three copy actions still work over HTTPS / localhost (secure context, Clipboard API path)

Summary by cubic

Fixes copy actions over HTTP so users can copy IDs and tokens in non-secure contexts, without breaking HTTPS behavior. Restores the async contract of useCopyToClipboard to preserve await ordering. Fixes #8857.

  • Bug Fixes
    • Guard on window.isSecureContext and navigator.clipboard; fall back to selection-based document.createRange() + window.getSelection() + document.execCommand("copy") compatible with the React Aria popover focus trap.
    • Make copyToClipboard async; add tests for secure/non-secure, missing clipboard, and rejected writes; fix Biome lint errors in the tests.

Written for commit 399e428. Summary will update on new commits. Review in cubic

The browser Clipboard API (navigator.clipboard) is only available in
secure contexts (HTTPS or localhost). When Infrahub is accessed over
plain HTTP, clipboard writes silently failed because the code attempted
the async API without checking context security first.

Use document.createRange() + window.getSelection() + execCommand("copy")
as a synchronous fallback when the secure context or Clipboard API is
unavailable. This avoids the React Aria focus-trap issue that broke the
previous textarea-based fallback (the textarea could not receive focus
while a Popover was open).

Fixes opsmill#8857
@DharmaBytesX DharmaBytesX requested a review from a team as a code owner May 13, 2026 10:36
@DharmaBytesX

Copy link
Copy Markdown
Contributor Author

Tested manually on HTTP (non-localhost IP). Copy ID, Copy HFID, and Copy Token all work correctly after the fix.

@DharmaBytesX

Copy link
Copy Markdown
Contributor Author

Hi! This fix for the clipboard issue over HTTP has been tested manually and is ready for review — could someone take a look when you have a moment? Thanks!

@pa-lem pa-lem 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 fix, the secure-context detection and selection-based fallback are the right approach. One small follow-up to keep the public API consistent:

The hook signature changed from async (value) => Promise<void> to (value) => void. That breaks the contract for
frontend/app/src/shared/components/buttons/clipboard.tsx:21-24, which still does:

const handleCopy = async () => {
  await copyToClipboard(value);   // now awaits a non-Promise → resolves immediately
  toast(<Alert message={alert} type={ALERT_TYPES.INFO} />);
};

The toast now fires before the async navigator.clipboard.writeText() settles, so on the secure-context path the success toast can show even if the write rejects.

Suggested change would be that we keep the hook awaitable:

const copyToClipboard = React.useCallback(async (value: string) => {
  function confirmCopied() {
    setIsCopied(true);
    setTimeout(() => setIsCopied(false), COPIED_FEEDBACK_DURATION);
  }

  if (!window.isSecureContext || !navigator.clipboard) {
    oldSchoolCopy(value);
    confirmCopied();
    return;
  }

  try {
    await navigator.clipboard.writeText(value);
    confirmCopied();
  } catch {
    oldSchoolCopy(value);
    confirmCopied();
  }
}, []);

This preserves the original Promise return type, so await copyToClipboard(...) in clipboard.tsx keeps its original ordering guarantee, and the other four
call sites (which don't await) remain unaffected.

Nice-to-have: a small unit test for useCopyToClipboard covering both paths (mock window.isSecureContext = false and navigator.clipboard = undefined) would
protect this dual-path logic from future regressions.

- Make copyToClipboard async (returns Promise<void>) so callers
  that await it (e.g. clipboard.tsx) get correct ordering guarantees
- Rewrite promise chain as try/await/catch for clarity
- Add unit tests covering secure-context, non-secure context,
  unavailable clipboard, and rejected writeText paths

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

@DharmaBytesX DharmaBytesX left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thx for the review @pa-lem. Made the fix with Claude Code, restored the async contract and added unit tests covering both paths. Then, I manually verified the fix by booting up a dev instance and testing on Firefox myself.

@pa-lem pa-lem self-requested a review May 19, 2026 14:39
@dgarros dgarros merged commit 78ac2c4 into opsmill:stable May 19, 2026
54 checks passed
@DharmaBytesX DharmaBytesX deleted the fix/8857-copy-id-hfid branch May 20, 2026 11:18
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.

bug: Copy ID and HFID does not work

3 participants