Skip to content

1aad3cd8 - docs: set clipboard-write permission on the Iframe example - #1521

Merged
TaprootFreak merged 6 commits into
DFXswiss:developfrom
Daniel-DFX:1aad3cd8-iframe-clipboard-write
Sep 24, 2026
Merged

TaprootFreak merged 6 commits into
DFXswiss:developfrom
Daniel-DFX:1aad3cd8-iframe-clipboard-write

Conversation

@Daniel-DFX

@Daniel-DFX Daniel-DFX commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

EN:
Recommends allow="clipboard-write" in the README's Iframe integration section, since Chromium rejects navigator.clipboard.writeText in cross-origin Iframes without it. Adds the attribute to the Iframe code example, replaces the invalid self-closing <iframe ... /> with <iframe ...></iframe>, removes TypeScript annotations from the HTML examples so they run as plain JavaScript, and checks the sender of the Iframe close message in both prose and example. Supersedes #1296, which lives on a fork this branch cannot push to.

DE:
Empfiehlt im README-Abschnitt zur Iframe-Integration allow="clipboard-write", da Chromium navigator.clipboard.writeText in cross-origin Iframes sonst ablehnt. Ergänzt das Attribut im Iframe-Codebeispiel, ersetzt das ungültige selbstschliessende <iframe ... /> durch <iframe ...></iframe>, entfernt TypeScript-Annotationen aus den HTML-Beispielen, damit sie als reines JavaScript laufen, und prüft den Absender der Iframe-Close-Message in Text und Beispiel. Ersetzt #1296, dessen Branch auf einem nicht beschreibbaren Fork liegt.

Details

Why

clipboard-write is a Permissions-Policy-gated feature whose default allowlist is self. In a cross-origin Iframe — which is what the documented Iframe integration of app.dfx.swiss is — Chromium therefore rejects navigator.clipboard.writeText unless the embedding page grants the permission via allow="clipboard-write".

Since #1287 (merged), useClipboard (src/hooks/clipboard.hook.ts) copies via navigator.clipboard.writeText and falls back to copy-to-clipboard when the Clipboard API is unavailable or the write rejects. Without the attribute, Iframe users in Chromium take that fallback on every copy through the hook; with it, they get the native path. Other copy sites still call copy-to-clipboard directly and are unaffected either way.

The attribute is therefore an upgrade, not a prerequisite — copy buttons keep working without it because the fallback is not policy-gated — which is why the README recommends ("should") rather than requires it. The sentence describes browser behaviour only, so it does not depend on the app's copy implementation. Firefox and Safari do not enforce clipboard-write delegation (they gate the Clipboard API on user activation), so the attribute is a no-op there.

iframe is not a void element, so the previous self-closing form was invalid HTML: a browser treats /> as > and swallows any markup an integrator pastes after it as fallback content.

The Web Component and React Component integrations render into the host page's own document and need no attribute.

Pre-existing fixes in the touched examples

Review found four pre-existing defects next to the change, fixed here per CONTRIBUTING ("Report every bug you find, including pre-existing ones"):

  • The Iframe and Web Component examples are fenced as html, but their inline <script> used TypeScript annotations (event: MessageEvent<CloseMessage>, message: CloseMessage, data: CloseMessage), which throw a SyntaxError when pasted into a plain <script> tag. The annotations are removed; the CloseMessage interface above still documents the payload. The React example is TypeScript/TSX and stays unchanged.
  • The Usage intro said "three different ways" but lists four; it now says four.
  • The Iframe example used the obsolete frameborder="0" attribute; it now uses style="border: 0".
  • The Iframe example's message listener passed every window message to handleClose. It now ignores messages whose event.origin is not https://app.dfx.swiss or whose event.source is not the embedded Iframe (given id="dfx-services"), so another window cannot forge a close message.
    The Iframe section prose now states the same check, so integrators who do not copy the example verbatim still see it.

Test plan

  • npx prettier --check README.md and format:md:check (prettier 3.9.6, as pinned) — clean
  • Claims checked against src/hooks/clipboard.hook.ts on current develop

Recommend allow="clipboard-write" in the Iframe integration section, since
Chromium does not grant navigator.clipboard to cross-origin Iframes without
it, add the attribute to the code example, and close the iframe tag (iframe
is not a void element).
@Daniel-DFX

Copy link
Copy Markdown
Contributor Author

EN:
The A38 report below records the checks, results and durations.

DE:
Der A38-Bericht unten dokumentiert die Prüfungen, Ergebnisse und Laufzeiten.

Details
Check / Prüfung Duration / Laufzeit Result / Ergebnis Exit code
lint: Lint and Markdown format 0 s not_applicable 0

Durations rounded up to whole seconds / Laufzeiten auf ganze Sekunden aufgerundet.

Original report / Originalbericht
{
  "head": "44b920a4393444b49b546b533305b3baa1b8b0b6",
  "markdown_only": true,
  "private": false,
  "recorded_at": "2026-09-23T16:36:22Z",
  "repo": "DFXswiss/app",
  "required": [
    "lint"
  ],
  "runs": [
    {
      "command": "agent a38 job commands --config '{\"env\":{\"CI\":\"true\"},\"npm\":{\"canaries\":[\"react-app-rewired/package.json\",\"react-scripts/package.json\",\"typescript/lib/typescript.js\",\"prettier/package.json\"],\"node_major\":20},\"steps\":[[\"npm\",\"run\",\"lint\"],[\"npm\",\"run\",\"format:md:check\"]]}'",
      "duration_s": 0.0,
      "exit_code": 0,
      "id": "lint",
      "name": "Lint and Markdown format",
      "result": "not_applicable",
      "timeout_s": 600.0
    }
  ],
  "schema": "dfx-local-ci/v1"
}

@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

dfx pr guard

EN: Thanks for your contribution! This repository follows A38. A38 pass: author local-CI report not required because every changed path is a markdown file.

DE: Danke für deinen Beitrag! In diesem Repository gilt A38. A38 pass: Autor-Local-CI-Report nicht erforderlich, weil jede geänderte Datei eine Markdown-Datei ist.

Details

@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

EN:
I have authorized the recorded CI runs; their results are still pending.

DE:
Ich habe die dokumentierten CI-Läufe freigegeben; ihre Ergebnisse stehen noch aus.

Details
{
  "base": "a40a65cb4aeb9e9bbfaad9a3100542de67f49beb",
  "head": "44b920a4393444b49b546b533305b3baa1b8b0b6",
  "pr": 1521,
  "repo": "DFXswiss/app",
  "runs": [
    {
      "run_id": 35889719812,
      "workflow": ".github/workflows/codeql.yml"
    },
    {
      "run_id": 35889719865,
      "workflow": ".github/workflows/handbook-check.yaml"
    },
    {
      "run_id": 35889719778,
      "workflow": ".github/workflows/pr-review-bot.yml"
    },
    {
      "run_id": 35889720235,
      "workflow": ".github/workflows/pr.yml"
    }
  ]
}

The Iframe and Web Component examples are fenced as HTML, but their inline
scripts carried TypeScript annotations that throw a SyntaxError when pasted
into a plain <script> tag. Also correct the integration count: the list
names four ways, not three.
@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

EN:
I have authorized the recorded CI runs; their results are still pending.

DE:
Ich habe die dokumentierten CI-Läufe freigegeben; ihre Ergebnisse stehen noch aus.

Details
{
  "base": "a40a65cb4aeb9e9bbfaad9a3100542de67f49beb",
  "head": "9e9a337c5d15d39eeab6d978f593503c4307dcac",
  "pr": 1521,
  "repo": "DFXswiss/app",
  "runs": [
    {
      "run_id": 35891026631,
      "workflow": ".github/workflows/codeql.yml"
    },
    {
      "run_id": 35891026547,
      "workflow": ".github/workflows/handbook-check.yaml"
    },
    {
      "run_id": 35891026542,
      "workflow": ".github/workflows/pr-review-bot.yml"
    },
    {
      "run_id": 35891027141,
      "workflow": ".github/workflows/pr.yml"
    }
  ]
}

frameborder is obsolete in HTML; the border is removed with CSS instead.
@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

EN:
I have authorized the recorded CI runs; their results are still pending.

DE:
Ich habe die dokumentierten CI-Läufe freigegeben; ihre Ergebnisse stehen noch aus.

Details
{
  "base": "a40a65cb4aeb9e9bbfaad9a3100542de67f49beb",
  "head": "d207426a903931fc7219ef25f3cb307a1333bd9f",
  "pr": 1521,
  "repo": "DFXswiss/app",
  "runs": [
    {
      "run_id": 35892273485,
      "workflow": ".github/workflows/codeql.yml"
    },
    {
      "run_id": 35892273527,
      "workflow": ".github/workflows/handbook-check.yaml"
    },
    {
      "run_id": 35892273528,
      "workflow": ".github/workflows/pr-review-bot.yml"
    },
    {
      "run_id": 35892274192,
      "workflow": ".github/workflows/pr.yml"
    }
  ]
}

The Iframe example passed every window message to the close handler. It
now only accepts messages from app.dfx.swiss sent by the embedded Iframe.
@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

EN:
I have authorized the recorded CI runs; their results are still pending.

DE:
Ich habe die dokumentierten CI-Läufe freigegeben; ihre Ergebnisse stehen noch aus.

Details
{
  "base": "a40a65cb4aeb9e9bbfaad9a3100542de67f49beb",
  "head": "34b7df3295fb4f6946561938f7137c2f838b37a3",
  "pr": 1521,
  "repo": "DFXswiss/app",
  "runs": [
    {
      "run_id": 35893857717,
      "workflow": ".github/workflows/codeql.yml"
    },
    {
      "run_id": 35893857826,
      "workflow": ".github/workflows/handbook-check.yaml"
    },
    {
      "run_id": 35893857629,
      "workflow": ".github/workflows/pr-review-bot.yml"
    },
    {
      "run_id": 35893858481,
      "workflow": ".github/workflows/pr.yml"
    }
  ]
}

Name the origin and source check in the prose, not only in the code
example, and say precisely that Chromium rejects navigator.clipboard.writeText
in cross-origin Iframes without the clipboard-write permission.
@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

EN:
I have authorized the recorded CI runs; their results are still pending.

DE:
Ich habe die dokumentierten CI-Läufe freigegeben; ihre Ergebnisse stehen noch aus.

Details
{
  "base": "a40a65cb4aeb9e9bbfaad9a3100542de67f49beb",
  "head": "319f1713955e6002d0f43564626412a28cb4c100",
  "pr": 1521,
  "repo": "DFXswiss/app",
  "runs": [
    {
      "run_id": 35894371237,
      "workflow": ".github/workflows/codeql.yml"
    },
    {
      "run_id": 35894371225,
      "workflow": ".github/workflows/handbook-check.yaml"
    },
    {
      "run_id": 35894371021,
      "workflow": ".github/workflows/pr-review-bot.yml"
    },
    {
      "run_id": 35894371407,
      "workflow": ".github/workflows/pr.yml"
    }
  ]
}

If the Iframe id does not match, the listener now ignores the message
instead of throwing a TypeError.
@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

EN:
I have authorized the recorded CI runs; their results are still pending.

DE:
Ich habe die dokumentierten CI-Läufe freigegeben; ihre Ergebnisse stehen noch aus.

Details
{
  "base": "a40a65cb4aeb9e9bbfaad9a3100542de67f49beb",
  "head": "fc21226497418c0b9840689440e613cb7c0101f5",
  "pr": 1521,
  "repo": "DFXswiss/app",
  "runs": [
    {
      "run_id": 35895602945,
      "workflow": ".github/workflows/codeql.yml"
    },
    {
      "run_id": 35895603012,
      "workflow": ".github/workflows/handbook-check.yaml"
    },
    {
      "run_id": 35895603044,
      "workflow": ".github/workflows/pr-review-bot.yml"
    },
    {
      "run_id": 35895603317,
      "workflow": ".github/workflows/pr.yml"
    }
  ]
}

@Daniel-DFX

Copy link
Copy Markdown
Contributor Author

EN:
Ready after 6 review passes.
Recommends allow="clipboard-write" for the Iframe integration and fixes the README's HTML integration examples (valid markup, plain JavaScript, sender check on the close message).

DE:
Bereit nach 6 Review-Durchläufen.
Empfiehlt allow="clipboard-write" für die Iframe-Integration und korrigiert die HTML-Integrationsbeispiele im README (gültiges Markup, reines JavaScript, Absenderprüfung der Close-Message).

Details

Each pass ran independent quality and logic reviews on the full diff; fixes per pass:

  1. 44b920a4 — TypeScript annotations in the html-fenced Iframe and Web Component examples; Usage intro said "three" ways but lists four → fixed in 9e9a337c.
  2. 9e9a337c — obsolete frameborder="0" on the touched Iframe line → style="border: 0" in d207426a.
  3. d207426a — Iframe example accepted message events from any window → origin and source check with id="dfx-services" in 34b7df32.
  4. 34b7df32 — check stated only in the example; clipboard sentence imprecise → prose and "Chromium rejects navigator.clipboard.writeText" wording in 319f1713.
  5. 319f1713 — iframe.contentWindow not null-safe → iframe?.contentWindow in fc212264. A grammar nit on an untouched line (README "as React component") was left out of scope.
  6. fc212264 — 0 findings in both dimensions.

Open comments: none. No reviews, inline comments or review threads; the guard's A38 comment reports no problems (markdown-only change set).

Mergeability at fc212264: mergeable=MERGEABLE against develop (a40a65cb). All pull request checks at this head are green: Build and test, Lint and Markdown format, Full-stack E2E, CodeQL, handbook smoke, review, dfx pr guard, A38 report.

@Daniel-DFX
Daniel-DFX marked this pull request as ready for review September 23, 2026 17:45
@github-actions

Copy link
Copy Markdown

EN:
I have authorized the recorded CI runs; their results are still pending.

DE:
Ich habe die dokumentierten CI-Läufe freigegeben; ihre Ergebnisse stehen noch aus.

Details
{
  "base": "a40a65cb4aeb9e9bbfaad9a3100542de67f49beb",
  "head": "fc21226497418c0b9840689440e613cb7c0101f5",
  "pr": 1521,
  "repo": "DFXswiss/app",
  "runs": [
    {
      "run_id": 35895602945,
      "workflow": ".github/workflows/codeql.yml"
    },
    {
      "run_id": 35895603012,
      "workflow": ".github/workflows/handbook-check.yaml"
    },
    {
      "run_id": 35895603044,
      "workflow": ".github/workflows/pr-review-bot.yml"
    },
    {
      "run_id": 35895603317,
      "workflow": ".github/workflows/pr.yml"
    },
    {
      "run_id": 35897750505,
      "workflow": ".github/workflows/ci-on-ready.yaml"
    }
  ]
}

@TaprootFreak
TaprootFreak merged commit bb21e0c into DFXswiss:develop Sep 24, 2026
12 checks passed
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.

2 participants