Add-on iframe: delegate microphone + camera Permissions Policy#52068
Add-on iframe: delegate microphone + camera Permissions Policy#52068pvizeli wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
Hello @pvizeli,
When attempting to inspect the commits of your pull request for CLA signature status among all authors we encountered commit(s) which were not linked to a GitHub account, thus not allowing us to determine their status(es).
The commits that are missing a linked GitHub account are the following:
fe65390a4f94c1ce60046d0625e079786f4046a6- This commit has something that looks like an email address (pascal.vizeli@nabucasa.com). Maybe try linking that to GitHub?.
Unfortunately, we are unable to accept this pull request until this situation is corrected.
Here are your options:
-
If you had an email address set for the commit that simply wasn't linked to your GitHub account you can link that email now and it will retroactively apply to your commits. The simplest way to do this is to click the link to one of the above commits and look for a blue question mark in a blue circle in the top left. Hovering over that bubble will show you what email address you used. Clicking on that button will take you to your email address settings on GitHub. Just add the email address on that page and you're all set. GitHub has more information about this option in their help center.
-
If you didn't use an email address at all, it was an invalid email, or it's one you can't link to your GitHub, you will need to change the authorship information of the commit and your global Git settings so this doesn't happen again going forward. GitHub provides some great instructions on how to change your authorship information in their help center.
- If you only made a single commit you should be able to run
(substituting "Author Name" and "
git commit --amend --author="Author Name <email@address.com>"email@address.com" for your actual information) to set the authorship information. - If you made more than one commit and the commit with the missing authorship information is not the most recent one you have two options:
- You can re-create all commits missing authorship information. This is going to be the easiest solution for developers that aren't extremely confident in their Git and command line skills.
- You can use this script that GitHub provides to rewrite history. Please note: this should be used only if you are very confident in your abilities and understand its impacts.
- Whichever method you choose, I will come by to re-check the pull request once you push the fixes to this branch.
- If you only made a single commit you should be able to run
We apologize for this inconvenience, especially since it usually bites new contributors to Home Assistant. We hope you understand the need for us to protect ourselves and the great community we all have built legally. The best thing to come out of this is that you only need to fix this once and it benefits the entire Home Assistant and GitHub community.
Thanks, I look forward to checking this PR again soon! ❤️
|
Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍 |
The add-on ingress iframe in ``ha-panel-app.ts`` ships without an ``allow=`` attribute, so the Permissions Policy default of *deny* applies for ``microphone`` and ``camera`` on the cross-origin iframe. An add-on that wants to call ``getUserMedia`` — voice notes, dictation, video calls, photo capture — fails silently with ``NotAllowedError`` before the browser even surfaces the permission prompt. The failure is most visible on the Android Companion app, where there's no "open in a new tab" escape: the user presses the mic button and nothing happens, no toast, no logs. Delegate ``microphone``, ``camera``, and ``clipboard-write`` to the add-on iframe. Add-ons are first-party software the user explicitly installs, and Chrome's runtime permission prompt still gates the hardware access — the ``allow=`` attribute just lets the iframe *request* the prompt instead of being blocked at the policy layer. ``clipboard-write`` is bundled in because the next-most-frequent silent-fail in add-on land is ``navigator.clipboard.writeText`` for "copy link" / "copy code" affordances, blocked by the same mechanism.
fe65390 to
9b53a3f
Compare
|
@balloob is that somethings we can do? I need access to SocialHome to use the camera and microphone for QR code (pairing) and for speech DMs or transcript posts, and the voice calls and video calls |
silamon
left a comment
There was a problem hiding this comment.
You will also need to define the sandbox attribute when we're adding an allow. You can take a look at the iframe panel to have an example.
|
@silamon The sandbox property is not needed for the allow camera to work. It would provide extra security hardening, but I am also unsure if we were to break something that an add-on relies on? |
|
We go all-in on security. We don't want microphone or camera access to be granted to an addon without explit permission if it was granted before to the frontend. |
|
I agree with @balloob, the sandbox will break the add-ons UI. The only person with more experience in how to quirk UI to work with add-ons is @frenck - if he feels safe, let's do it. But what I can remember, there were some add-ons on my end with excessive URL rewrites that now follow allow-same-origin. In general, ingress is difficult because we sometimes do not control the app or the UI behind it. A user install an add-on and would like to have it working, they not care much about the other parameters as they decided it to install it. So @frenck do you think that option (sandbox) is safe? |
|
@silamon you got me into a wild rabbit hole. You are right, but our default implementation would make it wrong. We should fix both 👍 You are right that However, our default |
Split IFRAME_SANDBOX into two constants: IFRAME_SANDBOX (without allow-same-origin) for add-on ingress iframes that need origin isolation, and IFRAME_SANDBOX_SAME_ORIGIN for external iframes that need same-origin access. This ensures add-on iframes can't inherit camera/microphone permissions already granted to the Home Assistant origin, and prevents same-origin iframes from removing their own sandbox. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR aims to improve add-on ingress iframe capabilities by delegating Permissions Policy features so embedded add-on UIs can successfully request browser-gated APIs like microphone/camera and write to the clipboard.
Changes:
- Adds a Permissions Policy
allowattribute to the add-on ingress iframe (ha-panel-app) to delegatemicrophone,camera, andclipboard-write. - Refactors iframe sandbox constants to separate “base sandbox” from “sandbox + allow-same-origin”.
- Updates existing iframe embeds to use the new
IFRAME_SANDBOX_SAME_ORIGINconstant.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/util/iframe.ts |
Splits sandbox constants into a base set and a ..._SAME_ORIGIN variant. |
src/panels/lovelace/cards/hui-iframe-card.ts |
Switches to the new IFRAME_SANDBOX_SAME_ORIGIN constant (behavior intended to remain equivalent). |
src/panels/iframe/ha-panel-iframe.ts |
Switches to the new IFRAME_SANDBOX_SAME_ORIGIN constant (behavior intended to remain equivalent). |
src/panels/app/ha-panel-app.ts |
Adds allow="microphone; camera; clipboard-write" and introduces a sandbox attribute on the ingress iframe. |
|
I think from my view that it is good to go. I've added a second-opinion though since I'm still not convinced about not needing the allow-source-origin. |
|
If we allow source origin, and since the origin is the same, it will have full access to window.parent and can do whatever it wants, including just adding a script tag there. |
Proposed change
The add-on ingress iframe rendered by
ha-panel-app.tscurrently ships with noallow=attribute, so the W3C Permissions Policy default of deny applies formicrophoneandcameraon the cross-origin iframe.Any add-on that wants to call
getUserMedia— voice notes, dictation, video calls, photo capture, conference apps — fails silently withNotAllowedErrorbefore the browser even surfaces the runtime permission prompt. The page sees a rejected promise but the user sees nothing change.This is most visible on the Android Companion app, where the add-on iframe is the only entry point. The user presses the mic, nothing happens, no toast, no logs. The same problem exists in a desktop Chrome tab opened to the HA frontend but is less surprising there because the user can right-click → open in a new tab as a workaround.
The fix is a one-line attribute: delegate
microphone,camera, andclipboard-writeto the add-on iframe.<iframe class=${classMap({ loaded: this._iframeLoaded, "kiosk-mode": this._kioskMode, })} title=${this._addon.name} src=${this._addon.ingress_url!} + allow="microphone; camera; clipboard-write" @load=${this._checkLoaded} ${ref(this._iframeRef)} > </iframe>Why this is safe
allow=attribute only allows the iframe to request the prompt; it doesn't grant access. The user still gets the canonical "Use your microphone?" dialog the first time, and the Android Companion app's existingWebChromeClient.onPermissionRequestflow (which already checks the runtimeRECORD_AUDIOAndroid permission) is unchanged.clipboard-writeis bundled in because the next-most-frequent silent-fail in add-on land isnavigator.clipboard.writeTextfor "copy link" / "copy code" affordances, blocked by the same Permissions Policy mechanism. Add-ons commonly need to surface copyable values; the symmetry keeps the policy delegation list tight.Type of change
Example use cases
getUserMedia({video: {facingMode: 'environment'}}).Additional information
hui-iframe-card.ts(Lovelace iframe card) orha-panel-iframe.ts(legacy "Webpage" panel) — those embed user-configured arbitrary URLs and have a different trust model. Keeping this change strictly to the add-on ingress iframe.Checklist
prettier --write).