зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1536411 - StoragePrincipal - part 8 - SharedWorkers, r=Ehsan
Differential Revision: https://phabricator.services.mozilla.com/D25790 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
677630aa7c
Коммит
bba5a7d699
|
@ -465,13 +465,22 @@ already_AddRefed<BasePrincipal> BasePrincipal::CloneForcingFirstPartyDomain(
|
|||
// XXX this is slow. Maybe we should consider to make it faster.
|
||||
attrs.SetFirstPartyDomain(false, aURI, true /* aForced */);
|
||||
|
||||
return CloneForcingOriginAttributes(attrs);
|
||||
}
|
||||
|
||||
already_AddRefed<BasePrincipal> BasePrincipal::CloneForcingOriginAttributes(
|
||||
const OriginAttributes& aOriginAttributes) {
|
||||
if (NS_WARN_IF(!IsCodebasePrincipal())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoCString originNoSuffix;
|
||||
nsresult rv = GetOriginNoSuffix(originNoSuffix);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
nsIURI* uri = static_cast<ContentPrincipal*>(this)->mCodebase;
|
||||
RefPtr<ContentPrincipal> copy = new ContentPrincipal();
|
||||
rv = copy->Init(uri, attrs, originNoSuffix);
|
||||
rv = copy->Init(uri, aOriginAttributes, originNoSuffix);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
return copy.forget();
|
||||
|
|
|
@ -171,6 +171,9 @@ class BasePrincipal : public nsJSPrincipals {
|
|||
|
||||
already_AddRefed<BasePrincipal> CloneForcingFirstPartyDomain(nsIURI* aURI);
|
||||
|
||||
already_AddRefed<BasePrincipal> CloneForcingOriginAttributes(
|
||||
const OriginAttributes& aOriginAttributes);
|
||||
|
||||
// If this is an add-on content script principal, returns its AddonPolicy.
|
||||
// Otherwise returns null.
|
||||
extensions::WebExtensionPolicy* ContentScriptAddonPolicy();
|
||||
|
|
|
@ -151,13 +151,10 @@ nsresult WorkerLoadInfo::GetPrincipalsAndLoadGroupFromChannel(
|
|||
MOZ_DIAGNOSTIC_ASSERT(ssm);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> channelPrincipal;
|
||||
nsresult rv = ssm->GetChannelResultPrincipal(
|
||||
aChannel, getter_AddRefs(channelPrincipal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> channelStoragePrincipal;
|
||||
rv = ssm->GetChannelResultStoragePrincipal(
|
||||
aChannel, getter_AddRefs(channelStoragePrincipal));
|
||||
nsresult rv = ssm->GetChannelResultPrincipals(
|
||||
aChannel, getter_AddRefs(channelPrincipal),
|
||||
getter_AddRefs(channelStoragePrincipal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Every time we call GetChannelResultPrincipal() it will return a different
|
||||
|
|
|
@ -102,14 +102,14 @@ already_AddRefed<SharedWorker> SharedWorker::Constructor(
|
|||
do_QueryInterface(aGlobal.GetAsSupports());
|
||||
MOZ_ASSERT(window);
|
||||
|
||||
// If the window is blocked from accessing storage, do not allow it
|
||||
// to connect to a SharedWorker. This would potentially allow it
|
||||
// to communicate with other windows that do have storage access.
|
||||
// Allow private browsing, however, as we handle that isolation
|
||||
// via the principal.
|
||||
auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
|
||||
if (storageAllowed != nsContentUtils::StorageAccess::eAllow &&
|
||||
storageAllowed != nsContentUtils::StorageAccess::ePrivateBrowsing) {
|
||||
if (storageAllowed == nsContentUtils::StorageAccess::eDeny) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (storageAllowed == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
|
||||
!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -176,6 +176,37 @@ already_AddRefed<SharedWorker> SharedWorker::Constructor(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Here, the StoragePrincipal is always equal to the SharedWorker's principal
|
||||
// because the channel is not opened yet, and, because of this, it's not
|
||||
// classified. We need to force the correct originAttributes.
|
||||
if (storageAllowed == nsContentUtils::StorageAccess::ePartitionedOrDeny) {
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(window);
|
||||
if (!sop) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIPrincipal* windowPrincipal = sop->GetPrincipal();
|
||||
if (!windowPrincipal) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIPrincipal* windowStoragePrincipal = sop->GetEffectiveStoragePrincipal();
|
||||
if (!windowStoragePrincipal) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!windowPrincipal->Equals(windowStoragePrincipal)) {
|
||||
loadInfo.mStoragePrincipal =
|
||||
BasePrincipal::Cast(loadInfo.mPrincipal)
|
||||
->CloneForcingOriginAttributes(
|
||||
BasePrincipal::Cast(windowStoragePrincipal)
|
||||
->OriginAttributesRef());
|
||||
}
|
||||
}
|
||||
|
||||
PrincipalInfo storagePrincipalInfo;
|
||||
if (loadInfo.mPrincipal->Equals(loadInfo.mStoragePrincipal)) {
|
||||
storagePrincipalInfo = principalInfo;
|
||||
|
|
|
@ -22,11 +22,13 @@ namespace dom {
|
|||
// static
|
||||
already_AddRefed<SharedWorkerManagerHolder> SharedWorkerManager::Create(
|
||||
SharedWorkerService* aService, nsIEventTarget* aPBackgroundEventTarget,
|
||||
const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal) {
|
||||
const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal,
|
||||
const OriginAttributes& aStoragePrincipalAttrs) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<SharedWorkerManager> manager = new SharedWorkerManager(
|
||||
aPBackgroundEventTarget, aData, aLoadingPrincipal);
|
||||
RefPtr<SharedWorkerManager> manager =
|
||||
new SharedWorkerManager(aPBackgroundEventTarget, aData, aLoadingPrincipal,
|
||||
aStoragePrincipalAttrs);
|
||||
|
||||
RefPtr<SharedWorkerManagerHolder> holder =
|
||||
new SharedWorkerManagerHolder(manager, aService);
|
||||
|
@ -35,10 +37,12 @@ already_AddRefed<SharedWorkerManagerHolder> SharedWorkerManager::Create(
|
|||
|
||||
SharedWorkerManager::SharedWorkerManager(
|
||||
nsIEventTarget* aPBackgroundEventTarget, const RemoteWorkerData& aData,
|
||||
nsIPrincipal* aLoadingPrincipal)
|
||||
nsIPrincipal* aLoadingPrincipal,
|
||||
const OriginAttributes& aStoragePrincipalAttrs)
|
||||
: mPBackgroundEventTarget(aPBackgroundEventTarget),
|
||||
mLoadingPrincipal(aLoadingPrincipal),
|
||||
mDomain(aData.domain()),
|
||||
mStoragePrincipalAttrs(aStoragePrincipalAttrs),
|
||||
mResolvedScriptURL(DeserializeURI(aData.resolvedScriptURL())),
|
||||
mName(aData.name()),
|
||||
mIsSecureContext(aData.isSecureContext()),
|
||||
|
@ -80,11 +84,10 @@ bool SharedWorkerManager::MaybeCreateRemoteWorker(
|
|||
}
|
||||
|
||||
already_AddRefed<SharedWorkerManagerHolder>
|
||||
SharedWorkerManager::MatchOnMainThread(SharedWorkerService* aService,
|
||||
const nsACString& aDomain,
|
||||
nsIURI* aScriptURL,
|
||||
const nsAString& aName,
|
||||
nsIPrincipal* aLoadingPrincipal) {
|
||||
SharedWorkerManager::MatchOnMainThread(
|
||||
SharedWorkerService* aService, const nsACString& aDomain,
|
||||
nsIURI* aScriptURL, const nsAString& aName, nsIPrincipal* aLoadingPrincipal,
|
||||
const OriginAttributes& aStoragePrincipalAttrs) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
bool urlEquals;
|
||||
|
@ -96,7 +99,8 @@ SharedWorkerManager::MatchOnMainThread(SharedWorkerService* aService,
|
|||
// We want to be sure that the window's principal subsumes the
|
||||
// SharedWorker's loading principal and vice versa.
|
||||
mLoadingPrincipal->Subsumes(aLoadingPrincipal) &&
|
||||
aLoadingPrincipal->Subsumes(mLoadingPrincipal);
|
||||
aLoadingPrincipal->Subsumes(mLoadingPrincipal) &&
|
||||
mStoragePrincipalAttrs == aStoragePrincipalAttrs;
|
||||
if (!match) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -67,14 +67,16 @@ class SharedWorkerManager final : public RemoteWorkerObserver {
|
|||
|
||||
static already_AddRefed<SharedWorkerManagerHolder> Create(
|
||||
SharedWorkerService* aService, nsIEventTarget* aPBackgroundEventTarget,
|
||||
const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal);
|
||||
const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal,
|
||||
const OriginAttributes& aStoragePrincipalAttrs);
|
||||
|
||||
// Returns a holder if this manager matches. The holder blocks the shutdown of
|
||||
// the manager.
|
||||
already_AddRefed<SharedWorkerManagerHolder> MatchOnMainThread(
|
||||
SharedWorkerService* aService, const nsACString& aDomain,
|
||||
nsIURI* aScriptURL, const nsAString& aName,
|
||||
nsIPrincipal* aLoadingPrincipal);
|
||||
nsIPrincipal* aLoadingPrincipal,
|
||||
const OriginAttributes& aStoragePrincipalAttrs);
|
||||
|
||||
// RemoteWorkerObserver
|
||||
|
||||
|
@ -114,7 +116,8 @@ class SharedWorkerManager final : public RemoteWorkerObserver {
|
|||
private:
|
||||
SharedWorkerManager(nsIEventTarget* aPBackgroundEventTarget,
|
||||
const RemoteWorkerData& aData,
|
||||
nsIPrincipal* aLoadingPrincipal);
|
||||
nsIPrincipal* aLoadingPrincipal,
|
||||
const OriginAttributes& aStoragePrincipalAttrs);
|
||||
|
||||
~SharedWorkerManager();
|
||||
|
||||
|
@ -122,6 +125,7 @@ class SharedWorkerManager final : public RemoteWorkerObserver {
|
|||
|
||||
nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
|
||||
nsCString mDomain;
|
||||
OriginAttributes mStoragePrincipalAttrs;
|
||||
nsCOMPtr<nsIURI> mResolvedScriptURL;
|
||||
nsString mName;
|
||||
bool mIsSecureContext;
|
||||
|
|
|
@ -219,16 +219,9 @@ void SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(
|
|||
MOZ_ASSERT(aActor);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
PrincipalInfoToPrincipal(aData.principalInfo(), &rv);
|
||||
if (NS_WARN_IF(!principal)) {
|
||||
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
|
||||
return;
|
||||
}
|
||||
|
||||
rv = PopulatePrincipalContentSecurityPolicy(principal, aData.principalCsp(),
|
||||
aData.principalPreloadCsp());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
nsCOMPtr<nsIPrincipal> storagePrincipal =
|
||||
PrincipalInfoToPrincipal(aData.storagePrincipalInfo(), &rv);
|
||||
if (NS_WARN_IF(!storagePrincipal)) {
|
||||
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
|
||||
return;
|
||||
}
|
||||
|
@ -255,8 +248,8 @@ void SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(
|
|||
DeserializeURI(aData.resolvedScriptURL());
|
||||
for (SharedWorkerManager* workerManager : mWorkerManagers) {
|
||||
managerHolder = workerManager->MatchOnMainThread(
|
||||
this, aData.domain(), resolvedScriptURL, aData.name(),
|
||||
loadingPrincipal);
|
||||
this, aData.domain(), resolvedScriptURL, aData.name(), loadingPrincipal,
|
||||
BasePrincipal::Cast(storagePrincipal)->OriginAttributesRef());
|
||||
if (managerHolder) {
|
||||
break;
|
||||
}
|
||||
|
@ -264,8 +257,9 @@ void SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(
|
|||
|
||||
// Let's create a new one.
|
||||
if (!managerHolder) {
|
||||
managerHolder = SharedWorkerManager::Create(this, aBackgroundEventTarget,
|
||||
aData, loadingPrincipal);
|
||||
managerHolder = SharedWorkerManager::Create(
|
||||
this, aBackgroundEventTarget, aData, loadingPrincipal,
|
||||
BasePrincipal::Cast(storagePrincipal)->OriginAttributesRef());
|
||||
|
||||
mWorkerManagers.AppendElement(managerHolder->Manager());
|
||||
} else {
|
||||
|
|
|
@ -98,3 +98,5 @@ support-files = cookies.sjs
|
|||
[browser_partitionedDOMCache.js]
|
||||
[browser_partitionedServiceWorkers.js]
|
||||
support-files = matchAll.js
|
||||
[browser_partitionedSharedWorkers.js]
|
||||
support-files = sharedWorker.js
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/* import-globals-from storageprincipal_head.js */
|
||||
|
||||
StoragePrincipalHelper.runTest("SharedWorkers",
|
||||
async (win3rdParty, win1stParty, allowed) => {
|
||||
let sh1 = new win1stParty.SharedWorker("sharedWorker.js");
|
||||
await new Promise(resolve => {
|
||||
sh1.port.onmessage = e => {
|
||||
is(e.data, 1, "We expected 1 connection");
|
||||
resolve();
|
||||
};
|
||||
sh1.port.postMessage("count");
|
||||
});
|
||||
|
||||
let sh3 = new win3rdParty.SharedWorker("sharedWorker.js");
|
||||
await new Promise(resolve => {
|
||||
sh3.port.onmessage = e => {
|
||||
ok(!allowed, "We should be here only if the SharedWorker is partitioned");
|
||||
is(e.data, 1, "We expected 1 connection for 3rd party SharedWorker");
|
||||
resolve();
|
||||
};
|
||||
sh3.onerror = _ => {
|
||||
ok(allowed, "We should be here only if the SharedWorker is not partitioned");
|
||||
resolve();
|
||||
};
|
||||
sh3.port.postMessage("count");
|
||||
});
|
||||
|
||||
sh1.port.postMessage("close");
|
||||
sh3.port.postMessage("close");
|
||||
},
|
||||
|
||||
async _ => {
|
||||
await new Promise(resolve => {
|
||||
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
|
||||
});
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
let ports = 0;
|
||||
self.onconnect = e => {
|
||||
++ports;
|
||||
e.ports[0].onmessage = event => {
|
||||
if (event.data === "count") {
|
||||
e.ports[0].postMessage(ports);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data === "close") {
|
||||
self.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// Error.
|
||||
e.ports[0].postMessage(-1);
|
||||
};
|
||||
};
|
Загрузка…
Ссылка в новой задаче