Skip to content

Commit

Permalink
fix: allow set cookies with localhost
Browse files Browse the repository at this point in the history
Adding more tests to cover the breaking use cases noted in #246.

e.g.;.
* `new CookieJar().setCookieSync("settingThisShouldPass=true; Domain=localhost; Path=/;", "http://localhost")`

Also modifies the assertion for a test introduced in #221 that may be incorrect.
  • Loading branch information
colincasey committed Aug 25, 2022
1 parent ea0ea0c commit 7ae6c00
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 50 deletions.
26 changes: 13 additions & 13 deletions lib/pubsuffix-psl.js
Expand Up @@ -40,28 +40,28 @@ const SPECIAL_USE_DOMAINS = [
"test"
];

const SPECIAL_TREATMENT_DOMAINS = ["localhost", "invalid"];

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 (allowSpecialUseDomain && SPECIAL_USE_DOMAINS.includes(topLevelDomain)) {
if (domainParts.length > 1) {
const secondLevelDomain = domainParts[domainParts.length - 2];
// In aforementioned example, the eTLD/pubSuf will be apple.localhost
return `${secondLevelDomain}.${topLevelDomain}`;
} else if (SPECIAL_TREATMENT_DOMAINS.includes(topLevelDomain)) {
// For a single word special use domain, e.g. 'localhost' or 'invalid', per RFC 6761,
// "Application software MAY recognize {localhost/invalid} names as special, or
// MAY pass them to name resolution APIs as they would for other domain names."
return `${topLevelDomain}`;
}
}

if (!ignoreError && SPECIAL_USE_DOMAINS.includes(topLevelDomain)) {
if (allowSpecialUseDomain) {
return 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}.`
);
Expand Down
76 changes: 40 additions & 36 deletions test/api_test.js
Expand Up @@ -591,46 +591,50 @@ function allowSpecialUseOptionVows() {
"test"
];

const specialTreatmentDomains = ["localhost", "invalid"];

return specialUseDomains.reduce((vows, specialUseDomain) => {
vows[
`cookie jar with allowSpecialUseDomain set to the default value and domain is "${specialUseDomain}"`
] = {
topic: function() {
const cb = this.callback;
const cj = new CookieJar();
cj.setCookie(
`settingThisShouldPass=true; Domain=${specialUseDomain}; Path=/;`,
`http://${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) {
if (specialTreatmentDomains.includes(specialUseDomain)) {
vows[
`cookie jar with allowSpecialUseDomain set to the default value and domain is "${specialUseDomain}"`
] = {
topic: function() {
const cb = this.callback;
setTimeout(() => {
t.cj.getCookies(
`http://${specialUseDomain}`,
{ http: true },
(err, cookies) => {
t.cookies = cookies;
cb(err, t);
}
);
}, 2000);
const cj = new CookieJar();
cj.setCookie(
`settingThisShouldPass=true; Domain=${specialUseDomain}; Path=/;`,
`http://${specialUseDomain}`,
at(-1),
(err, cookie) => {
cb(err, { cj: cj, cookie: cookie });
}
);
},
"got the cookie": function(t) {
assert.lengthOf(t.cookies, 1);
assert.equal(t.cookies[0].key, "settingThisShouldPass");
"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://${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 set to the default value and domain is "dev.${specialUseDomain}"`
Expand Down
18 changes: 17 additions & 1 deletion test/regression_test.js
Expand Up @@ -197,10 +197,26 @@ vows
return cookieJar.setCookieSync(
"a=b; Domain=localhost",
"http://localhost"
);
); // Users are free to use localhost names as they would any other domain names. [RFC 6761, Sec. 6.3.1]
},
works: function(err, c) {
assert.instanceOf(c, Cookie);
assert.match(c, /Domain=localhost/);
}
}
},
{
"setCookie with localhost (localhost. domain) (GH-215)": {
topic: function() {
const cookieJar = new CookieJar();
return cookieJar.setCookieSync(
"a=b; Domain=localhost.",
"http://localhost."
); // Users are free to use localhost names as they would any other domain names. [RFC 6761, Sec. 6.3.1]
},
works: function(err, c) {
assert.instanceOf(c, Cookie);
assert.match(c, /Domain=localhost/);
}
}
},
Expand Down

0 comments on commit 7ae6c00

Please sign in to comment.