mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 1453916 - Allow canvas extraction from webextension content-script even with resistFingerprinting turned on. r=kmag,bz
--HG-- extra : rebase_source : d67c589e8819407bb5acc4378d029288dd9295be
This commit is contained in:
parent
98fa42844c
commit
937d9326cd
@ -461,6 +461,23 @@ BasePrincipal::CloneStrippingUserContextIdAndFirstPartyDomain()
|
||||
return BasePrincipal::CreateCodebasePrincipal(uri, attrs);
|
||||
}
|
||||
|
||||
extensions::WebExtensionPolicy*
|
||||
BasePrincipal::ContentScriptAddonPolicy()
|
||||
{
|
||||
if (!Is<ExpandedPrincipal>()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto expanded = As<ExpandedPrincipal>();
|
||||
for (auto& prin : expanded->WhiteList()) {
|
||||
if (auto policy = BasePrincipal::Cast(prin)->AddonPolicy()) {
|
||||
return policy;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
BasePrincipal::AddonAllowsLoad(nsIURI* aURI, bool aExplicit /* = false */)
|
||||
{
|
||||
|
@ -113,6 +113,10 @@ public:
|
||||
|
||||
already_AddRefed<BasePrincipal> CloneStrippingUserContextIdAndFirstPartyDomain();
|
||||
|
||||
// If this is an add-on content script principal, returns its AddonPolicy.
|
||||
// Otherwise returns null.
|
||||
extensions::WebExtensionPolicy* ContentScriptAddonPolicy();
|
||||
|
||||
// Helper to check whether this principal is associated with an addon that
|
||||
// allows unprivileged code to load aURI. aExplicit == true will prevent
|
||||
// use of all_urls permission, requiring the domain in its permissions.
|
||||
|
@ -4665,7 +4665,9 @@ CanvasRenderingContext2D::LineDashOffset() const {
|
||||
}
|
||||
|
||||
bool
|
||||
CanvasRenderingContext2D::IsPointInPath(JSContext* aCx, double aX, double aY, const CanvasWindingRule& aWinding)
|
||||
CanvasRenderingContext2D::IsPointInPath(JSContext* aCx, double aX, double aY,
|
||||
const CanvasWindingRule& aWinding,
|
||||
nsIPrincipal& aSubjectPrincipal)
|
||||
{
|
||||
if (!FloatValidate(aX, aY)) {
|
||||
return false;
|
||||
@ -4674,7 +4676,7 @@ CanvasRenderingContext2D::IsPointInPath(JSContext* aCx, double aX, double aY, co
|
||||
// Check for site-specific permission and return false if no permission.
|
||||
if (mCanvasElement) {
|
||||
nsCOMPtr<nsIDocument> ownerDoc = mCanvasElement->OwnerDoc();
|
||||
if (!CanvasUtils::IsImageExtractionAllowed(ownerDoc, aCx)) {
|
||||
if (!CanvasUtils::IsImageExtractionAllowed(ownerDoc, aCx, aSubjectPrincipal)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -4691,7 +4693,11 @@ CanvasRenderingContext2D::IsPointInPath(JSContext* aCx, double aX, double aY, co
|
||||
return mPath->ContainsPoint(Point(aX, aY), mTarget->GetTransform());
|
||||
}
|
||||
|
||||
bool CanvasRenderingContext2D::IsPointInPath(JSContext* aCx, const CanvasPath& aPath, double aX, double aY, const CanvasWindingRule& aWinding)
|
||||
bool
|
||||
CanvasRenderingContext2D::IsPointInPath(JSContext* aCx, const CanvasPath& aPath,
|
||||
double aX, double aY,
|
||||
const CanvasWindingRule& aWinding,
|
||||
nsIPrincipal&)
|
||||
{
|
||||
if (!FloatValidate(aX, aY)) {
|
||||
return false;
|
||||
@ -4708,7 +4714,8 @@ bool CanvasRenderingContext2D::IsPointInPath(JSContext* aCx, const CanvasPath& a
|
||||
}
|
||||
|
||||
bool
|
||||
CanvasRenderingContext2D::IsPointInStroke(JSContext* aCx, double aX, double aY)
|
||||
CanvasRenderingContext2D::IsPointInStroke(JSContext* aCx, double aX, double aY,
|
||||
nsIPrincipal& aSubjectPrincipal)
|
||||
{
|
||||
if (!FloatValidate(aX, aY)) {
|
||||
return false;
|
||||
@ -4717,7 +4724,7 @@ CanvasRenderingContext2D::IsPointInStroke(JSContext* aCx, double aX, double aY)
|
||||
// Check for site-specific permission and return false if no permission.
|
||||
if (mCanvasElement) {
|
||||
nsCOMPtr<nsIDocument> ownerDoc = mCanvasElement->OwnerDoc();
|
||||
if (!CanvasUtils::IsImageExtractionAllowed(ownerDoc, aCx)) {
|
||||
if (!CanvasUtils::IsImageExtractionAllowed(ownerDoc, aCx, aSubjectPrincipal)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -4743,7 +4750,9 @@ CanvasRenderingContext2D::IsPointInStroke(JSContext* aCx, double aX, double aY)
|
||||
return mPath->StrokeContainsPoint(strokeOptions, Point(aX, aY), mTarget->GetTransform());
|
||||
}
|
||||
|
||||
bool CanvasRenderingContext2D::IsPointInStroke(JSContext* aCx, const CanvasPath& aPath, double aX, double aY)
|
||||
bool
|
||||
CanvasRenderingContext2D::IsPointInStroke(JSContext* aCx, const CanvasPath& aPath,
|
||||
double aX, double aY, nsIPrincipal&)
|
||||
{
|
||||
if (!FloatValidate(aX, aY)) {
|
||||
return false;
|
||||
@ -5435,8 +5444,9 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindowInner& aWindow, double aX,
|
||||
|
||||
already_AddRefed<ImageData>
|
||||
CanvasRenderingContext2D::GetImageData(JSContext* aCx, double aSx,
|
||||
double aSy, double aSw,
|
||||
double aSh, ErrorResult& aError)
|
||||
double aSy, double aSw, double aSh,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
if (mDrawObserver) {
|
||||
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::GetImageData);
|
||||
@ -5502,7 +5512,7 @@ CanvasRenderingContext2D::GetImageData(JSContext* aCx, double aSx,
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> array(aCx);
|
||||
aError = GetImageDataArray(aCx, x, y, w, h, array.address());
|
||||
aError = GetImageDataArray(aCx, x, y, w, h, aSubjectPrincipal, array.address());
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -5518,6 +5528,7 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
|
||||
int32_t aY,
|
||||
uint32_t aWidth,
|
||||
uint32_t aHeight,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
JSObject** aRetval)
|
||||
{
|
||||
if (mDrawObserver) {
|
||||
@ -5590,7 +5601,7 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
|
||||
bool usePlaceholder = false;
|
||||
if (mCanvasElement) {
|
||||
nsCOMPtr<nsIDocument> ownerDoc = mCanvasElement->OwnerDoc();
|
||||
usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(ownerDoc, aCx);
|
||||
usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(ownerDoc, aCx, aSubjectPrincipal);
|
||||
}
|
||||
|
||||
do {
|
||||
|
@ -203,10 +203,16 @@ public:
|
||||
bool DrawCustomFocusRing(mozilla::dom::Element& aElement);
|
||||
void Clip(const CanvasWindingRule& aWinding);
|
||||
void Clip(const CanvasPath& aPath, const CanvasWindingRule& aWinding);
|
||||
bool IsPointInPath(JSContext* aCx, double aX, double aY, const CanvasWindingRule& aWinding);
|
||||
bool IsPointInPath(JSContext* aCx, const CanvasPath& aPath, double aX, double aY, const CanvasWindingRule& aWinding);
|
||||
bool IsPointInStroke(JSContext* aCx, double aX, double aY);
|
||||
bool IsPointInStroke(JSContext* aCx, const CanvasPath& aPath, double aX, double aY);
|
||||
bool IsPointInPath(JSContext* aCx, double aX, double aY,
|
||||
const CanvasWindingRule& aWinding,
|
||||
nsIPrincipal& aSubjectPrincipal);
|
||||
bool IsPointInPath(JSContext* aCx, const CanvasPath& aPath,
|
||||
double aX, double aY,
|
||||
const CanvasWindingRule& aWinding, nsIPrincipal&);
|
||||
bool IsPointInStroke(JSContext* aCx, double aX, double aY,
|
||||
nsIPrincipal& aSubjectPrincipal);
|
||||
bool IsPointInStroke(JSContext* aCx, const CanvasPath& aPath,
|
||||
double aX, double aY, nsIPrincipal&);
|
||||
void FillText(const nsAString& aText, double aX, double aY,
|
||||
const Optional<double>& aMaxWidth,
|
||||
mozilla::ErrorResult& aError);
|
||||
@ -248,7 +254,7 @@ public:
|
||||
mozilla::ErrorResult& aError);
|
||||
already_AddRefed<ImageData>
|
||||
GetImageData(JSContext* aCx, double aSx, double aSy, double aSw, double aSh,
|
||||
mozilla::ErrorResult& aError);
|
||||
nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError);
|
||||
void PutImageData(ImageData& aImageData,
|
||||
double aDx, double aDy, mozilla::ErrorResult& aError);
|
||||
void PutImageData(ImageData& aImageData,
|
||||
@ -559,6 +565,7 @@ public:
|
||||
protected:
|
||||
nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
|
||||
uint32_t aWidth, uint32_t aHeight,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
JSObject** aRetval);
|
||||
|
||||
nsresult PutImageData_explicit(int32_t aX, int32_t aY, uint32_t aW, uint32_t aH,
|
||||
|
@ -43,7 +43,7 @@ using namespace mozilla::gfx;
|
||||
namespace mozilla {
|
||||
namespace CanvasUtils {
|
||||
|
||||
bool IsImageExtractionAllowed(nsIDocument *aDocument, JSContext *aCx)
|
||||
bool IsImageExtractionAllowed(nsIDocument *aDocument, JSContext *aCx, nsIPrincipal& aPrincipal)
|
||||
{
|
||||
// Do the rest of the checks only if privacy.resistFingerprinting is on.
|
||||
if (!nsContentUtils::ShouldResistFingerprinting()) {
|
||||
@ -58,25 +58,14 @@ bool IsImageExtractionAllowed(nsIDocument *aDocument, JSContext *aCx)
|
||||
nsPIDOMWindowOuter *win = aDocument->GetWindow();
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(win));
|
||||
|
||||
if (sop) {
|
||||
// Documents with system principal can always extract canvas data.
|
||||
nsIPrincipal *principal = sop->GetPrincipal();
|
||||
if (nsContentUtils::IsSystemPrincipal(principal)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (principal) {
|
||||
// Allow extension principals
|
||||
nsAutoString addonId;
|
||||
Unused << NS_WARN_IF(NS_FAILED(principal->GetAddonId(addonId)));
|
||||
if (!addonId.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// The system principal can always extract canvas data.
|
||||
if (nsContentUtils::IsSystemPrincipal(&aPrincipal)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Always give permission to chrome scripts (e.g. Page Inspector).
|
||||
if (nsContentUtils::ThreadsafeIsCallerChrome()) {
|
||||
// Allow extension principals.
|
||||
auto principal = BasePrincipal::Cast(&aPrincipal);
|
||||
if (principal->AddonPolicy() || principal->ContentScriptAddonPolicy()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ void DoDrawImageSecurityCheck(dom::HTMLCanvasElement *aCanvasElement,
|
||||
bool HasDrawWindowPrivilege(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
// Check site-specific permission and display prompt if appropriate.
|
||||
bool IsImageExtractionAllowed(nsIDocument *aDocument, JSContext *aCx);
|
||||
bool IsImageExtractionAllowed(nsIDocument *aDocument, JSContext *aCx, nsIPrincipal& aPrincipal);
|
||||
|
||||
// Make a double out of |v|, treating undefined values as 0.0 (for
|
||||
// the sake of sparse arrays). Return true iff coercion
|
||||
|
@ -670,6 +670,7 @@ void
|
||||
HTMLCanvasElement::ToDataURL(JSContext* aCx, const nsAString& aType,
|
||||
JS::Handle<JS::Value> aParams,
|
||||
nsAString& aDataURL,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
// do a trust check if this is a write-only canvas
|
||||
@ -679,7 +680,7 @@ HTMLCanvasElement::ToDataURL(JSContext* aCx, const nsAString& aType,
|
||||
return;
|
||||
}
|
||||
|
||||
aRv = ToDataURLImpl(aCx, aType, aParams, aDataURL);
|
||||
aRv = ToDataURLImpl(aCx, aSubjectPrincipal, aType, aParams, aDataURL);
|
||||
}
|
||||
|
||||
void
|
||||
@ -750,6 +751,7 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(CanvasCaptureTrackSource,
|
||||
|
||||
already_AddRefed<CanvasCaptureMediaStream>
|
||||
HTMLCanvasElement::CaptureStream(const Optional<double>& aFrameRate,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (IsWriteOnly()) {
|
||||
@ -794,7 +796,8 @@ HTMLCanvasElement::CaptureStream(const Optional<double>& aFrameRate,
|
||||
// all-white, opaque image data.
|
||||
bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(
|
||||
OwnerDoc(),
|
||||
nsContentUtils::GetCurrentJSContext());
|
||||
nsContentUtils::GetCurrentJSContext(),
|
||||
aSubjectPrincipal);
|
||||
|
||||
rv = RegisterFrameCaptureListener(stream->FrameCaptureListener(), usePlaceholder);
|
||||
if (NS_FAILED(rv)) {
|
||||
@ -807,13 +810,15 @@ HTMLCanvasElement::CaptureStream(const Optional<double>& aFrameRate,
|
||||
|
||||
nsresult
|
||||
HTMLCanvasElement::ExtractData(JSContext* aCx,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
nsIInputStream** aStream)
|
||||
{
|
||||
// Check site-specific permission and display prompt if appropriate.
|
||||
// If no permission, return all-white, opaque image data.
|
||||
bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(OwnerDoc(), aCx);
|
||||
bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(
|
||||
OwnerDoc(), aCx, aSubjectPrincipal);
|
||||
return ImageEncoder::ExtractData(aType,
|
||||
aOptions,
|
||||
GetSize(),
|
||||
@ -825,6 +830,7 @@ HTMLCanvasElement::ExtractData(JSContext* aCx,
|
||||
|
||||
nsresult
|
||||
HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
const nsAString& aMimeType,
|
||||
const JS::Value& aEncoderOptions,
|
||||
nsAString& aDataURL)
|
||||
@ -847,12 +853,14 @@ HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
rv = ExtractData(aCx, type, params, getter_AddRefs(stream));
|
||||
rv = ExtractData(aCx, aSubjectPrincipal, type, params,
|
||||
getter_AddRefs(stream));
|
||||
|
||||
// If there are unrecognized custom parse options, we should fall back to
|
||||
// the default values for the encoder without any options at all.
|
||||
if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
|
||||
rv = ExtractData(aCx, type, EmptyString(), getter_AddRefs(stream));
|
||||
rv = ExtractData(aCx, aSubjectPrincipal, type, EmptyString(),
|
||||
getter_AddRefs(stream));
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -873,6 +881,7 @@ HTMLCanvasElement::ToBlob(JSContext* aCx,
|
||||
BlobCallback& aCallback,
|
||||
const nsAString& aType,
|
||||
JS::Handle<JS::Value> aParams,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
// do a trust check if this is a write-only canvas
|
||||
@ -904,7 +913,8 @@ HTMLCanvasElement::ToBlob(JSContext* aCx,
|
||||
|
||||
// Check site-specific permission and display prompt if appropriate.
|
||||
// If no permission, return all-white, opaque image data.
|
||||
bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(OwnerDoc(), aCx);
|
||||
bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(
|
||||
OwnerDoc(), aCx, aSubjectPrincipal);
|
||||
CanvasRenderingContextHelper::ToBlob(aCx, global, aCallback, aType,
|
||||
aParams, usePlaceholder, aRv);
|
||||
|
||||
@ -952,20 +962,20 @@ HTMLCanvasElement::TransferControlToOffscreen(ErrorResult& aRv)
|
||||
already_AddRefed<File>
|
||||
HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
|
||||
const nsAString& aType,
|
||||
CallerType aCallerType,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
OwnerDoc()->WarnOnceAbout(nsIDocument::eMozGetAsFile);
|
||||
|
||||
// do a trust check if this is a write-only canvas
|
||||
if (mWriteOnly && aCallerType != CallerType::System) {
|
||||
if (mWriteOnly && !nsContentUtils::IsSystemPrincipal(&aSubjectPrincipal)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
RefPtr<File> file;
|
||||
aRv = MozGetAsFileImpl(aName, aType, getter_AddRefs(file));
|
||||
aRv = MozGetAsFileImpl(aName, aType, aSubjectPrincipal, getter_AddRefs(file));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -975,12 +985,14 @@ HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
|
||||
nsresult
|
||||
HTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
|
||||
const nsAString& aType,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
File** aResult)
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsAutoString type(aType);
|
||||
nsresult rv = ExtractData(nsContentUtils::GetCurrentJSContext(),
|
||||
type, EmptyString(), getter_AddRefs(stream));
|
||||
aSubjectPrincipal, type, EmptyString(),
|
||||
getter_AddRefs(stream));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint64_t imgSize;
|
||||
|
@ -178,12 +178,14 @@ public:
|
||||
void ToDataURL(JSContext* aCx, const nsAString& aType,
|
||||
JS::Handle<JS::Value> aParams,
|
||||
nsAString& aDataURL,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void ToBlob(JSContext* aCx,
|
||||
BlobCallback& aCallback,
|
||||
const nsAString& aType,
|
||||
JS::Handle<JS::Value> aParams,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv);
|
||||
|
||||
OffscreenCanvas* TransferControlToOffscreen(ErrorResult& aRv);
|
||||
@ -203,7 +205,7 @@ public:
|
||||
}
|
||||
already_AddRefed<File> MozGetAsFile(const nsAString& aName,
|
||||
const nsAString& aType,
|
||||
CallerType aCallerType,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv);
|
||||
already_AddRefed<nsISupports> MozGetIPCContext(const nsAString& aContextId,
|
||||
ErrorResult& aRv);
|
||||
@ -211,7 +213,7 @@ public:
|
||||
void SetMozPrintCallback(PrintCallback* aCallback);
|
||||
|
||||
already_AddRefed<CanvasCaptureMediaStream>
|
||||
CaptureStream(const Optional<double>& aFrameRate, ErrorResult& aRv);
|
||||
CaptureStream(const Optional<double>& aFrameRate, nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv);
|
||||
|
||||
/**
|
||||
* Get the size in pixels of this canvas element
|
||||
@ -354,15 +356,18 @@ protected:
|
||||
CreateContext(CanvasContextType aContextType) override;
|
||||
|
||||
nsresult ExtractData(JSContext* aCx,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
nsIInputStream** aStream);
|
||||
nsresult ToDataURLImpl(JSContext* aCx,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
const nsAString& aMimeType,
|
||||
const JS::Value& aEncoderOptions,
|
||||
nsAString& aDataURL);
|
||||
nsresult MozGetAsFileImpl(const nsAString& aName,
|
||||
const nsAString& aType,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
File** aResult);
|
||||
void CallPrintCallback();
|
||||
|
||||
|
@ -230,9 +230,13 @@ interface CanvasDrawPath {
|
||||
void clip(optional CanvasWindingRule winding = "nonzero");
|
||||
void clip(Path2D path, optional CanvasWindingRule winding = "nonzero");
|
||||
// NOT IMPLEMENTED void resetClip();
|
||||
[NeedsSubjectPrincipal]
|
||||
boolean isPointInPath(unrestricted double x, unrestricted double y, optional CanvasWindingRule winding = "nonzero");
|
||||
[NeedsSubjectPrincipal] // Only required because overloads can't have different extended attributes.
|
||||
boolean isPointInPath(Path2D path, unrestricted double x, unrestricted double y, optional CanvasWindingRule winding = "nonzero");
|
||||
[NeedsSubjectPrincipal]
|
||||
boolean isPointInStroke(double x, double y);
|
||||
[NeedsSubjectPrincipal] // Only required because overloads can't have different extended attributes.
|
||||
boolean isPointInStroke(Path2D path, unrestricted double x, unrestricted double y);
|
||||
};
|
||||
|
||||
@ -274,7 +278,7 @@ interface CanvasImageData {
|
||||
ImageData createImageData(double sw, double sh);
|
||||
[NewObject, Throws]
|
||||
ImageData createImageData(ImageData imagedata);
|
||||
[NewObject, Throws]
|
||||
[NewObject, Throws, NeedsSubjectPrincipal]
|
||||
ImageData getImageData(double sx, double sy, double sw, double sh);
|
||||
[Throws]
|
||||
void putImageData(ImageData imagedata, double dx, double dy);
|
||||
|
@ -23,10 +23,10 @@ interface HTMLCanvasElement : HTMLElement {
|
||||
[Throws]
|
||||
nsISupports? getContext(DOMString contextId, optional any contextOptions = null);
|
||||
|
||||
[Throws]
|
||||
[Throws, NeedsSubjectPrincipal]
|
||||
DOMString toDataURL(optional DOMString type = "",
|
||||
optional any encoderOptions);
|
||||
[Throws]
|
||||
[Throws, NeedsSubjectPrincipal]
|
||||
void toBlob(BlobCallback _callback,
|
||||
optional DOMString type = "",
|
||||
optional any encoderOptions);
|
||||
@ -36,7 +36,7 @@ interface HTMLCanvasElement : HTMLElement {
|
||||
partial interface HTMLCanvasElement {
|
||||
[Pure, SetterThrows]
|
||||
attribute boolean mozOpaque;
|
||||
[Throws, NeedsCallerType]
|
||||
[Throws, NeedsSubjectPrincipal]
|
||||
File mozGetAsFile(DOMString name, optional DOMString? type = null);
|
||||
// A Mozilla-only extension to get a canvas context backed by double-buffered
|
||||
// shared memory. Only privileged callers can call this.
|
||||
@ -45,7 +45,7 @@ partial interface HTMLCanvasElement {
|
||||
|
||||
attribute PrintCallback? mozPrintCallback;
|
||||
|
||||
[Throws, Pref="canvas.capturestream.enabled"]
|
||||
[Throws, Pref="canvas.capturestream.enabled", NeedsSubjectPrincipal]
|
||||
CanvasCaptureMediaStream captureStream(optional double frameRate);
|
||||
};
|
||||
|
||||
|
@ -569,34 +569,6 @@ XPCJSContext::ActivityCallback(void* arg, bool active)
|
||||
self->mWatchdogManager->RecordContextActivity(self, active);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsWebExtensionPrincipal(nsIPrincipal* principal, nsAString& addonId)
|
||||
{
|
||||
if (auto policy = BasePrincipal::Cast(principal)->AddonPolicy()) {
|
||||
policy->GetId(addonId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsWebExtensionContentScript(BasePrincipal* principal, nsAString& addonId)
|
||||
{
|
||||
if (!principal->Is<ExpandedPrincipal>()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto expanded = principal->As<ExpandedPrincipal>();
|
||||
|
||||
for (auto& prin : expanded->WhiteList()) {
|
||||
if (IsWebExtensionPrincipal(prin, addonId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
XPCJSContext::InterruptCallback(JSContext* cx)
|
||||
@ -636,7 +608,8 @@ XPCJSContext::InterruptCallback(JSContext* cx)
|
||||
if (chrome) {
|
||||
prefName = PREF_MAX_SCRIPT_RUN_TIME_CHROME;
|
||||
limit = Preferences::GetInt(prefName, 20);
|
||||
} else if (IsWebExtensionContentScript(principal, addonId)) {
|
||||
} else if (auto policy = principal->ContentScriptAddonPolicy()) {
|
||||
policy->GetId(addonId);
|
||||
prefName = PREF_MAX_SCRIPT_RUN_TIME_EXT_CONTENT;
|
||||
limit = Preferences::GetInt(prefName, 5);
|
||||
} else {
|
||||
|
@ -339,8 +339,7 @@ PrincipalImmuneToScriptPolicy(nsIPrincipal* aPrincipal)
|
||||
}
|
||||
|
||||
// WebExtension principals get a free pass.
|
||||
nsString addonId;
|
||||
if (IsWebExtensionPrincipal(principal, addonId)) {
|
||||
if (principal->AddonPolicy()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,7 @@ prefs =
|
||||
[test_ext_background_canvas.html]
|
||||
[test_ext_background_page.html]
|
||||
skip-if = (toolkit == 'android') # android doesn't have devtools
|
||||
[test_ext_canvas_resistFingerprinting.html]
|
||||
[test_ext_clipboard.html]
|
||||
[test_ext_clipboard_image.html]
|
||||
skip-if = headless # disabled test case with_permission_allow_copy, see inline comment. Headless: Bug 1405872
|
||||
|
@ -0,0 +1,65 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/AddTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<script type="text/javascript" src="head_cookies.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.resistFingerprinting", true]],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_contentscript() {
|
||||
function contentScript() {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = canvas.height = "100";
|
||||
|
||||
var ctx = canvas.getContext("2d");
|
||||
ctx.fillStyle = 'green';
|
||||
ctx.fillRect(0, 0, 100, 100);
|
||||
var data = ctx.getImageData(0, 0, 100, 100);
|
||||
|
||||
browser.test.sendMessage("data-color", data.data[1]);
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
content_scripts: [
|
||||
{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_start",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
files: {
|
||||
"content_script.js": contentScript,
|
||||
},
|
||||
};
|
||||
const url = "http://mochi.test:8888/chrome/toolkit/components/extensions/test/mochitest/file_sample.html";
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
|
||||
await extension.startup();
|
||||
let win = window.open(url);
|
||||
let color = await extension.awaitMessage("data-color");
|
||||
is(color, 128, "Got correct pixel data for green");
|
||||
win.close();
|
||||
await extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user