summaryrefslogtreecommitdiffstats
path: root/remote/webdriver-bidi
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--remote/webdriver-bidi/modules/root/browsingContext.sys.mjs24
-rw-r--r--remote/webdriver-bidi/modules/root/network.sys.mjs81
-rw-r--r--remote/webdriver-bidi/modules/root/session.sys.mjs37
-rw-r--r--remote/webdriver-bidi/modules/root/storage.sys.mjs129
-rw-r--r--remote/webdriver-bidi/modules/windowglobal/browsingContext.sys.mjs14
5 files changed, 196 insertions, 89 deletions
diff --git a/remote/webdriver-bidi/modules/root/browsingContext.sys.mjs b/remote/webdriver-bidi/modules/root/browsingContext.sys.mjs
index f2a5d5e645..8424bebf4a 100644
--- a/remote/webdriver-bidi/modules/root/browsingContext.sys.mjs
+++ b/remote/webdriver-bidi/modules/root/browsingContext.sys.mjs
@@ -22,7 +22,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
"chrome://remote/content/shared/NavigationManager.sys.mjs",
NavigationListener:
"chrome://remote/content/shared/listeners/NavigationListener.sys.mjs",
- OwnershipModel: "chrome://remote/content/webdriver-bidi/RemoteValue.sys.mjs",
PollPromise: "chrome://remote/content/shared/Sync.sys.mjs",
pprint: "chrome://remote/content/shared/Format.sys.mjs",
print: "chrome://remote/content/shared/PDF.sys.mjs",
@@ -857,12 +856,6 @@ class BrowsingContextModule extends Module {
* @param {number=} options.maxNodeCount
* The maximum amount of nodes which is going to be returned.
* Defaults to return all the found nodes.
- * @param {OwnershipModel=} options.ownership
- * The ownership model to use for the serialization
- * of the DOM nodes. Defaults to `OwnershipModel.None`.
- * @property {string=} sandbox
- * The name of the sandbox. If the value is null or empty
- * string, the default realm will be used.
* @property {SerializationOptions=} serializationOptions
* An object which holds the information of how the DOM nodes
* should be serialized.
@@ -884,8 +877,6 @@ class BrowsingContextModule extends Module {
context: contextId,
locator,
maxNodeCount = null,
- ownership = lazy.OwnershipModel.None,
- sandbox = null,
serializationOptions,
startNodes = null,
} = options;
@@ -923,19 +914,6 @@ class BrowsingContextModule extends Module {
}, maxNodeCountErrorMsg)(maxNodeCount);
}
- const ownershipTypes = Object.values(lazy.OwnershipModel);
- lazy.assert.that(
- ownership => ownershipTypes.includes(ownership),
- `Expected "ownership" to be one of ${ownershipTypes}, got ${ownership}`
- )(ownership);
-
- if (sandbox != null) {
- lazy.assert.string(
- sandbox,
- `Expected "sandbox" to be a string, got ${sandbox}`
- );
- }
-
const serializationOptionsWithDefaults =
lazy.setDefaultAndAssertSerializationOptions(serializationOptions);
@@ -961,8 +939,6 @@ class BrowsingContextModule extends Module {
params: {
locator,
maxNodeCount,
- resultOwnership: ownership,
- sandbox,
serializationOptions: serializationOptionsWithDefaults,
startNodes,
},
diff --git a/remote/webdriver-bidi/modules/root/network.sys.mjs b/remote/webdriver-bidi/modules/root/network.sys.mjs
index 238b9f3640..6850e3f372 100644
--- a/remote/webdriver-bidi/modules/root/network.sys.mjs
+++ b/remote/webdriver-bidi/modules/root/network.sys.mjs
@@ -340,6 +340,9 @@ class NetworkModule extends Module {
* of any intercept, the request will be suspended.
*
* @param {object=} options
+ * @param {Array<string>=} options.contexts
+ * The list of browsing context ids where this intercept should be used.
+ * Optional, defaults to null.
* @param {Array<InterceptPhase>} options.phases
* The phases where this intercept should be checked.
* @param {Array<URLPattern>=} options.urlPatterns
@@ -353,7 +356,34 @@ class NetworkModule extends Module {
* Raised if an argument is of an invalid type or value.
*/
addIntercept(options = {}) {
- const { phases, urlPatterns = [] } = options;
+ const { contexts = null, phases, urlPatterns = [] } = options;
+
+ if (contexts !== null) {
+ lazy.assert.array(
+ contexts,
+ `Expected "contexts" to be an array, got ${contexts}`
+ );
+
+ if (!options.contexts.length) {
+ throw new lazy.error.InvalidArgumentError(
+ `Expected "contexts" to contain at least one item, got an empty array`
+ );
+ }
+
+ for (const contextId of contexts) {
+ lazy.assert.string(
+ contextId,
+ `Expected elements of "contexts" to be a string, got ${contextId}`
+ );
+ const context = this.#getBrowsingContext(contextId);
+
+ if (context.parent) {
+ throw new lazy.error.InvalidArgumentError(
+ `Context with id ${contextId} is not a top-level browsing context`
+ );
+ }
+ }
+ }
lazy.assert.array(
phases,
@@ -386,6 +416,7 @@ class NetworkModule extends Module {
const interceptId = lazy.generateUUID();
this.#interceptMap.set(interceptId, {
+ contexts,
phases,
urlPatterns: parsedPatterns,
});
@@ -1122,6 +1153,23 @@ class NetworkModule extends Module {
return challenges;
}
+ #getBrowsingContext(contextId) {
+ const context = lazy.TabManager.getBrowsingContextById(contextId);
+ if (context === null) {
+ throw new lazy.error.NoSuchFrameError(
+ `Browsing Context with id ${contextId} not found`
+ );
+ }
+
+ if (!context.currentWindowGlobal) {
+ throw new lazy.error.NoSuchFrameError(
+ `No window found for BrowsingContext with id ${contextId}`
+ );
+ }
+
+ return context;
+ }
+
#getContextInfo(browsingContext) {
return {
contextId: browsingContext.id,
@@ -1129,11 +1177,7 @@ class NetworkModule extends Module {
};
}
- #getSuspendMarkerText(requestData, phase) {
- return `Request (id: ${requestData.request}) suspended by WebDriver BiDi in ${phase} phase`;
- }
-
- #getNetworkIntercepts(event, requestData) {
+ #getNetworkIntercepts(event, requestData, contextId) {
const intercepts = [];
let phase;
@@ -1153,8 +1197,23 @@ class NetworkModule extends Module {
return intercepts;
}
+ // Retrieve the top browsing context id for this network event.
+ const browsingContext = lazy.TabManager.getBrowsingContextById(contextId);
+ const topLevelContextId = lazy.TabManager.getIdForBrowsingContext(
+ browsingContext.top
+ );
+
const url = requestData.url;
for (const [interceptId, intercept] of this.#interceptMap) {
+ if (
+ intercept.contexts !== null &&
+ !intercept.contexts.includes(topLevelContextId)
+ ) {
+ // Skip this intercept if the event's context does not match the list
+ // of contexts for this intercept.
+ continue;
+ }
+
if (intercept.phases.includes(phase)) {
const urlPatterns = intercept.urlPatterns;
if (
@@ -1196,6 +1255,10 @@ class NetworkModule extends Module {
return navigation ? navigation.navigationId : null;
}
+ #getSuspendMarkerText(requestData, phase) {
+ return `Request (id: ${requestData.request}) suspended by WebDriver BiDi in ${phase} phase`;
+ }
+
#onAuthRequired = (name, data) => {
const {
authCallbacks,
@@ -1580,7 +1643,11 @@ class NetworkModule extends Module {
#processNetworkEvent(eventName, data) {
const { contextId, navigation, redirectCount, requestData, timestamp } =
data;
- const intercepts = this.#getNetworkIntercepts(eventName, requestData);
+ const intercepts = this.#getNetworkIntercepts(
+ eventName,
+ requestData,
+ contextId
+ );
const isBlocked = !!intercepts.length;
const baseParameters = {
diff --git a/remote/webdriver-bidi/modules/root/session.sys.mjs b/remote/webdriver-bidi/modules/root/session.sys.mjs
index a34ca514e3..8ecf7d7724 100644
--- a/remote/webdriver-bidi/modules/root/session.sys.mjs
+++ b/remote/webdriver-bidi/modules/root/session.sys.mjs
@@ -76,16 +76,10 @@ class SessionModule extends Module {
const { events, contexts: contextIds = null } = params;
// Check input types until we run schema validation.
- lazy.assert.array(events, "events: array value expected");
- events.forEach(name => {
- lazy.assert.string(name, `${name}: string value expected`);
- });
+ this.#assertNonEmptyArrayWithStrings(events, "events");
if (contextIds !== null) {
- lazy.assert.array(contextIds, "contexts: array value expected");
- contextIds.forEach(contextId => {
- lazy.assert.string(contextId, `${contextId}: string value expected`);
- });
+ this.#assertNonEmptyArrayWithStrings(contextIds, "contexts");
}
const listeners = this.#updateEventMap(events, contextIds, true);
@@ -113,15 +107,9 @@ class SessionModule extends Module {
const { events, contexts: contextIds = null } = params;
// Check input types until we run schema validation.
- lazy.assert.array(events, "events: array value expected");
- events.forEach(name => {
- lazy.assert.string(name, `${name}: string value expected`);
- });
+ this.#assertNonEmptyArrayWithStrings(events, "events");
if (contextIds !== null) {
- lazy.assert.array(contextIds, "contexts: array value expected");
- contextIds.forEach(contextId => {
- lazy.assert.string(contextId, `${contextId}: string value expected`);
- });
+ this.#assertNonEmptyArrayWithStrings(contextIds, "contexts");
}
const listeners = this.#updateEventMap(events, contextIds, false);
@@ -139,6 +127,23 @@ class SessionModule extends Module {
}
}
+ #assertNonEmptyArrayWithStrings(array, variableName) {
+ lazy.assert.array(
+ array,
+ `Expected "${variableName}" to be an array, got ${array}`
+ );
+ lazy.assert.that(
+ array => !!array.length,
+ `Expected "${variableName}" array to have at least one item`
+ )(array);
+ array.forEach(item => {
+ lazy.assert.string(
+ item,
+ `Expected elements of "${variableName}" to be a string, got ${item}`
+ );
+ });
+ }
+
#getBrowserIdForContextId(contextId) {
const context = lazy.TabManager.getBrowsingContextById(contextId);
if (!context) {
diff --git a/remote/webdriver-bidi/modules/root/storage.sys.mjs b/remote/webdriver-bidi/modules/root/storage.sys.mjs
index 3eced2da4c..34f909aa28 100644
--- a/remote/webdriver-bidi/modules/root/storage.sys.mjs
+++ b/remote/webdriver-bidi/modules/root/storage.sys.mjs
@@ -16,6 +16,15 @@ ChromeUtils.defineESModuleGetters(lazy, {
"chrome://remote/content/shared/UserContextManager.sys.mjs",
});
+const PREF_COOKIE_BEHAVIOR = "network.cookie.cookieBehavior";
+const PREF_COOKIE_OPTIN_PARTITIONING =
+ "network.cookie.cookieBehavior.optInPartitioning";
+
+// This is a static preference, so it cannot be modified during runtime and we can cache its value.
+ChromeUtils.defineLazyGetter(lazy, "cookieBehaviorOptInPartitioning", () =>
+ Services.prefs.getBoolPref(PREF_COOKIE_OPTIN_PARTITIONING)
+);
+
const CookieFieldsMapping = {
domain: "host",
expiry: "expiry",
@@ -603,10 +612,22 @@ class StorageModule extends Module {
if (partitionSpec.type === PartitionType.Context) {
const { context: contextId } = partitionSpec;
const browsingContext = this.#getBrowsingContext(contextId);
+ const principal = Services.scriptSecurityManager.createContentPrincipal(
+ browsingContext.currentURI,
+ {}
+ );
// Define browsing context’s associated storage partition as combination of user context id
- // and the origin of the document in this browsing context.
+ // and the origin of the document in this browsing context. We also add here `isThirdPartyURI`
+ // which is required to filter out third-party cookies in case they are not allowed.
return {
+ // In case we have the browsing context of an iframe here, we perform a check
+ // if the URI of the top context is considered third-party to the URI of the iframe principal.
+ // It's considered a third-party if base domains or hosts (in case one or both base domains
+ // can not be determined) do not match.
+ isThirdPartyURI: browsingContext.parent
+ ? principal.isThirdPartyURI(browsingContext.top.currentURI)
+ : false,
sourceOrigin: browsingContext.currentURI.prePath,
userContext: browsingContext.originAttributes.userContextId,
};
@@ -640,6 +661,9 @@ class StorageModule extends Module {
);
}
+ // This key is not used for partitioning and was required to only filter out third-party cookies.
+ delete partitionKey.isThirdPartyURI;
+
return partitionKey;
}
@@ -742,44 +766,61 @@ class StorageModule extends Module {
// Prepare the data in the format required for the platform API.
const originAttributes = this.#getOriginAttributes(storagePartitionKey);
- // In case we want to get the cookies for a certain `sourceOrigin`,
- // we have to separately retrieve cookies for a hostname built from `sourceOrigin`,
- // and with `partitionKey` equal an empty string to retrieve the cookies that which were set
- // by this hostname but without `partitionKey`, e.g. with `document.cookie`.
- if (storagePartitionKey.sourceOrigin) {
- const url = new URL(storagePartitionKey.sourceOrigin);
- const hostname = url.hostname;
-
- const principal = Services.scriptSecurityManager.createContentPrincipal(
- Services.io.newURI(url),
- {}
+ // Retrieve the cookies which exactly match a built partition attributes.
+ const cookiesWithOriginAttributes =
+ Services.cookies.getCookiesWithOriginAttributes(
+ JSON.stringify(originAttributes)
);
- const isSecureProtocol = principal.isOriginPotentiallyTrustworthy;
-
- // We want to keep `userContext` id here, if it's present,
- // but set the `partitionKey` to an empty string.
- const cookiesMatchingHostname =
- Services.cookies.getCookiesWithOriginAttributes(
- JSON.stringify({ ...originAttributes, partitionKey: "" }),
- hostname
+
+ const isFirstPartyOrCrossSiteAllowed =
+ !storagePartitionKey.isThirdPartyURI ||
+ this.#shouldIncludeCrossSiteCookie();
+
+ // Check if we accessing the first party storage or cross-site cookies are allowed.
+ if (isFirstPartyOrCrossSiteAllowed) {
+ // In case we want to get the cookies for a certain `sourceOrigin`,
+ // we have to separately retrieve cookies for a hostname built from `sourceOrigin`,
+ // and with `partitionKey` equal an empty string to retrieve the cookies that which were set
+ // by this hostname but without `partitionKey`, e.g. with `document.cookie`.
+ if (storagePartitionKey.sourceOrigin) {
+ const url = new URL(storagePartitionKey.sourceOrigin);
+ const hostname = url.hostname;
+
+ const principal = Services.scriptSecurityManager.createContentPrincipal(
+ Services.io.newURI(url),
+ {}
);
+ const isSecureProtocol = principal.isOriginPotentiallyTrustworthy;
+
+ // We want to keep `userContext` id here, if it's present,
+ // but set the `partitionKey` to an empty string.
+ const cookiesMatchingHostname =
+ Services.cookies.getCookiesWithOriginAttributes(
+ JSON.stringify({ ...originAttributes, partitionKey: "" }),
+ hostname
+ );
+ for (const cookie of cookiesMatchingHostname) {
+ // Ignore secure cookies for non-secure protocols.
+ if (cookie.isSecure && !isSecureProtocol) {
+ continue;
+ }
+ store.push(cookie);
+ }
+ }
- for (const cookie of cookiesMatchingHostname) {
- // Ignore secure cookies for non-secure protocols.
- if (cookie.isSecure && !isSecureProtocol) {
- continue;
+ store = store.concat(cookiesWithOriginAttributes);
+ }
+ // If we're trying to access the store in the third party context and
+ // the preferences imply that we shouldn't include cross site cookies,
+ // but we should include partitioned cookies, add only partitioned cookies.
+ else if (this.#shouldIncludePartitionedCookies()) {
+ for (const cookie of cookiesWithOriginAttributes) {
+ if (cookie.isPartitioned) {
+ store.push(cookie);
}
- store.push(cookie);
}
}
- // Add the cookies which exactly match a built partition attributes.
- store = store.concat(
- Services.cookies.getCookiesWithOriginAttributes(
- JSON.stringify(originAttributes)
- )
- );
-
return store;
}
@@ -856,6 +897,30 @@ class StorageModule extends Module {
return cookie;
}
+
+ #shouldIncludeCrossSiteCookie() {
+ const cookieBehavior = Services.prefs.getIntPref(PREF_COOKIE_BEHAVIOR);
+
+ if (
+ cookieBehavior === Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN ||
+ cookieBehavior ===
+ Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ #shouldIncludePartitionedCookies() {
+ const cookieBehavior = Services.prefs.getIntPref(PREF_COOKIE_BEHAVIOR);
+
+ return (
+ cookieBehavior ===
+ Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN &&
+ lazy.cookieBehaviorOptInPartitioning
+ );
+ }
}
export const storage = StorageModule;
diff --git a/remote/webdriver-bidi/modules/windowglobal/browsingContext.sys.mjs b/remote/webdriver-bidi/modules/windowglobal/browsingContext.sys.mjs
index adf821601d..ef61954284 100644
--- a/remote/webdriver-bidi/modules/windowglobal/browsingContext.sys.mjs
+++ b/remote/webdriver-bidi/modules/windowglobal/browsingContext.sys.mjs
@@ -17,6 +17,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
"chrome://remote/content/webdriver-bidi/modules/root/browsingContext.sys.mjs",
OriginType:
"chrome://remote/content/webdriver-bidi/modules/root/browsingContext.sys.mjs",
+ OwnershipModel: "chrome://remote/content/webdriver-bidi/RemoteValue.sys.mjs",
PollPromise: "chrome://remote/content/shared/Sync.sys.mjs",
});
@@ -425,16 +426,9 @@ class BrowsingContextModule extends WindowGlobalBiDiModule {
}
_locateNodes(params = {}) {
- const {
- locator,
- maxNodeCount,
- resultOwnership,
- sandbox,
- serializationOptions,
- startNodes,
- } = params;
+ const { locator, maxNodeCount, serializationOptions, startNodes } = params;
- const realm = this.messageHandler.getRealm({ sandboxName: sandbox });
+ const realm = this.messageHandler.getRealm();
const contextNodes = [];
if (startNodes === null) {
@@ -482,7 +476,7 @@ class BrowsingContextModule extends WindowGlobalBiDiModule {
this.serialize(
returnedNode,
serializationOptions,
- resultOwnership,
+ lazy.OwnershipModel.None,
realm,
{ seenNodeIds }
)