diff --git a/README.md b/README.md index 656a2555..d4e27f79 100644 --- a/README.md +++ b/README.md @@ -251,6 +251,7 @@ The `options` object can be omitted and can have the following properties: * _rejectPublicSuffixes_ - boolean - default `true` - reject cookies with domains like "com" and "co.uk" * _looseMode_ - boolean - default `false` - accept malformed cookies like `bar` and `=bar`, which have an implied empty name. + * _allowSpecialUseDomain_ - boolean - default `false` - accepts special-use domain suffixes, such as `local`. Useful for testing purposes. This is not in the standard, but is used sometimes on the web and is accepted by (most) browsers. Since eventually this module would like to support database/remote/etc. CookieJars, continuation passing style is used for CookieJar methods. diff --git a/lib/cookie.js b/lib/cookie.js index 3c695f0a..72edd0e2 100644 --- a/lib/cookie.js +++ b/lib/cookie.js @@ -981,6 +981,9 @@ function CookieJar(store, options) { if (options.looseMode != null) { this.enableLooseMode = options.looseMode; } + if (options.allowSpecialUseDomain != null) { + this.allowSpecialUseDomain = options.allowSpecialUseDomain; + } if (!store) { store = new MemoryCookieStore(); @@ -990,6 +993,7 @@ function CookieJar(store, options) { CookieJar.prototype.store = null; CookieJar.prototype.rejectPublicSuffixes = true; CookieJar.prototype.enableLooseMode = false; +CookieJar.prototype.allowSpecialUseDomain = false; const CAN_BE_SYNC = []; CAN_BE_SYNC.push("setCookie"); @@ -1213,7 +1217,7 @@ CookieJar.prototype.getCookies = function(url, options, cb) { // TODO persist lastAccessed cb(null, cookies); - }); + }, this.allowSpecialUseDomain); }; CAN_BE_SYNC.push("getCookieString"); diff --git a/lib/memstore.js b/lib/memstore.js index 12aa9e2c..d2288a5e 100644 --- a/lib/memstore.js +++ b/lib/memstore.js @@ -67,7 +67,7 @@ MemoryCookieStore.prototype.findCookie = function(domain, path, key, cb) { return cb(null, this.idx[domain][path][key] || null); }; -MemoryCookieStore.prototype.findCookies = function(domain, path, cb) { +MemoryCookieStore.prototype.findCookies = function(domain, path, cb, allowSpecialUseDomain) { const results = []; if (!domain) { return cb(null, []); @@ -100,7 +100,7 @@ MemoryCookieStore.prototype.findCookies = function(domain, path, cb) { }; } - const domains = permuteDomain(domain) || [domain]; + const domains = permuteDomain(domain, allowSpecialUseDomain) || [domain]; const idx = this.idx; domains.forEach(curDomain => { const domainIndex = idx[curDomain]; diff --git a/lib/permuteDomain.js b/lib/permuteDomain.js index fb814e31..78e6cad5 100644 --- a/lib/permuteDomain.js +++ b/lib/permuteDomain.js @@ -33,8 +33,22 @@ const pubsuffix = require("./pubsuffix-psl"); // Gives the permutation of all possible domainMatch()es of a given domain. The // array is in shortest-to-longest order. Handy for indexing. -function permuteDomain(domain) { - const pubSuf = pubsuffix.getPublicSuffix(domain); +const SPECIAL_USE_DOMAINS = ["local"]; // RFC 6761 +function permuteDomain(domain, allowSpecialUseDomain) { + let pubSuf = null; + if (allowSpecialUseDomain) { + const domainParts = domain.split("."); + if (SPECIAL_USE_DOMAINS.includes(domainParts[domainParts.length - 1])) { + pubSuf = `${domainParts[domainParts.length - 2]}.${ + domainParts[domainParts.length - 1] + }`; + } else { + pubSuf = pubsuffix.getPublicSuffix(domain); + } + } else { + pubSuf = pubsuffix.getPublicSuffix(domain); + } + if (!pubSuf) { return null; }