Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BroadcastChannel being blocked need permissions dialog #44

Open
taf2 opened this issue Feb 16, 2024 · 25 comments
Open

BroadcastChannel being blocked need permissions dialog #44

taf2 opened this issue Feb 16, 2024 · 25 comments

Comments

@taf2
Copy link

taf2 commented Feb 16, 2024

There needs to be away to allow an application that's embedded into a third party application like Salesforce, HubSpot, Zoho to still send messages back and forth between a WebRTC popout window and an embedded iframe. Web applications that need persistent connection to carry a voice call while still allowing the UI page to be reloaded are SOL with new privacy storage changes that were rolled out in Chrome 121. BroadcastChannel was an effective way for an iframe to communicate with a popout window. Further I would suspect if the iframe is the window.opener of the popout window they should* be able to communicate and be treated as the same "partition". I can see other tabs that are open separate outside of the iframe not being shared but if the original origin with the iframe did the window.open call would make a lot of sense to allow BroadcastChannel to postMessage and receive messages between the parent and child on the same origin.

At the very least having something like: ```

const handle = await document.requestStorageAccess({all: true});

handle.postMessage...
handle.onmessage

// or something similar or someway to send messages


IMO - these changes continue to push more web applications to consider desktop/mobile as the only viable path forward.
@wanderview
Copy link

I believe this is available in this origin trial:

https://developers.google.com/privacy-sandbox/blog/saa-non-cookie-storage

@taf2
Copy link
Author

taf2 commented Feb 16, 2024

Sorry if I'm not seeing it - but the only things I see available in chrome 121 (current release)
Screenshot 2024-02-16 at 2 51 04 PM

caches: CacheStorage {}
indexedDB: IDBFactory {}
localStorage: Storage {}
locks: LockManager {}
sessionStorage: Storage {length: 0}

I'm not seeing BroadcastChannel, and trying to use it still fails with the origin trial. It appears to only work if chrome://flags/#third-party-storage-partitioning is disabled.

@wanderview
Copy link

@arichiv Can you help here? The blog post suggests BroadcastChannel was added in M121.

@arichiv
Copy link

arichiv commented Feb 16, 2024

The code went in trunk November 10 https://chromium-review.googlesource.com/c/chromium/src/+/5012979 and the branch cut for M121 was December 4 https://chromiumdash.appspot.com/schedule.

I think what you're seeing are the object members, and if you expand the prototype section you will see the BroadcastChannel function listed.

@taf2
Copy link
Author

taf2 commented Feb 16, 2024

@arichiv ok thank you i see

const handle = await document.requestStorageAccess({all: true});
const bc = new handle.BroadcastChannel("channel")

I don't see documentation around being able to only request access to BroadcastChannel...

Any clarification to add on the expected June end of the origin trial. Is this then going to potentially be accepted and an API we can count on or do we need to start work on a native solution to avoid future outages related to modifications to the web platform?

@arichiv
Copy link

arichiv commented Feb 16, 2024

There's no 'new' needed in this context, try:

const handle = await document.requestStorageAccess({BroadcastChannel: true});
const bc = handle.BroadcastChannel("channel");

Depending on usage/feedback from developers and other browser vendors we hope it'll be generally available.

@taf2
Copy link
Author

taf2 commented Feb 16, 2024

@arichiv

Thank you for the usage clarification!

  • hoping there remains away to keep web applications viable... not everything is about ads (really enjoy building on the web!)

@arichiv
Copy link

arichiv commented Feb 16, 2024

I spent a bunch of time this month adding SharedWorker support, so I'm rooting for the API at least :-)

@taf2
Copy link
Author

taf2 commented Feb 16, 2024

@arichiv i'm sorry i am still running into an issue or maybe misunderstanding of the way this should* work - (running a bit of a fever right now so might just be doing something silly)

Here is how my application works:

Within Salesforce I have an embedded iframe (OpenCTI AdapterURL) is pointing to my domain (calldomain.example.com/salesforce_phone)

I have a web component tag in a shadow DOM (sharing in case this matters) that class instance exposes a launch phone button.

Screenshot 2024-02-16 at 6 35 50 PM

the DOM within salesforce:
Screenshot 2024-02-16 at 6 42 19 PM

In the connectedCallback:

Controller UI in embedded iframe.

  connectedCallback() {
    this.shadow = this.attachShadow({ mode: 'open' });
    this.enableElement();
  }

  async enableElement() {
    // see: https://github.com/privacycg/storage-partitioning/issues/44
    if (typeof(document.requestStorageAccess) == 'function') {
      console.log("requestStorageAccess");
      this.context = await document.requestStorageAccess({BroadcastChannel: true});
      this.phone_channel = this.context.BroadcastChannel('__phone_device');
    } else {
      this.phone_channel = new BroadcastChannel('__phone_device');
    }
...

After getting an access token it pops a window passing that token to the popout window:

Click handler to launch phone device when it's not detected

  async openDevice() {
    try {
      const auth = await this.getLoginAccessToken();
      const windowFeatures = "width=600,height=450,menubar=no,location=no,resizable=no,scrollbars=yes,status=yes";
      window.open(`https://${window.location.hostname}/phoneapp/token?session=${auth.sessionId}&token=${auth.token}&email=${auth.email}`, "CT
    } catch (e) {
      this.displayAccessTokenError(e);
    }
  }

From which the popout window is defined by a device web component. That class handles the WebRTC elements of the communication and uses a BroadcastChannel created in it's connectedCallback to pass messages back and forth between the CRM embedded iframe interface. This allows the communication channel to be decoupled from the UI. Meaning agents can reload the page without dropping a phone call...

Device element:

  connectedCallback() {
    this.shadow = this.attachShadow({ mode: 'open' });
    this.enableElement();
  }

  async enableElement() {
    if (typeof(document.requestStorageAccess) == 'function') {
      console.log("requestStorageAccess");
      this.channel = (await document.requestStorageAccess({BroadcastChannel: true})).BroadcastChannel('__phone_device');
    } else {
      this.channel = new BroadcastChannel('__phone_device');
    }

What i'm missing is messages between the channels are not received even when using document.requestStorageAccess to get access to the channel... Should i see UI asking me to grant permission? Also interestingly when I add the conditional code to requestStorageAccess now when toggling the feature off here: chrome://flags/#third-party-storage-partitioning the communication remains broken. e.g. using requestStorageAccess must not be correct within the iframe to the popout window...

@arichiv
Copy link

arichiv commented Feb 16, 2024

Is cookie partitioning on? Without that you won't see the prompt.

Also:
(1) you will have had to interact with the iframe's origin as a top-level site at some point prior
(2) the call to requestStorageAccess must be called in the event response to some sort of user interaction (click) within the iframe

@taf2
Copy link
Author

taf2 commented Feb 16, 2024

for (2) interesting I actually am not setting any cookies on my domain. The phoneapp loads within salesforce it's possible on page load an agent might click on the launch phone button before clicking on anything within the saleforce UI... Salesforce OpenCTI unfortunately does not allow us to expose a CallCenter adaptor that is not loaded in an iframe first...

(1) ah... this is problematic would this apply also to the popout window that was open in a response to a click as well?

@taf2
Copy link
Author

taf2 commented Feb 17, 2024

If my understanding is correct with this new change there would be no way to have the child popout window signal to the parent iframe without having a user first interact by clicking on the salesforce.com interface and then clicking in the iframe and then clicking in the popout....

@arichiv
Copy link

arichiv commented Feb 17, 2024

Yes, interaction must happen in some top level frame on an origin, and then independent interaction must happen in the iframe for that same origin for requestStorageAccess to be callable.

It doesn't matter if you set cookies or not, the prompt only appears if third party cookies are off.

The other option is: https://developers.google.com/privacy-sandbox/3pcd/related-website-sets

@taf2
Copy link
Author

taf2 commented Feb 17, 2024

Anyway someone from salesforce.com is going to allow related website sets...

@taf2
Copy link
Author

taf2 commented Feb 18, 2024

@arichiv should we get an exception if we don't get access to the feature? I'm noticing I get a handle with what appears a valid handle.BroadcastChannel but it does not allow communication between my iframe and the popout window that my iframe opens. Does the popout window need to also request access or is it just the iframe? What is a good way of knowning when to directly use new BroadcastChannel vs requesting permission?

@arichiv
Copy link

arichiv commented Feb 18, 2024

Only the iframe needs to request and use the handle, if the same origin is loaded in a new window it can just use new BroadcastChannel. The request is for unpartitioned storage/communication in a third-party (cross site iframe) context.

@taf2
Copy link
Author

taf2 commented Feb 18, 2024

This does not appear to be working...

notworking.mp4

I don't get any exception which leads me to believe I'm initializing things correctly... but I also do not see any permissions dialog... I've verified my chrome://flags by both setting to default and "enabled".

@arichiv
Copy link

arichiv commented Feb 18, 2024

Are third-party cookies disabled in addition to the storage partitioning flag being on? Without that no permission will pop. https://developers.google.com/privacy-sandbox/3pcd/prepare/test-for-breakage

Also, I see that it tried to bind the channels on both sides but does it send a message? I didn't see a call to postMessage but that could just be happening elsewhere.

@taf2
Copy link
Author

taf2 commented Feb 18, 2024

Correct, we postMessage but onmessage handler never receives a message.

Am I understanding correctly,
Screenshot 2024-02-18 at 10 21 04 AM. would need to be enabled to see a permissions dialog? toggling that on now and testing i don't get a permissions dialog just the same behavior of no exceptions as if the broadcast channel correctly initialized but does not work postMessage is never received by the onmessage handler...

In the popout window and in the iframe:

Screenshot 2024-02-18 at 10 26 10 AM

I’m manually typing into the console got it wrong a few times typoed . But see in the top window pop out console window and then bottom console window I get the broadcasts channel and post message but not message appears in the top window

@arichiv
Copy link

arichiv commented Feb 18, 2024

I'd suggest building a much smaller demo in scope (you could copy and adapt https://saa-beyond-cookies.glitch.me to use BroadcastChannel) to verify first.

If you did this and shared it I could debug directly if it's not working, it's hard to tell exactly what's happening in your example.

@taf2
Copy link
Author

taf2 commented Feb 18, 2024

No that was just me typo in the console see the last part postMessage(“hi”)

the last 4 lines in the pop out window console logs and the single line in the iframe console bottom console…

I’ll do a simplified version

@taf2
Copy link
Author

taf2 commented Feb 19, 2024

Am I understanding correctly that unless I am able to get salesforce.com to indicate that calltrackingmetrics.com is related site or for that matter any application developer on salesforce.com would need to get salesforce.com to now associate the application developer via "Related Website Sets" json file pull request is required for

const handle = await document.requestStorageAccess({all: true});

to ever work?

At what point does disabling this feature via
chrome://flags/#third-party-storage-partitioning stop working?

@johannhof
Copy link
Member

@taf2 if they're not declared as related websites you should see a permission prompt instead, can you share the console output of the requestStorageAccess call?

(noting that if this becomes a longer debugging conversation we should probably take it to https://github.com/GoogleChromeLabs/privacy-sandbox-dev-support, this repo is for standards discussions)

@arichiv
Copy link

arichiv commented Feb 19, 2024

chrome://flags/#third-party-storage-partitioning goes away in M124, but the Deprecation trials and enterprise policies that can disable storage partitioning will continue existing for a few milestones after.

@arichiv
Copy link

arichiv commented Feb 19, 2024

I re-worked https://saa-beyond-cookies.glitch.me/ to use Broadcast Channel and it works as expected, prompt included.

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

No branches or pull requests

5 participants
@taf2 @arichiv @wanderview @johannhof and others