@@ -50,2 +50,3 @@ /** | ||
| export type Credentials = import("./types.js").Credentials; | ||
| export type SameSiteType = "strict" | "lax" | "none"; | ||
| export type CookieInfo = { | ||
@@ -73,5 +74,5 @@ /** | ||
| /** | ||
| * The HTTP-only flag of the cookie. | ||
| * The SameSite attribute of the cookie. | ||
| */ | ||
| httpOnly?: boolean | undefined; | ||
| sameSite?: SameSiteType | undefined; | ||
| }; |
@@ -15,2 +15,5 @@ /** | ||
| /** | ||
| * @typedef {"strict"|"lax"|"none"} SameSiteType | ||
| */ | ||
| /** | ||
| * @typedef {Object} CookieInfo | ||
@@ -22,3 +25,3 @@ * @property {string} name The name of the cookie. | ||
| * @property {boolean} [secure] The secure flag of the cookie. | ||
| * @property {boolean} [httpOnly] The HTTP-only flag of the cookie. | ||
| * @property {SameSiteType} [sameSite] The SameSite attribute of the cookie. | ||
| */ | ||
@@ -28,2 +31,3 @@ //----------------------------------------------------------------------------- | ||
| //----------------------------------------------------------------------------- | ||
| const sameSiteValues = new Set(["strict", "lax", "none"]); | ||
| /** | ||
@@ -44,2 +48,17 @@ * Asserts that a string is a valid domain that does not include a protocol or path. | ||
| /** | ||
| * Asserts that a string is a valid SameSite value and that the security requirements are met. | ||
| * @param {SameSiteType|undefined} sameSite The SameSite value to verify. | ||
| * @param {boolean} secure The secure flag of the cookie. | ||
| * @throws {TypeError} If the SameSite value is not valid or if SameSite=None without Secure. | ||
| */ | ||
| function assertValidSameSite(sameSite, secure) { | ||
| if (sameSite && !sameSiteValues.has(sameSite)) { | ||
| throw new TypeError(`Invalid sameSite value: ${sameSite}`); | ||
| } | ||
| // If sameSite is "none", secure must be true | ||
| if (sameSite === "none" && !secure) { | ||
| throw new TypeError(`SameSite=None requires Secure flag to be true`); | ||
| } | ||
| } | ||
| /** | ||
| * Represents a cookie. | ||
@@ -75,6 +94,6 @@ * @implements {CookieInfo} | ||
| /** | ||
| * The HTTP-only flag of the cookie. | ||
| * @type {boolean} | ||
| * The SameSite attribute of the cookie. | ||
| * @type {SameSiteType} | ||
| */ | ||
| httpOnly; | ||
| sameSite; | ||
| /** | ||
@@ -86,7 +105,7 @@ * Creates a new CookieData instance. | ||
| * @param {string|undefined} options.domain The domain of the cookie. | ||
| * @param {string} [options.path=""] The path of the cookie. | ||
| * @param {string} [options.path="/"] The path of the cookie. | ||
| * @param {boolean} [options.secure=false] The secure flag of the cookie. | ||
| * @param {boolean} [options.httpOnly=false] The HTTP-only flag of the cookie. | ||
| * @param {SameSiteType} [options.sameSite="lax"] The SameSite attribute of the cookie. | ||
| */ | ||
| constructor({ name, value, domain, path = "/", secure = false, httpOnly = false, }) { | ||
| constructor({ name, value, domain, path = "/", secure = false, sameSite = "lax", }) { | ||
| assertValidDomain(domain); | ||
@@ -99,2 +118,3 @@ if (!name) { | ||
| } | ||
| assertValidSameSite(sameSite, secure); | ||
| this.name = name; | ||
@@ -105,3 +125,3 @@ this.value = value; | ||
| this.secure = secure; | ||
| this.httpOnly = httpOnly; | ||
| this.sameSite = sameSite; | ||
| } | ||
@@ -124,5 +144,42 @@ /** | ||
| const url = parseUrl(request.url); | ||
| return (url.hostname.endsWith(this.domain) && | ||
| // Basic checks for domain, path, and secure flag | ||
| const basicChecks = url.hostname.endsWith(this.domain) && | ||
| url.pathname.startsWith(this.path) && | ||
| (this.secure ? url.protocol === "https:" : true)); | ||
| (this.secure ? url.protocol === "https:" : true); | ||
| if (!basicChecks) { | ||
| return false; | ||
| } | ||
| // Check SameSite attribute | ||
| if (this.sameSite) { | ||
| const requestOrigin = request.headers?.get("Origin"); | ||
| switch (this.sameSite) { | ||
| case "strict": | ||
| // Only send cookie if the request came from the same origin | ||
| if (requestOrigin && requestOrigin !== url.origin) { | ||
| return false; | ||
| } | ||
| break; | ||
| case "lax": | ||
| // Permit cookies for navigation to top-level document via "safe" methods | ||
| // For simplicity, we'll only block cross-origin non-GET requests in Lax mode | ||
| if (requestOrigin && | ||
| requestOrigin !== url.origin && | ||
| request.method !== "GET") { | ||
| return false; | ||
| } | ||
| break; | ||
| case "none": | ||
| // Allow cross-origin requests, but cookie must be Secure | ||
| // We already validated secure flag in the constructor | ||
| break; | ||
| default: | ||
| // Default to Lax behavior | ||
| if (requestOrigin && | ||
| requestOrigin !== url.origin && | ||
| request.method !== "GET") { | ||
| return false; | ||
| } | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
@@ -148,8 +205,8 @@ /** | ||
| } | ||
| if (this.sameSite) { | ||
| cookieString += `; SameSite=${this.sameSite}`; | ||
| } | ||
| if (this.secure) { | ||
| cookieString += `; Secure`; | ||
| } | ||
| if (this.httpOnly) { | ||
| cookieString += `; HttpOnly`; | ||
| } | ||
| return cookieString + "]"; | ||
@@ -156,0 +213,0 @@ } |
+1
-1
| { | ||
| "name": "mentoss", | ||
| "version": "0.10.0", | ||
| "version": "0.11.0", | ||
| "description": "A utility to mock fetch requests and responses.", | ||
@@ -5,0 +5,0 @@ "type": "module", |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
149588
1.71%3451
1.71%