Skip to content

Commit

Permalink
Unit test cases for allowSpecialUseDomain option (#225)
Browse files Browse the repository at this point in the history
This PR adds test cases for the `allowSpecialUseDomain` option introduced in [PR #173](#173).  The special use domain check was changed to be a refinement on the public suffix check since both setting and retrieving cookies can fail since not all special use domains are considered public suffixes.

The following cases are tested:
* when the cookie jar is configured with `allowSpecialUseDomain=true`, the code will skip the lookup of a public suffix when a special use domain is detected
* when the cookie jar is configured with `allowSpecialUseDomain=false`, the code will raise an error describing proper usage when a special use domain is detected

Co-authored-by: Andrew Waterman <[email protected]>
  • Loading branch information
colincasey and awaterma authored Dec 20, 2021
1 parent 250380a commit d079268
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 27 deletions.
5 changes: 4 additions & 1 deletion lib/cookie.js
Original file line number Diff line number Diff line change
Expand Up @@ -1166,7 +1166,10 @@ class CookieJar {

// S5.3 step 5: public suffixes
if (this.rejectPublicSuffixes && cookie.domain) {
const suffix = pubsuffix.getPublicSuffix(cookie.cdomain());
const suffix = pubsuffix.getPublicSuffix(cookie.cdomain(), {
allowSpecialUseDomain: this.allowSpecialUseDomain,
ignoreError: options.ignoreError
});
if (suffix == null && !IP_V6_REGEX_OBJECT.test(cookie.domain)) {
// e.g. "com"
err = new Error("Cookie has domain set to a public suffix");
Expand Down
28 changes: 3 additions & 25 deletions lib/permuteDomain.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,32 +34,10 @@ 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.

// RFC 6761
const SPECIAL_USE_DOMAINS = [
"local",
"example",
"invalid",
"localhost",
"test"
];

function permuteDomain(domain, allowSpecialUseDomain) {
let pubSuf = null;
if (allowSpecialUseDomain) {
const domainParts = domain.split(".");
// If the right-most label in the name is a special-use domain (e.g. bananas.apple.localhost),
// then don't use PSL. This is because most special-use domains are not listed on PSL.
const topLevelDomain = domainParts[domainParts.length - 1];
if (SPECIAL_USE_DOMAINS.includes(topLevelDomain)) {
const secondLevelDomain = domainParts[domainParts.length - 2];
// In aforementioned example, the eTLD/pubSuf will be apple.localhost
pubSuf = `${secondLevelDomain}.${topLevelDomain}`;
} else {
pubSuf = pubsuffix.getPublicSuffix(domain);
}
} else {
pubSuf = pubsuffix.getPublicSuffix(domain);
}
const pubSuf = pubsuffix.getPublicSuffix(domain, {
allowSpecialUseDomain: allowSpecialUseDomain
});

if (!pubSuf) {
return null;
Expand Down
34 changes: 33 additions & 1 deletion lib/pubsuffix-psl.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,39 @@
"use strict";
const psl = require("psl");

function getPublicSuffix(domain) {
// RFC 6761
const SPECIAL_USE_DOMAINS = [
"local",
"example",
"invalid",
"localhost",
"test"
];

function getPublicSuffix(domain, options = {}) {
const domainParts = domain.split(".");
const topLevelDomain = domainParts[domainParts.length - 1];
const allowSpecialUseDomain = !!options.allowSpecialUseDomain;
const ignoreError = !!options.ignoreError;

if (
allowSpecialUseDomain &&
domainParts.length > 1 &&
SPECIAL_USE_DOMAINS.includes(topLevelDomain)
) {
// If the right-most label in the name is a special-use domain (e.g. bananas.apple.localhost),
// then don't use PSL. This is because most special-use domains are not listed on PSL.
const secondLevelDomain = domainParts[domainParts.length - 2];
// In aforementioned example, the eTLD/pubSuf will be apple.localhost
return `${secondLevelDomain}.${topLevelDomain}`;
}

if (!ignoreError && SPECIAL_USE_DOMAINS.includes(topLevelDomain)) {
throw new Error(
`Cookie has domain set to the public suffix "${topLevelDomain}" which is a special use domain. To allow this, configure your CookieJar with {allowSpecialUseDomain:true, rejectPublicSuffixes: false}.`
);
}

return psl.get(domain);
}

Expand Down
82 changes: 82 additions & 0 deletions test/api_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -579,4 +579,86 @@ vows
}
}
})
.addBatch(allowSpecialUseOptionVows())
.export(module);

function allowSpecialUseOptionVows() {
const specialUseDomains = [
"local",
"example",
"invalid",
"localhost",
"test"
];

return specialUseDomains.reduce((vows, specialUseDomain) => {
vows[
`cookie jar with allowSpecialUseDomain enabled and domain is "${specialUseDomain}"`
] = {
topic: function() {
const cb = this.callback;
const cj = new CookieJar(new tough.MemoryCookieStore(), {
rejectPublicSuffixes: true,
allowSpecialUseDomain: true
});
cj.setCookie(
`settingThisShouldPass=true; Domain=dev.${specialUseDomain}; Path=/;`,
`http://dev.${specialUseDomain}`,
at(-1),
(err, cookie) => {
cb(err, { cj: cj, cookie: cookie });
}
);
},
"set the cookie": function(t) {
assert.ok(t.cookie, "didn't set?!");
assert.equal(t.cookie.key, "settingThisShouldPass");
},
"then, retrieving": {
topic: function(t) {
const cb = this.callback;
setTimeout(() => {
t.cj.getCookies(
`http://dev.${specialUseDomain}`,
{ http: true },
(err, cookies) => {
t.cookies = cookies;
cb(err, t);
}
);
}, 2000);
},
"got the cookie": function(t) {
assert.lengthOf(t.cookies, 1);
assert.equal(t.cookies[0].key, "settingThisShouldPass");
}
}
};

vows[
`cookie jar with allowSpecialUseDomain disabled and domain is "${specialUseDomain}"`
] = {
topic: function() {
const cj = new CookieJar(new tough.MemoryCookieStore(), {
allowSpecialUseDomain: false,
rejectPublicSuffixes: true
});
cj.setCookie(
`settingThisShouldFail=true; Domain=dev.${specialUseDomain}; Path=/;`,
`http://dev.${specialUseDomain}`,
this.callback
);
},
errors: function(err, cookie) {
assert.ok(err);
assert.ok(!cookie);
assert.equal(
err.message,
`Cookie has domain set to the public suffix "${specialUseDomain}" which is a special use domain. To allow this, configure your CookieJar with {allowSpecialUseDomain:true, rejectPublicSuffixes: false}.`
);
}
};

return vows;
}, {});
}

0 comments on commit d079268

Please sign in to comment.