Open Bug 1422862 Opened 6 years ago Updated 4 days ago

Make OffscreenCanvas respect Canvas Permission Prompt

Categories

(Core :: Graphics: Canvas2D, enhancement, P3)

enhancement

Tracking

()

Tracking Status
firefox59 --- affected

People

(Reporter: tjr, Unassigned)

References

(Blocks 1 open bug)

Details

(Whiteboard: [fingerprinting][gfx-noted][fp-triaged][fpp:m8])

We have a permission prompt for Canvas we added in Bug 967895.  Some light testing indicates that OffscreenCanvas does not trigger the prompt.
Whiteboard: [fingerprinting] → [fingerprinting][gfx-noted]
Here is a page to reproduce this issue, https://lyuyuan92.github.io/test_canvas_on_and_off_screen.html
With gfx.offscreencanvas.enabled and privacy.resistFingerprinting set to True, Firefox allows OffscreenCanvas API call without prompting the user.
Whiteboard: [fingerprinting][gfx-noted] → [fingerprinting][gfx-noted][fp-triaged]

This test case works with my latest patches (in flight on autoland still) but there is no permissions prompt still.

If I understand this correctly, should the prompt only show when the raw pixels are exposed to JavaScript? I presume that is why copyOne triggers the prompt, because this line pulls out the data:

https://github.com/0x00A5/lyuyuan92.github.io/blob/master/test_canvas_on_and_off_screen.html#L30

but createTwo moves it around via an ImageBitmap, it doesn't:

https://github.com/0x00A5/lyuyuan92.github.io/blob/master/test_canvas_on_and_off_screen.html#L40-L41

I would only expect the prompt to be generated for Canvas2D.getImageData and HTMLCanvasElement.toDataURL (maybe HTMLCanvasElement.toBlob?). So it doesn't seem like there is actually a problem here....

Yes, this sounds like we misunderstood the feature when we initially filed this bug (so as not to forget about it.) If there is no way for an OffscreenCanvas to actually give its rendered content via an API (like there is for canvas through e.g. toDataURL), and all it can do it stick it into a canvas (where permission prompts work) or another object that can't be read via Javascript (like an <img> tag) - then we are fine here.

Flags: needinfo?(aosmond)
Severity: normal → S3

If there is no way for an OffscreenCanvas to actually give its rendered content via an API (like there is for canvas through e.g. toDataURL),

There are ways to get the rendered content out of the OffscreenCanvas, e.g. convertToBlob() or transferToImageBitmap().

It seems like we currently check ShouldResistFingerprinting(RFPTarget::CanvasImageExtractionPrompt) in OffscreenCanvas::ConvertToBlob, but there doesn't seem to be any way to actually show a prompt. (Which might be tricky to do, I guess, because OffscreenCanvas can run on a Worker thread) So to me it seems like we will always get a placeholder image when using this API.

Flags: needinfo?(tihuang)

So transferToImageBitmap gives you an ImageBitmap, and I get the impression from MDN that the only useful thing you can do with that is put it into a canvas. (Which will lead to the normal canvas extraction paths.) I guess you can measure the width and height, which could leak data - except maybe these values are fixed to the initial size you specify when you create the OffscreenCanvas...?

convertToBlog gives you a Blob, which I see does have e.g. arrayBuffer() which will let you see the actual contents. That's definitely a problem. You're right - we don't do any permission checking here so you're always getting a placeholder.

OffscreenCanvas has a GlobalObject associated with it when its created, so it seems like we ought to be able to call IsImageExtractionAllowed?

OffscreenCanvas has a GlobalObject associated with it when its created, so it seems like we ought to be able to call IsImageExtractionAllowed?

The current code in IsImageExtractionAllowed is unlikely to work without changes in a Worker context. It seems to require a Document and I think not all Workers are associated with a document (but I keep forgetting why, maybe SharedWorker or ServiceWorkers?). We would probably also need to dispatch the call to the main thread.

We might be able to trigger the canvas prompt from the worker context. If the canvas prompt is requested from a content process, it sends an IPC message to the parent process via the browserChild. So, if we can access the browserChild in the worker context, we can use it to show the prompt.

The workerLoadInfo maintains a browserChild list, so we probably can use an active browserChild to request canvas prompt. However, this might not work for service workers because it could run without any opened tab for its origin. In this case, we can only check the canvas permission.

Flags: needinfo?(tihuang)

Hey,

my investigation in Element (the 'official' Matrix client) yielded finding this bug, so I'd add its issue link here, in hopes of this getting a bit more priority:

https://github.com/element-hq/element-web/issues/23936

Tom, you were just in this code, it seems like it might be an easy fix?

Flags: needinfo?(aosmond) → needinfo?(tschuster)
Whiteboard: [fingerprinting][gfx-noted][fp-triaged] → [fingerprinting][gfx-noted][fp-triaged][fpp:m8]

I don't think this is easy per se. While can use the BrowserChild to prompt for canvas extraction permission, we actually need to use nsIPermissionManager to query for it. That interface does not look thread-safe.

Flags: needinfo?(tschuster)
You need to log in before you can comment on or make changes to this bug.