Skip to content

Commit

Permalink
fix: allow set cookies with localhost (#253)
Browse files Browse the repository at this point in the history
* fix: allow set cookies with localhost

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.

* fix: allow set cookies with localhost

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.

* fix: allow set cookies with localhost

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.

* fix: allow set cookies with localhost

updated CHANGELOG.md to point to the releases page since changelogs are auto-generated now.

* Release v4.1.2
  • Loading branch information
colincasey authored Aug 25, 2022
1 parent ec70796 commit b1a8898
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 53 deletions.
35 changes: 2 additions & 33 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,5 @@
# Changelog

All notable changes to this project will be documented in this file.

## 4.X.X

### Minor Changes
- Added parameter checking to setCookie so as to error out when no URL was passed in

## X.Y.Z

### Minor Changes
- Added loose mode to the serialized options. Now a serialized cookie jar with loose mode enabled will honor that flag when deserialized.
- Added allowSpecialUseDomain and prefixSecurity to the serialized options. Now any options accepted passed in to the cookie jar will be honored when serialized and deserialized.
- Added handling of IPv6 host names so that they would work with tough cookie.

## 4.0.0

### Breaking Changes (Major Version)

- Modernized JS Syntax
- Use ESLint and Prettier to apply consistent, modern formatting (add dependency on `universalify`, `eslint` and `prettier`)
- Upgraded version dependencies for `psl` and `async`
- Re-order parameters for `findCookies()` - callback fn has to be last in order to comply with `universalify`
- Use Classes instead of function prototypes to define classes
- Might break people using `.call()` to do inheritance using function prototypes

### Minor Changes
- SameSite cookie support
- Cookie prefix support
- Support for promises
- '.local' support
- Numerous bug fixes!


All notable changes to this project can be found at on the [Releases](https://github.com/salesforce/tough-cookie/releases)
page.

23 changes: 13 additions & 10 deletions lib/pubsuffix-psl.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,25 @@ 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)) {
Expand Down
2 changes: 1 addition & 1 deletion lib/version.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// generated by genversion
module.exports = '4.1.1'
module.exports = '4.1.2'
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"RFC6265",
"RFC2965"
],
"version": "4.1.1",
"version": "4.1.2",
"homepage": "https://github.com/salesforce/tough-cookie",
"repository": {
"type": "git",
Expand Down
50 changes: 47 additions & 3 deletions test/api_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -591,9 +591,53 @@ function allowSpecialUseOptionVows() {
"test"
];

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

return specialUseDomains.reduce((vows, specialUseDomain) => {
if (specialTreatmentDomains.includes(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) {
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 "${specialUseDomain}"`
`cookie jar with allowSpecialUseDomain set to the default value and domain is "dev.${specialUseDomain}"`
] = {
topic: function() {
const cb = this.callback;
Expand Down Expand Up @@ -633,7 +677,7 @@ function allowSpecialUseOptionVows() {
};

vows[
`cookie jar with allowSpecialUseDomain enabled and domain is "${specialUseDomain}"`
`cookie jar with allowSpecialUseDomain enabled and domain is "dev.${specialUseDomain}"`
] = {
topic: function() {
const cb = this.callback;
Expand Down Expand Up @@ -676,7 +720,7 @@ function allowSpecialUseOptionVows() {
};

vows[
`cookie jar with allowSpecialUseDomain disabled and domain is "${specialUseDomain}"`
`cookie jar with allowSpecialUseDomain disabled and domain is "dev.${specialUseDomain}"`
] = {
topic: function() {
const cj = new CookieJar(new tough.MemoryCookieStore(), {
Expand Down
24 changes: 19 additions & 5 deletions test/regression_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,20 +197,34 @@ vows
return cookieJar.setCookieSync(
"a=b; Domain=localhost",
"http://localhost"
); // when domain set to 'localhost', will throw 'Error: Cookie has domain set to a public suffix'
); // Users are free to use localhost names as they would any other domain names. [RFC 6761, Sec. 6.3.1]
},
works: function(err, c) {
// localhost as domain throws an error, cookie should not be defined
assert.instanceOf(err, Error);
assert.isUndefined(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/);
}
}
},
{
"setCookie with localhost (GH-215) (null domain)": {
topic: function() {
const cookieJar = new CookieJar();
return cookieJar.setCookieSync("a=b; Domain=", "http://localhost"); // when domain set to 'localhost', will throw 'Error: Cookie has domain set to a public suffix'
return cookieJar.setCookieSync("a=b; Domain=", "http://localhost");
},
works: function(c) {
assert.instanceOf(c, Cookie);
Expand Down

0 comments on commit b1a8898

Please sign in to comment.