From 8b06ee751cb7a419f22811d0a7aae8d6194dafdb Mon Sep 17 00:00:00 2001 From: Colin Casey Date: Thu, 25 Aug 2022 10:03:09 -0300 Subject: [PATCH 1/5] 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. --- lib/pubsuffix-psl.js | 3 +++ test/api_test.js | 44 +++++++++++++++++++++++++++++++++++++++-- test/regression_test.js | 8 +++----- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/lib/pubsuffix-psl.js b/lib/pubsuffix-psl.js index d5555523..bf416511 100644 --- a/lib/pubsuffix-psl.js +++ b/lib/pubsuffix-psl.js @@ -59,6 +59,9 @@ function getPublicSuffix(domain, options = {}) { } if (!ignoreError && SPECIAL_USE_DOMAINS.includes(topLevelDomain)) { + if (allowSpecialUseDomain) { + return ""; + } 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}.` ); diff --git a/test/api_test.js b/test/api_test.js index 42e6166e..fae25378 100644 --- a/test/api_test.js +++ b/test/api_test.js @@ -594,6 +594,46 @@ function allowSpecialUseOptionVows() { 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) { + 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}"` ] = { topic: function() { const cb = this.callback; @@ -633,7 +673,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; @@ -676,7 +716,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(), { diff --git a/test/regression_test.js b/test/regression_test.js index 29d21c0e..44f9b83e 100644 --- a/test/regression_test.js +++ b/test/regression_test.js @@ -197,12 +197,10 @@ 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' + ); }, 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); } } }, @@ -210,7 +208,7 @@ vows "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); From ea0ea0ce42a81563a92cb8c00a7d876df6235754 Mon Sep 17 00:00:00 2001 From: Colin Casey Date: Thu, 25 Aug 2022 10:11:55 -0300 Subject: [PATCH 2/5] 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. --- lib/pubsuffix-psl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pubsuffix-psl.js b/lib/pubsuffix-psl.js index bf416511..83398555 100644 --- a/lib/pubsuffix-psl.js +++ b/lib/pubsuffix-psl.js @@ -60,7 +60,7 @@ function getPublicSuffix(domain, options = {}) { if (!ignoreError && SPECIAL_USE_DOMAINS.includes(topLevelDomain)) { if (allowSpecialUseDomain) { - return ""; + 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}.` From 7ae6c00ffed8290b2343ea46e38ed8f9bb424cbb Mon Sep 17 00:00:00 2001 From: Colin Casey Date: Thu, 25 Aug 2022 14:43:51 -0300 Subject: [PATCH 3/5] 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. --- lib/pubsuffix-psl.js | 26 +++++++------- test/api_test.js | 76 ++++++++++++++++++++++------------------- test/regression_test.js | 18 +++++++++- 3 files changed, 70 insertions(+), 50 deletions(-) diff --git a/lib/pubsuffix-psl.js b/lib/pubsuffix-psl.js index 83398555..b6649346 100644 --- a/lib/pubsuffix-psl.js +++ b/lib/pubsuffix-psl.js @@ -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}.` ); diff --git a/test/api_test.js b/test/api_test.js index fae25378..73fd3ed6 100644 --- a/test/api_test.js +++ b/test/api_test.js @@ -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}"` diff --git a/test/regression_test.js b/test/regression_test.js index 44f9b83e..f9ff15b9 100644 --- a/test/regression_test.js +++ b/test/regression_test.js @@ -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/); } } }, From bd7a3916a2abfdf5ba41a9d69539d8a6008c432b Mon Sep 17 00:00:00 2001 From: Colin Casey Date: Thu, 25 Aug 2022 15:33:56 -0300 Subject: [PATCH 4/5] fix: allow set cookies with localhost updated CHANGELOG.md to point to the releases page since changelogs are auto-generated now. --- CHANGELOG.md | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83cecb5a..94427e49 100644 --- a/CHANGELOG.md +++ b/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. From 0c7917f8b6cc45144b326592e6a058130c74e2b7 Mon Sep 17 00:00:00 2001 From: Colin Casey Date: Thu, 25 Aug 2022 15:34:33 -0300 Subject: [PATCH 5/5] Release v4.1.2 --- lib/version.js | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/version.js b/lib/version.js index 1b1faea1..0cba2a81 100644 --- a/lib/version.js +++ b/lib/version.js @@ -1,2 +1,2 @@ // generated by genversion -module.exports = '4.1.1' +module.exports = '4.1.2' diff --git a/package.json b/package.json index e56c2386..4bc8ccea 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "RFC6265", "RFC2965" ], - "version": "4.1.1", + "version": "4.1.2", "homepage": "https://github.com/salesforce/tough-cookie", "repository": { "type": "git",