Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: allow set cookies with localhost #253

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 2 additions & 33 deletions CHANGELOG.md
@@ -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
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
@@ -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
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
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
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