Socket
Socket
Sign inDemoInstall

tough-cookie

Package Overview
Dependencies
0
Maintainers
2
Versions
46
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.2.0 to 2.0.0

test/jar_serialization_test.js

321

lib/cookie.js

@@ -38,2 +38,3 @@ /*!

var pathMatch = require('./pathMatch').pathMatch;
var VERSION = require('../package.json').version;

@@ -88,5 +89,3 @@ var punycode;

var cookiesCreated = 0; // Number of cookies created in runtime
// RFC6265 S5.1.1 date parser:

@@ -463,11 +462,16 @@ function parseDate(str) {

// ensure a default date for sorting:
c.creation = new Date();
//NOTE: add runtime index for the cookieCompare() to resolve the situation when Date's precision is not enough .
//Store initial UTC time as well, so we will be able to determine if we need to fallback to the Date object.
c._creationRuntimeIdx = ++cookiesCreated;
c._initialCreationTime = c.creation.getTime();
return c;
}
// avoid the V8 deoptimization monster!
function jsonParse(str) {
var obj;
try {
obj = JSON.parse(str);
} catch (e) {
return e;
}
return obj;
}
function fromJSON(str) {

@@ -479,14 +483,21 @@ if (!str) {

var obj;
try {
obj = JSON.parse(str);
} catch (e) {
return null;
if (typeof str === 'string') {
obj = jsonParse(str);
if (obj instanceof Error) {
return null;
}
} else {
// assume it's an Object
obj = str;
}
var c = new Cookie();
for (var i=0; i<numCookieProperties; i++) {
var prop = cookieProperties[i];
if (obj[prop] == null) {
continue;
for (var i=0; i<Cookie.serializableProperties.length; i++) {
var prop = Cookie.serializableProperties[i];
if (obj[prop] === undefined ||
obj[prop] === Cookie.prototype[prop])
{
continue; // leave as prototype default
}
if (prop === 'expires' ||

@@ -496,3 +507,8 @@ prop === 'creation' ||

{
c[prop] = obj[prop] == "Infinity" ? "Infinity" : new Date(obj[prop]);
if (obj[prop] === null) {
c[prop] = null;
} else {
c[prop] = obj[prop] == "Infinity" ?
"Infinity" : new Date(obj[prop]);
}
} else {

@@ -503,6 +519,2 @@ c[prop] = obj[prop];

// ensure a default date for sorting:
c.creation = c.creation || new Date();
return c;

@@ -521,19 +533,24 @@ }

function cookieCompare(a,b) {
var cmp = 0;
// descending for length: b CMP a
var deltaLen = (b.path ? b.path.length : 0) - (a.path ? a.path.length : 0);
if (deltaLen !== 0) {
return deltaLen;
var aPathLen = a.path ? a.path.length : 0;
var bPathLen = b.path ? b.path.length : 0;
cmp = bPathLen - aPathLen;
if (cmp !== 0) {
return cmp;
}
// ascending for time: a CMP b
var aTime = a.creation ? a.creation.getTime() : MAX_TIME;
var bTime = b.creation ? b.creation.getTime() : MAX_TIME;
// NOTE: if creation dates are equal and they were not modified from the outside,
// then use _creationRuntimeIdx for the comparison.
if(aTime === bTime && aTime === a._initialCreationTime && bTime === b._initialCreationTime) {
return a._creationRuntimeIdx - b._creationRuntimeIdx;
cmp = aTime - bTime;
if (cmp !== 0) {
return cmp;
}
// ascending for time: a CMP b
return aTime - bTime;
// break ties for the same millisecond (precision of JavaScript's clock)
cmp = a.creationIndex - b.creationIndex;
return cmp;
}

@@ -579,13 +596,27 @@

function Cookie (opts) {
if (typeof opts !== "object") {
return;
}
Object.keys(opts).forEach(function (key) {
if (Cookie.prototype.hasOwnProperty(key)) {
this[key] = opts[key] || Cookie.prototype[key];
function Cookie(opts) {
opts = opts || {};
Object.keys(opts).forEach(function(prop) {
if (Cookie.prototype.hasOwnProperty(prop) &&
Cookie.prototype[prop] !== opts[prop] &&
prop.substr(0,1) !== '_')
{
this[prop] = opts[prop];
}
}.bind(this));
}, this);
this.creation = this.creation || new Date();
// used to break creation ties in cookieCompare():
Object.defineProperty(this, 'creationIndex', {
configurable: false,
enumerable: false, // important for assert.deepEqual checks
writable: true,
value: ++Cookie.cookiesCreated
});
}
Cookie.cookiesCreated = 0; // incremented each time a cookie is created
Cookie.parse = parse;

@@ -610,13 +641,18 @@ Cookie.fromJSON = fromJSON;

Cookie.prototype.creation = null; // Date when set; defaulted by Cookie.parse
Cookie.prototype._initialCreationTime = null; // Used to determine if cookie.creation was modified
Cookie.prototype._creationRuntimeIdx = null; // Runtime index of the created cookie, used in cookieCompare()
Cookie.prototype.lastAccessed = null; // Date when set
Object.defineProperty(Cookie.prototype, 'creationIndex', {
configurable: true,
enumerable: false,
writable: true,
value: 0
});
var cookieProperties = Object.freeze(Object.keys(Cookie.prototype).map(function(p) {
if (p instanceof Function) {
return;
}
return p;
}));
var numCookieProperties = cookieProperties.length;
Cookie.serializableProperties = Object.keys(Cookie.prototype)
.filter(function(prop) {
return !(
Cookie.prototype[prop] instanceof Function ||
prop === 'creationIndex' ||
prop.substr(0,1) === '_'
);
});

@@ -632,2 +668,42 @@ Cookie.prototype.inspect = function inspect() {

Cookie.prototype.toJSON = function() {
var obj = {};
var props = Cookie.serializableProperties;
for (var i=0; i<props.length; i++) {
var prop = props[i];
if (this[prop] === Cookie.prototype[prop]) {
continue; // leave as prototype default
}
if (prop === 'expires' ||
prop === 'creation' ||
prop === 'lastAccessed')
{
if (this[prop] === null) {
obj[prop] = null;
} else {
obj[prop] = this[prop] == "Infinity" ? // intentionally not ===
"Infinity" : this[prop].toISOString();
}
} else if (prop === 'maxAge') {
if (this[prop] !== null) {
// again, intentionally not ===
obj[prop] = (this[prop] == Infinity || this[prop] == -Infinity) ?
this[prop].toString() : this[prop];
}
} else {
if (this[prop] !== Cookie.prototype[prop]) {
obj[prop] = this[prop];
}
}
}
return obj;
};
Cookie.prototype.clone = function() {
return fromJSON(this.toJSON());
};
Cookie.prototype.validate = function validate() {

@@ -757,3 +833,3 @@ if (!COOKIE_OCTETS.test(this.value)) {

if (this.maxAge != null) {
var relativeTo = this.creation || now || new Date();
var relativeTo = now || this.creation || new Date();
var age = (this.maxAge <= 0) ? -Infinity : this.maxAge*1000;

@@ -796,3 +872,2 @@ return relativeTo.getTime() + age;

function CookieJar(store, rejectPublicSuffixes) {

@@ -910,2 +985,3 @@ if (rejectPublicSuffixes != null) {

cookie.creation = oldCookie.creation; // step 11.3
cookie.creationIndex = oldCookie.creationIndex; // preserve tie-breaker
cookie.lastAccessed = now;

@@ -1057,2 +1133,147 @@ // Step 11.4 (delete cookie) is implied by just setting the new one:

CAN_BE_SYNC.push('serialize');
CookieJar.prototype.serialize = function(cb) {
var type = this.store.constructor.name;
if (type === 'Object') {
type = null;
}
// update README.md "Serialization Format" if you change this, please!
var serialized = {
// The version of tough-cookie that serialized this jar. Generally a good
// practice since future versions can make data import decisions based on
// known past behavior. When/if this matters, use `semver`.
version: 'tough-cookie@'+VERSION,
// add the store type, to make humans happy:
storeType: type,
// CookieJar configuration:
rejectPublicSuffixes: !!this.rejectPublicSuffixes,
// this gets filled from getAllCookies:
cookies: []
};
if (!(this.store.getAllCookies &&
typeof this.store.getAllCookies === 'function'))
{
return cb(new Error('store does not support getAllCookies and cannot be serialized'));
}
this.store.getAllCookies(function(err,cookies) {
if (err) {
return cb(err);
}
serialized.cookies = cookies.map(function(cookie) {
// convert to serialized 'raw' cookies
cookie = (cookie instanceof Cookie) ? cookie.toJSON() : cookie;
// Remove the index so new ones get assigned during deserialization
delete cookie.creationIndex;
return cookie;
});
return cb(null, serialized);
});
};
// well-known name that JSON.stringify calls
CookieJar.prototype.toJSON = function() {
return this.serializeSync();
};
// use the class method CookieJar.deserialize instead of calling this directly
CAN_BE_SYNC.push('_importCookies');
CookieJar.prototype._importCookies = function(serialized, cb) {
var jar = this;
var cookies = serialized.cookies;
if (!cookies || !Array.isArray(cookies)) {
return cb(new Error('serialized jar has no cookies array'));
}
function putNext(err) {
if (err) {
return cb(err);
}
if (!cookies.length) {
return cb(err, jar);
}
var cookie;
try {
cookie = fromJSON(cookies.shift());
} catch (e) {
return cb(e);
}
if (cookie === null) {
return putNext(null); // skip this cookie
}
jar.store.putCookie(cookie, putNext);
}
putNext();
};
CookieJar.deserialize = function(strOrObj, store, cb) {
if (arguments.length !== 3) {
// store is optional
cb = store;
store = null;
}
var serialized;
if (typeof strOrObj === 'string') {
serialized = jsonParse(strOrObj);
if (serialized instanceof Error) {
return cb(serialized);
}
} else {
serialized = strOrObj;
}
var jar = new CookieJar(store, serialized.rejectPublicSuffixes);
jar._importCookies(serialized, function(err) {
if (err) {
return cb(err);
}
cb(null, jar);
});
};
CookieJar.fromJSON = CookieJar.deserializeSync;
CookieJar.deserializeSync = function(strOrObj, store) {
var serialized = typeof strOrObj === 'string' ?
JSON.parse(strOrObj) : strOrObj;
var jar = new CookieJar(store, serialized.rejectPublicSuffixes);
// catch this mistake early:
if (!jar.store.synchronous) {
throw new Error('CookieJar store is not synchronous; use async API instead.');
}
jar._importCookiesSync(serialized);
return jar;
};
CAN_BE_SYNC.push('clone');
CookieJar.prototype.clone = function(newStore, cb) {
if (arguments.length === 1) {
cb = newStore;
newStore = null;
}
this.serialize(function(err,serialized) {
if (err) {
return cb(err);
}
CookieJar.deserialize(newStore, serialized, cb);
});
};
// Use a closure to provide a true imperative API for synchronous stores.

@@ -1059,0 +1280,0 @@ function syncWrap(method) {

@@ -44,2 +44,4 @@ /*!

MemoryCookieStore.prototype.idx = null;
// Since it's just a struct in RAM, this Store is synchronous
MemoryCookieStore.prototype.synchronous = true;

@@ -120,3 +122,3 @@

MemoryCookieStore.prototype.updateCookie = function updateCookie(oldCookie, newCookie, cb) {
MemoryCookieStore.prototype.updateCookie = function(oldCookie, newCookie, cb) {
// updateCookie() may avoid updating cookies that are identical. For example,

@@ -128,3 +130,3 @@ // lastAccessed may not be important to some stores and an equality

MemoryCookieStore.prototype.removeCookie = function removeCookie(domain, path, key, cb) {
MemoryCookieStore.prototype.removeCookie = function(domain, path, key, cb) {
if (this.idx[domain] && this.idx[domain][path] && this.idx[domain][path][key]) {

@@ -136,3 +138,3 @@ delete this.idx[domain][path][key];

MemoryCookieStore.prototype.removeCookies = function removeCookies(domain, path, cb) {
MemoryCookieStore.prototype.removeCookies = function(domain, path, cb) {
if (this.idx[domain]) {

@@ -147,1 +149,27 @@ if (path) {

};
MemoryCookieStore.prototype.getAllCookies = function(cb) {
var cookies = [];
var idx = this.idx;
var domains = Object.keys(idx);
domains.forEach(function(domain) {
var paths = Object.keys(idx[domain]);
paths.forEach(function(path) {
var keys = Object.keys(idx[domain][path]);
keys.forEach(function(key) {
if (key !== null) {
cookies.push(idx[domain][path][key]);
}
});
});
});
// Sort by creationIndex so deserializing retains the creation order.
// When implementing your own store, this SHOULD retain the order too
cookies.sort(function(a,b) {
return (a.creationIndex||0) - (b.creationIndex||0);
});
cb(null, cookies);
};

@@ -65,4 +65,8 @@ /*!

Store.prototype.removeCookies = function removeCookies(domain, path, cb) {
Store.prototype.removeCookies = function(domain, path, cb) {
throw new Error('removeCookies is not implemented');
};
Store.prototype.getAllCookies = function(cb) {
throw new Error('getAllCookies is not implemented (therefore jar cannot be serialized)');
};

2

package.json

@@ -16,3 +16,3 @@ {

],
"version": "1.2.0",
"version": "2.0.0",
"homepage": "https://github.com/SalesforceEng/tough-cookie",

@@ -19,0 +19,0 @@ "repository": {

@@ -11,3 +11,3 @@ [RFC6265](https://tools.ietf.org/html/rfc6265) Cookies and CookieJar for Node.js

``` javascript
var tough = require('tough-cookie'); // note: not 'cookie', 'cookies' or 'node-cookie'
var tough = require('tough-cookie');
var Cookie = tough.Cookie;

@@ -36,4 +36,3 @@ var cookie = Cookie.parse(header);

tough
=====
## tough

@@ -44,19 +43,15 @@ Functions on the module you get from `require('tough-cookie')`. All can be used as pure functions and don't need to be "bound".

parseDate(string)
-----------------
### `parseDate(string)`
Parse a cookie date string into a `Date`. Parses according to RFC6265 Section 5.1.1, not `Date.parse()`.
formatDate(date)
----------------
### `formatDate(date)`
Format a Date into a RFC1123 string (the RFC6265-recommended format).
canonicalDomain(str)
--------------------
### `canonicalDomain(str)`
Transforms a domain-name into a canonical domain-name. The canonical domain-name is a trimmed, lowercased, stripped-of-leading-dot and optionally punycode-encoded domain-name (Section 5.1.2 of RFC6265). For the most part, this function is idempotent (can be run again on its output without ill effects).
domainMatch(str,domStr[,canonicalize=true])
-------------------------------------------
### `domainMatch(str,domStr[,canonicalize=true])`

@@ -67,4 +62,3 @@ Answers "does this real domain match the domain in a cookie?". The `str` is the "current" domain-name and the `domStr` is the "cookie" domain-name. Matches according to RFC6265 Section 5.1.3, but it helps to think of it as a "suffix match".

defaultPath(path)
-----------------
### `defaultPath(path)`

@@ -75,4 +69,3 @@ Given a current request/response path, gives the Path apropriate for storing in a cookie. This is basically the "directory" of a "file" in the path, but is specified by Section 5.1.4 of the RFC.

pathMatch(reqPath,cookiePath)
-----------------------------
### `pathMatch(reqPath,cookiePath)`

@@ -83,14 +76,11 @@ Answers "does the request-path path-match a given cookie-path?" as per RFC6265 Section 5.1.4. Returns a boolean.

parse(header)
----------------------------
### `parse(header)`
alias for `Cookie.parse(header)`
fromJSON(string)
----------------
### `fromJSON(string)`
alias for `Cookie.fromJSON(string)`
getPublicSuffix(hostname)
-------------------------
### `getPublicSuffix(hostname)`

@@ -103,7 +93,10 @@ Returns the public suffix of this hostname. The public suffix is the shortest domain-name upon which a cookie can be set. Returns `null` if the hostname cannot have cookies set for it.

cookieCompare(a,b)
------------------
### `cookieCompare(a,b)`
For use with `.sort()`, sorts a list of cookies into the recommended order given in the RFC (Section 5.4 step 2). Longest `.path`s go first, then sorted oldest to youngest.
For use with `.sort()`, sorts a list of cookies into the recommended order given in the RFC (Section 5.4 step 2). The sort algorithm is, in order of precedence:
* Longest `.path`
* oldest `.creation` (which has a 1ms precision, same as `Date`)
* lowest `.creationIndex` (to get beyond the 1ms precision)
``` javascript

@@ -114,19 +107,19 @@ var cookies = [ /* unsorted array of Cookie objects */ ];

permuteDomain(domain)
---------------------
**Note**: Since JavaScript's `Date` is limited to a 1ms precision, cookies within the same milisecond are entirely possible. This is especially true when using the `now` option to `.setCookie()`. The `.creationIndex` property is a per-process global counter, assigned during construction with `new Cookie()`. This preserves the spirit of the RFC sorting: older cookies go first. This works great for `MemoryCookieStore`, since `Set-Cookie` headers are parsed in order, but may not be so great for distributed systems. Sophisticated `Store`s may wish to set this to some other _logical clock_ such that if cookies A and B are created in the same millisecond, but cookie A is created before cookie B, then `A.creationIndex < B.creationIndex`. If you want to alter the global counter, which you probably _shouldn't_ do, it's stored in `Cookie.cookiesCreated`.
### `permuteDomain(domain)`
Generates a list of all possible domains that `domainMatch()` the parameter. May be handy for implementing cookie stores.
### `permutePath(path)`
permutePath(path)
-----------------
Generates a list of all possible paths that `pathMatch()` the parameter. May be handy for implementing cookie stores.
Cookie
======
Cookie.parse(header)
-----------------------------------
## Cookie
Exported via `tough.Cookie`.
### `Cookie.parse(header)`
Parses a single Cookie or Set-Cookie HTTP header into a `Cookie` object. Returns `undefined` if the string can't be parsed.

@@ -143,10 +136,6 @@

Cookie.fromJSON(string)
-----------------------
### Properties
Convert a JSON string to a `Cookie` object. Does a `JSON.parse()` and converts the `.created`, `.lastAccessed` and `.expires` properties into `Date` objects.
Cookie object properties:
Properties
==========
* _key_ - string - the name or key of the cookie (default "")

@@ -161,2 +150,4 @@ * _value_ - string - the value of the cookie (default "")

* _extensions_ - `Array` - any unrecognized cookie attributes as strings (even if equal-signs inside)
* _creation_ - `Date` - when this cookie was constructed
* _creationIndex_ - number - set at construction, used to provide greater sort precision (please see `cookieCompare(a,b)` for a full explanation)

@@ -167,39 +158,32 @@ After a cookie has been passed through `CookieJar.setCookie()` it will have the following additional attributes:

* _pathIsDefault_ - boolean - if true, there was no Path field on the cookie and `defaultPath()` was used to derive one.
* _created_ - `Date` - when this cookie was added to the jar
* _creation_ - `Date` - **modified** from construction to when the cookie was added to the jar
* _lastAccessed_ - `Date` - last time the cookie got accessed. Will affect cookie cleaning once implemented. Using `cookiejar.getCookies(...)` will update this attribute.
Construction([{options}])
------------
### `Cookie([{properties}])`
Receives an options object that can contain any Cookie properties, uses the default for unspecified properties.
Receives an options object that can contain any of the above Cookie properties, uses the default for unspecified properties.
.toString()
-----------
### `.toString()`
encode to a Set-Cookie header value. The Expires cookie field is set using `formatDate()`, but is omitted entirely if `.expires` is `Infinity`.
.cookieString()
---------------
### `.cookieString()`
encode to a Cookie header value (i.e. the `.key` and `.value` properties joined with '=').
.setExpires(String)
-------------------
### `.setExpires(String)`
sets the expiry based on a date-string passed through `parseDate()`. If parseDate returns `null` (i.e. can't parse this date string), `.expires` is set to `"Infinity"` (a string) is set.
.setMaxAge(number)
-------------------
### `.setMaxAge(number)`
sets the maxAge in seconds. Coerces `-Infinity` to `"-Infinity"` and `Infinity` to `"Infinity"` so it JSON serializes correctly.
.expiryTime([now=Date.now()])
-----------------------------
### `.expiryTime([now=Date.now()])`
.expiryDate([now=Date.now()])
-----------------------------
### `.expiryDate([now=Date.now()])`
expiryTime() Computes the absolute unix-epoch milliseconds that this cookie expires. expiryDate() works similarly, except it returns a `Date` object. Note that in both cases the `now` parameter should be milliseconds.
Max-Age takes precedence over Expires (as per the RFC). The `.created` attribute -- or, by default, the `now` paramter -- is used to offset the `.maxAge` attribute.
Max-Age takes precedence over Expires (as per the RFC). The `.creation` attribute -- or, by default, the `now` paramter -- is used to offset the `.maxAge` attribute.

@@ -210,4 +194,3 @@ If Expires (`.expires`) is set, that's returned.

.TTL([now=Date.now()])
---------
### `.TTL([now=Date.now()])`

@@ -218,13 +201,30 @@ compute the TTL relative to `now` (milliseconds). The same precedence rules as for `expiryTime`/`expiryDate` apply.

.canonicalizedDoman()
---------------------
### `.canonicalizedDoman()`
.cdomain()
----------
### `.cdomain()`
return the canonicalized `.domain` field. This is lower-cased and punycode (RFC3490) encoded if the domain has any non-ASCII characters.
.validate()
-----------
### `.toJSON()`
For convenience in using `JSON.serialize(cookie)`. Returns a plain-old `Object` that can be JSON-serialized.
Any `Date` properties (i.e., `.expires`, `.creation`, and `.lastAccessed`) are exported in ISO format (`.toISOString()`).
**NOTE**: Custom `Cookie` properties will be discarded. In tough-cookie 1.x, since there was no `.toJSON` method explicitly defined, all enumerable properties were captured. If you want a property to be serialized, add the property name to the `Cookie.serializableProperties` Array.
### `Cookie.fromJSON(strOrObj)`
Does the reverse of `cookie.toJSON()`. If passed a string, will `JSON.parse()` that first.
Any `Date` properties (i.e., `.expires`, `.creation`, and `.lastAccessed`) are parsed via `Date.parse()`, not the tough-cookie `parseDate`, since it's JavaScript/JSON-y timestamps being handled at this layer.
Returns `null` upon JSON parsing error.
### `.clone()`
Does a deep clone of this cookie, exactly implemented as `Cookie.fromJSON(cookie.toJSON())`.
### `.validate()`
Status: *IN PROGRESS*. Works for a few things, but is by no means comprehensive.

@@ -242,13 +242,14 @@

CookieJar
=========
Construction([store = new MemoryCookieStore()][, rejectPublicSuffixes])
------------
## CookieJar
Exported via `tough.CookieJar`.
### `CookieJar([store],[rejectPublicSuffixes])`
Simply use `new CookieJar()`. If you'd like to use a custom store, pass that to the constructor otherwise a `MemoryCookieStore` will be created and used.
### Properties
Attributes
----------
CookieJar object properties:

@@ -259,6 +260,5 @@ * _rejectPublicSuffixes_ - boolean - reject cookies with domains like "com" and "co.uk" (default: `true`)

.setCookie(cookieOrString, currentUrl, [{options},] cb(err,cookie))
-------------------------------------------------------------------
### `.setCookie(cookieOrString, currentUrl, [{options},] cb(err,cookie))`
Attempt to set the cookie in the cookie jar. If the operation fails, an error will be given to the callback `cb`, otherwise the cookie is passed through. The cookie will have updated `.created`, `.lastAccessed` and `.hostOnly` properties.
Attempt to set the cookie in the cookie jar. If the operation fails, an error will be given to the callback `cb`, otherwise the cookie is passed through. The cookie will have updated `.creation`, `.lastAccessed` and `.hostOnly` properties.

@@ -270,19 +270,12 @@ The `options` object can be omitted and can have the following properties:

* _now_ - Date - default `new Date()` - what to use for the creation/access time of cookies
* _ignoreError_ - boolean - default `false` - silently ignore things like parse errors and invalid domains. CookieStore errors aren't ignored by this option.
* _ignoreError_ - boolean - default `false` - silently ignore things like parse errors and invalid domains. `Store` errors aren't ignored by this option.
As per the RFC, the `.hostOnly` property is set if there was no "Domain=" parameter in the cookie string (or `.domain` was null on the Cookie object). The `.domain` property is set to the fully-qualified hostname of `currentUrl` in this case. Matching this cookie requires an exact hostname match (not a `domainMatch` as per usual).
.setCookieSync(cookieOrString, currentUrl, [{options}])
-------------------------------------------------------
### `.setCookieSync(cookieOrString, currentUrl, [{options}])`
Synchronous version of `setCookie`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).
.storeCookie(cookie, [{options},] cb(err,cookie))
-------------------------------------------------
### `.getCookies(currentUrl, [{options},] cb(err,cookies))`
__REMOVED__ removed in lieu of the CookieStore API below
.getCookies(currentUrl, [{options},] cb(err,cookies))
-----------------------------------------------------
Retrieve the list of cookies that can be sent in a Cookie header for the current url.

@@ -298,42 +291,84 @@

* _expire_ - boolean - default `true` - perform expiry-time checking of cookies and asynchronously remove expired cookies from the store. Using `false` will return expired cookies and **not** remove them from the store (which is useful for replaying Set-Cookie headers, potentially).
* _allPaths_ - boolean - default `false` - if `true`, do not scope cookies by path. The default uses RFC-compliant path scoping. **Note**: may not be supported by the CookieStore `fetchCookies` function (the default MemoryCookieStore supports it).
* _allPaths_ - boolean - default `false` - if `true`, do not scope cookies by path. The default uses RFC-compliant path scoping. **Note**: may not be supported by the underlying store (the default `MemoryCookieStore` supports it).
The `.lastAccessed` property of the returned cookies will have been updated.
.getCookiesSync(currentUrl, [{options}])
----------------------------------------
### `.getCookiesSync(currentUrl, [{options}])`
Synchronous version of `getCookies`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).
.getCookieString(...)
---------------------
### `.getCookieString(...)`
Accepts the same options as `.getCookies()` but passes a string suitable for a Cookie header rather than an array to the callback. Simply maps the `Cookie` array via `.cookieString()`.
.getCookieStringSync(...)
-------------------------
### `.getCookieStringSync(...)`
Synchronous version of `getCookieString`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).
.getSetCookieStrings(...)
-------------------------
### `.getSetCookieStrings(...)`
Returns an array of strings suitable for **Set-Cookie** headers. Accepts the same options as `.getCookies()`. Simply maps the cookie array via `.toString()`.
.getSetCookieStringsSync(...)
-----------------------------
### `.getSetCookieStringsSync(...)`
Synchronous version of `getSetCookieStrings`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).
Store
=====
### `.serialize(cb(err,serializedObject))`
Base class for CookieJar stores.
Serialize the Jar if the underlying store supports `.getAllCookies`.
# CookieStore API
**NOTE**: Custom `Cookie` properties will be discarded. If you want a property to be serialized, add the property name to the `Cookie.serializableProperties` Array.
See [Serialization Format].
### `.serializeSync()`
Sync version of .serialize
### `.toJSON()`
Alias of .serializeSync() for the convenience of `JSON.stringify(cookiejar)`.
### `CookieJar.deserialize(serialized, [store], cb(err,object))`
A new Jar is created and the serialized Cookies are added to the underlying store. Each `Cookie` is added via `store.putCookie` in the order in which they appear in the serialization.
The `store` argument is optional, but should be an instance of `Store`. By default, a new instance of `MemoryCookieStore` is created.
As a convenience, if `serialized` is a string, it is passed through `JSON.parse` first. If that throws an error, this is passed to the callback.
### `CookieJar.deserializeSync(serialized, [store])`
Sync version of `.deserialize`. _Note_ that the `store` must be synchronous for this to work.
### `CookieJar.fromJSON(string)`
Alias of `.deserializeSync` to provide consistency with `Cookie.fromJSON()`.
### `.clone([store,]cb(err,newJar))`
Produces a deep clone of this jar. Modifications to the original won't affect the clone, and vice versa.
The `store` argument is optional, but should be an instance of `Store`. By default, a new instance of `MemoryCookieStore` is created. Transferring between store types is supported so long as the source implements `.getAllCookies()` and the destination implements `.putCookie()`.
### `.cloneSync([store])`
Synchronous version of `.clone`, returning a new `CookieJar` instance.
The `store` argument is optional, but must be a _synchronous_ `Store` instance if specified. If not passed, a new instance of `MemoryCookieStore` is used.
The _source_ and _destination_ must both be synchronous `Store`s. If one or both stores are asynchronous, use `.clone` instead. Recall that `MemoryCookieStore` supports both synchronous and asynchronous API calls.
## Store
Base class for CookieJar stores. Available as `tough.Store`.
## Store API
The storage model for each `CookieJar` instance can be replaced with a custom implementation. The default is `MemoryCookieStore` which can be found in the `lib/memstore.js` file. The API uses continuation-passing-style to allow for asynchronous stores.
Stores should inherit from the base `Store` class, which is available as `require('tough-cookie').Store`. Stores are asynchronous by default, but if `store.synchronous` is set, then the `*Sync` methods on the CookieJar can be used.
Stores should inherit from the base `Store` class, which is available as `require('tough-cookie').Store`.
Stores are asynchronous by default, but if `store.synchronous` is set to `true`, then the `*Sync` methods on the of the containing `CookieJar` can be used (however, the continuation-passing style
All `domain` parameters will have been normalized before calling.

@@ -343,4 +378,3 @@

store.findCookie(domain, path, key, cb(err,cookie))
---------------------------------------------------
### `store.findCookie(domain, path, key, cb(err,cookie))`

@@ -351,4 +385,3 @@ Retrieve a cookie with the given domain, path and key (a.k.a. name). The RFC maintains that exactly one of these cookies should exist in a store. If the store is using versioning, this means that the latest/newest such cookie should be returned.

store.findCookies(domain, path, cb(err,cookies))
------------------------------------------------
### `store.findCookies(domain, path, cb(err,cookies))`

@@ -363,4 +396,3 @@ Locates cookies matching the given domain and path. This is most often called in the context of `cookiejar.getCookies()` above.

store.putCookie(cookie, cb(err))
--------------------------------
### `store.putCookie(cookie, cb(err))`

@@ -373,8 +405,7 @@ Adds a new cookie to the store. The implementation SHOULD replace any existing cookie with the same `.domain`, `.path`, and `.key` properties -- depending on the nature of the implementation, it's possible that between the call to `fetchCookie` and `putCookie` that a duplicate `putCookie` can occur.

store.updateCookie(oldCookie, newCookie, cb(err))
-------------------------------------------------
### `store.updateCookie(oldCookie, newCookie, cb(err))`
Update an existing cookie. The implementation MUST update the `.value` for a cookie with the same `domain`, `.path` and `.key`. The implementation SHOULD check that the old value in the store is equivalent to `oldCookie` - how the conflict is resolved is up to the store.
The `.lastAccessed` property will always be different between the two objects and `.created` will always be the same. Stores MAY ignore or defer the `.lastAccessed` change at the cost of affecting how cookies are sorted (or selected for deletion).
The `.lastAccessed` property will always be different between the two objects (to the precision possible via JavaScript's clock). Both `.creation` and `.creationIndex` are guaranteed to be the same. Stores MAY ignore or defer the `.lastAccessed` change at the cost of affecting how cookies are selected for automatic deletion (e.g., least-recently-used, which is up to the store to implement).

@@ -387,4 +418,3 @@ Stores may wish to optimize changing the `.value` of the cookie in the store versus storing a new cookie. If the implementation doesn't define this method a stub that calls `putCookie(newCookie,cb)` will be added to the store object.

store.removeCookie(domain, path, key, cb(err))
----------------------------------------------
### `store.removeCookie(domain, path, key, cb(err))`

@@ -395,4 +425,3 @@ Remove a cookie from the store (see notes on `findCookie` about the uniqueness constraint).

store.removeCookies(domain, path, cb(err))
------------------------------------------
### `store.removeCookies(domain, path, cb(err))`

@@ -403,9 +432,44 @@ Removes matching cookies from the store. The `path` parameter is optional, and if missing means all paths in a domain should be removed.

MemoryCookieStore
=================
### `store.getAllCookies(cb(err, cookies))`
Inherits from Store.
Produces an `Array` of all cookies during `jar.serialize()`. The items in the array can be true `Cookie` objects or generic `Object`s with the [Serialization Format] data structure.
Just-in-memory CookieJar synchronous store implementation, used by default.
Cookies SHOULD be returned in creation order to preserve sorting via `compareCookies()`. For reference, `MemoryCookieStore` will sort by `.creationIndex` since it uses true `Cookie` objects internally. If you don't return the cookies in creation order, they'll still be sorted by creation time, but this only has a precision of 1ms. See `compareCookies` for more detail.
Pass an error if retrieval fails.
## MemoryCookieStore
Inherits from `Store`.
A just-in-memory CookieJar synchronous store implementation, used by default. Despite being a synchronous implementation, it's usable with both the synchronous and asynchronous forms of the `CookieJar` API.
# Serialization Format
**NOTE**: if you want to have custom `Cookie` properties serialized, add the property name to `Cookie.serializableProperties`.
```js
{
// The version of tough-cookie that serialized this jar.
version: 'tough-cookie@1.x.y',
// add the store type, to make humans happy:
storeType: 'MemoryCookieStore',
// CookieJar configuration:
rejectPublicSuffixes: true,
// ... future items go here
// Gets filled from jar.store.getAllCookies():
cookies: [
{
key: 'string',
value: 'string',
// ...
/* other Cookie.serializableProperties go here */
}
]
}
```
# Copyright and License

@@ -412,0 +476,0 @@

@@ -36,2 +36,3 @@ /*!

var Cookie = tough.Cookie;
var CookieJar = tough.CookieJar;

@@ -47,2 +48,67 @@ function toKeyArray(cookies) {

.addBatch({
"Assumptions:": {
".creationIndex is set during construction": function() {
var now = new Date();
var c1 = new Cookie();
var c2 = new Cookie();
assert.isNumber(c1.creationIndex);
assert.isNumber(c2.creationIndex);
assert(c1.creationIndex < c2.creationIndex,
'creationIndex should increase with each construction');
},
".creationIndex is set during construction (forced ctime)": function() {
var now = new Date();
var c1 = new Cookie({creation: now});
var c2 = new Cookie({creation: now});
assert.strictEqual(c1.creation, c2.creation);
assert.isNumber(c1.creationIndex);
assert.isNumber(c2.creationIndex);
assert(c1.creationIndex < c2.creationIndex,
'creationIndex should increase with each construction');
},
".creationIndex is left alone during new setCookie": function() {
var jar = new CookieJar();
var c = new Cookie({key:'k', value:'v', domain:'example.com'});
var now = new Date();
var beforeDate = c.creation;
assert.instanceOf(beforeDate, Date);
assert.notStrictEqual(now, beforeDate);
var beforeIndex = c.creationIndex;
assert.isNumber(c.creationIndex);
jar.setCookieSync(c, 'http://example.com/', {now: now});
assert.strictEqual(c.creation, now);
assert.strictEqual(c.creationIndex, beforeIndex);
},
".creationIndex is preserved during update setCookie": function() {
var jar = new CookieJar();
var thisMs = Date.now();
var t1 = new Date(thisMs);
var t2 = new Date(thisMs);
assert.notStrictEqual(t1, t2); // Date objects are distinct
var c = new Cookie({key:'k', value:'v1', domain:'example.com'});
jar.setCookieSync(c, 'http://example.com/', {now: t1});
var originalIndex = c.creationIndex;
assert.strictEqual(c.creation, t1);
assert.strictEqual(c.lastAccessed, t1);
c = new Cookie({key:'k', value:'v2', domain:'example.com'});
assert.notStrictEqual(c.creation, t1); // new timestamp assigned
jar.setCookieSync(c, 'http://example.com/', {now: t2});
assert.strictEqual(c.creation, t1); // retained
assert.strictEqual(c.lastAccessed, t2); // updated
assert.strictEqual(c.creationIndex, originalIndex); // retained
},
}
})
.addBatch({
"Cookie Sorting": {

@@ -49,0 +115,0 @@ topic: function () {

@@ -126,4 +126,4 @@ /*!

topic: function(f) { return f(null) },
"looks good": function(str) {
assert.match(str, /"maxAge":null/);
"absent": function(str) {
assert.match(str, /(?!"maxAge":null)/); // NB: negative RegExp
}

@@ -130,0 +130,0 @@ }

@@ -64,4 +64,3 @@ /*!

var actual = jar.getCookiesSync(sentTo);
actual = actual.sort(tough.cookieCompare);
var actual = jar.getCookiesSync(sentTo,{sort:true});

@@ -68,0 +67,0 @@ assert.strictEqual(actual.length, expected.length);

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc