1 | [RFC6265](https://tools.ietf.org/html/rfc6265) Cookies and CookieJar for Node.js
|
2 |
|
3 | [![npm package](https://nodei.co/npm/tough-cookie.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/tough-cookie/)
|
4 |
|
5 | [![Build Status](https://travis-ci.org/salesforce/tough-cookie.svg?branch=master)](https://travis-ci.org/salesforce/tough-cookie)
|
6 |
|
7 | # Synopsis
|
8 |
|
9 | ``` javascript
|
10 | var tough = require('tough-cookie');
|
11 | var Cookie = tough.Cookie;
|
12 | var cookie = Cookie.parse(header);
|
13 | cookie.value = 'somethingdifferent';
|
14 | header = cookie.toString();
|
15 |
|
16 | var cookiejar = new tough.CookieJar();
|
17 | cookiejar.setCookie(cookie, 'http://currentdomain.example.com/path', cb);
|
18 | // ...
|
19 | cookiejar.getCookies('http://example.com/otherpath',function(err,cookies) {
|
20 | res.headers['cookie'] = cookies.join('; ');
|
21 | });
|
22 | ```
|
23 |
|
24 | # Installation
|
25 |
|
26 | It's _so_ easy!
|
27 |
|
28 | `npm install tough-cookie`
|
29 |
|
30 | Why the name? NPM modules `cookie`, `cookies` and `cookiejar` were already taken.
|
31 |
|
32 | ## Version Support
|
33 |
|
34 | Support for versions of node.js will follow that of the [request](https://www.npmjs.com/package/request) module.
|
35 |
|
36 | # API
|
37 |
|
38 | ## tough
|
39 |
|
40 | Functions on the module you get from `require('tough-cookie')`. All can be used as pure functions and don't need to be "bound".
|
41 |
|
42 | **Note**: prior to 1.0.x, several of these functions took a `strict` parameter. This has since been removed from the API as it was no longer necessary.
|
43 |
|
44 | ### `parseDate(string)`
|
45 |
|
46 | Parse a cookie date string into a `Date`. Parses according to RFC6265 Section 5.1.1, not `Date.parse()`.
|
47 |
|
48 | ### `formatDate(date)`
|
49 |
|
50 | Format a Date into a RFC1123 string (the RFC6265-recommended format).
|
51 |
|
52 | ### `canonicalDomain(str)`
|
53 |
|
54 | 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).
|
55 |
|
56 | ### `domainMatch(str,domStr[,canonicalize=true])`
|
57 |
|
58 | 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".
|
59 |
|
60 | The `canonicalize` parameter will run the other two parameters through `canonicalDomain` or not.
|
61 |
|
62 | ### `defaultPath(path)`
|
63 |
|
64 | 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.
|
65 |
|
66 | The `path` parameter MUST be _only_ the pathname part of a URI (i.e. excludes the hostname, query, fragment, etc.). This is the `.pathname` property of node's `uri.parse()` output.
|
67 |
|
68 | ### `pathMatch(reqPath,cookiePath)`
|
69 |
|
70 | Answers "does the request-path path-match a given cookie-path?" as per RFC6265 Section 5.1.4. Returns a boolean.
|
71 |
|
72 | This is essentially a prefix-match where `cookiePath` is a prefix of `reqPath`.
|
73 |
|
74 | ### `parse(cookieString[, options])`
|
75 |
|
76 | alias for `Cookie.parse(cookieString[, options])`
|
77 |
|
78 | ### `fromJSON(string)`
|
79 |
|
80 | alias for `Cookie.fromJSON(string)`
|
81 |
|
82 | ### `getPublicSuffix(hostname)`
|
83 |
|
84 | 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.
|
85 |
|
86 | For example: `www.example.com` and `www.subdomain.example.com` both have public suffix `example.com`.
|
87 |
|
88 | For further information, see http://publicsuffix.org/. This module derives its list from that site. This call is currently a wrapper around [`psl`](https://www.npmjs.com/package/psl)'s [get() method](https://www.npmjs.com/package/psl#pslgetdomain).
|
89 |
|
90 | ### `cookieCompare(a,b)`
|
91 |
|
92 | 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:
|
93 |
|
94 | * Longest `.path`
|
95 | * oldest `.creation` (which has a 1ms precision, same as `Date`)
|
96 | * lowest `.creationIndex` (to get beyond the 1ms precision)
|
97 |
|
98 | ``` javascript
|
99 | var cookies = [ /* unsorted array of Cookie objects */ ];
|
100 | cookies = cookies.sort(cookieCompare);
|
101 | ```
|
102 |
|
103 | **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`.
|
104 |
|
105 | ### `permuteDomain(domain)`
|
106 |
|
107 | Generates a list of all possible domains that `domainMatch()` the parameter. May be handy for implementing cookie stores.
|
108 |
|
109 | ### `permutePath(path)`
|
110 |
|
111 | Generates a list of all possible paths that `pathMatch()` the parameter. May be handy for implementing cookie stores.
|
112 |
|
113 |
|
114 | ## Cookie
|
115 |
|
116 | Exported via `tough.Cookie`.
|
117 |
|
118 | ### `Cookie.parse(cookieString[, options])`
|
119 |
|
120 | Parses a single Cookie or Set-Cookie HTTP header into a `Cookie` object. Returns `undefined` if the string can't be parsed.
|
121 |
|
122 | The options parameter is not required and currently has only one property:
|
123 |
|
124 | * _loose_ - boolean - if `true` enable parsing of key-less cookies like `=abc` and `=`, which are not RFC-compliant.
|
125 |
|
126 | If options is not an object, it is ignored, which means you can use `Array#map` with it.
|
127 |
|
128 | Here's how to process the Set-Cookie header(s) on a node HTTP/HTTPS response:
|
129 |
|
130 | ``` javascript
|
131 | if (res.headers['set-cookie'] instanceof Array)
|
132 | cookies = res.headers['set-cookie'].map(Cookie.parse);
|
133 | else
|
134 | cookies = [Cookie.parse(res.headers['set-cookie'])];
|
135 | ```
|
136 |
|
137 | _Note:_ in version 2.3.3, tough-cookie limited the number of spaces before the `=` to 256 characters. This limitation has since been removed.
|
138 | See [Issue 92](https://github.com/salesforce/tough-cookie/issues/92)
|
139 |
|
140 | ### Properties
|
141 |
|
142 | Cookie object properties:
|
143 |
|
144 | * _key_ - string - the name or key of the cookie (default "")
|
145 | * _value_ - string - the value of the cookie (default "")
|
146 | * _expires_ - `Date` - if set, the `Expires=` attribute of the cookie (defaults to the string `"Infinity"`). See `setExpires()`
|
147 | * _maxAge_ - seconds - if set, the `Max-Age=` attribute _in seconds_ of the cookie. May also be set to strings `"Infinity"` and `"-Infinity"` for non-expiry and immediate-expiry, respectively. See `setMaxAge()`
|
148 | * _domain_ - string - the `Domain=` attribute of the cookie
|
149 | * _path_ - string - the `Path=` of the cookie
|
150 | * _secure_ - boolean - the `Secure` cookie flag
|
151 | * _httpOnly_ - boolean - the `HttpOnly` cookie flag
|
152 | * _sameSite_ - string - the `SameSite` cookie attribute (from [RFC6265bis]); must be one of `none`, `lax`, or `strict`
|
153 | * _extensions_ - `Array` - any unrecognized cookie attributes as strings (even if equal-signs inside)
|
154 | * _creation_ - `Date` - when this cookie was constructed
|
155 | * _creationIndex_ - number - set at construction, used to provide greater sort precision (please see `cookieCompare(a,b)` for a full explanation)
|
156 |
|
157 | After a cookie has been passed through `CookieJar.setCookie()` it will have the following additional attributes:
|
158 |
|
159 | * _hostOnly_ - boolean - is this a host-only cookie (i.e. no Domain field was set, but was instead implied)
|
160 | * _pathIsDefault_ - boolean - if true, there was no Path field on the cookie and `defaultPath()` was used to derive one.
|
161 | * _creation_ - `Date` - **modified** from construction to when the cookie was added to the jar
|
162 | * _lastAccessed_ - `Date` - last time the cookie got accessed. Will affect cookie cleaning once implemented. Using `cookiejar.getCookies(...)` will update this attribute.
|
163 |
|
164 | ### `Cookie([{properties}])`
|
165 |
|
166 | Receives an options object that can contain any of the above Cookie properties, uses the default for unspecified properties.
|
167 |
|
168 | ### `.toString()`
|
169 |
|
170 | encode to a Set-Cookie header value. The Expires cookie field is set using `formatDate()`, but is omitted entirely if `.expires` is `Infinity`.
|
171 |
|
172 | ### `.cookieString()`
|
173 |
|
174 | encode to a Cookie header value (i.e. the `.key` and `.value` properties joined with '=').
|
175 |
|
176 | ### `.setExpires(String)`
|
177 |
|
178 | 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.
|
179 |
|
180 | ### `.setMaxAge(number)`
|
181 |
|
182 | sets the maxAge in seconds. Coerces `-Infinity` to `"-Infinity"` and `Infinity` to `"Infinity"` so it JSON serializes correctly.
|
183 |
|
184 | ### `.expiryTime([now=Date.now()])`
|
185 |
|
186 | ### `.expiryDate([now=Date.now()])`
|
187 |
|
188 | 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.
|
189 |
|
190 | Max-Age takes precedence over Expires (as per the RFC). The `.creation` attribute -- or, by default, the `now` parameter -- is used to offset the `.maxAge` attribute.
|
191 |
|
192 | If Expires (`.expires`) is set, that's returned.
|
193 |
|
194 | Otherwise, `expiryTime()` returns `Infinity` and `expiryDate()` returns a `Date` object for "Tue, 19 Jan 2038 03:14:07 GMT" (latest date that can be expressed by a 32-bit `time_t`; the common limit for most user-agents).
|
195 |
|
196 | ### `.TTL([now=Date.now()])`
|
197 |
|
198 | compute the TTL relative to `now` (milliseconds). The same precedence rules as for `expiryTime`/`expiryDate` apply.
|
199 |
|
200 | The "number" `Infinity` is returned for cookies without an explicit expiry and `0` is returned if the cookie is expired. Otherwise a time-to-live in milliseconds is returned.
|
201 |
|
202 | ### `.canonicalizedDomain()`
|
203 |
|
204 | ### `.cdomain()`
|
205 |
|
206 | return the canonicalized `.domain` field. This is lower-cased and punycode (RFC3490) encoded if the domain has any non-ASCII characters.
|
207 |
|
208 | ### `.toJSON()`
|
209 |
|
210 | For convenience in using `JSON.serialize(cookie)`. Returns a plain-old `Object` that can be JSON-serialized.
|
211 |
|
212 | Any `Date` properties (i.e., `.expires`, `.creation`, and `.lastAccessed`) are exported in ISO format (`.toISOString()`).
|
213 |
|
214 | **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.
|
215 |
|
216 | ### `Cookie.fromJSON(strOrObj)`
|
217 |
|
218 | Does the reverse of `cookie.toJSON()`. If passed a string, will `JSON.parse()` that first.
|
219 |
|
220 | 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.
|
221 |
|
222 | Returns `null` upon JSON parsing error.
|
223 |
|
224 | ### `.clone()`
|
225 |
|
226 | Does a deep clone of this cookie, exactly implemented as `Cookie.fromJSON(cookie.toJSON())`.
|
227 |
|
228 | ### `.validate()`
|
229 |
|
230 | Status: *IN PROGRESS*. Works for a few things, but is by no means comprehensive.
|
231 |
|
232 | validates cookie attributes for semantic correctness. Useful for "lint" checking any Set-Cookie headers you generate. For now, it returns a boolean, but eventually could return a reason string -- you can future-proof with this construct:
|
233 |
|
234 | ``` javascript
|
235 | if (cookie.validate() === true) {
|
236 | // it's tasty
|
237 | } else {
|
238 | // yuck!
|
239 | }
|
240 | ```
|
241 |
|
242 |
|
243 | ## CookieJar
|
244 |
|
245 | Exported via `tough.CookieJar`.
|
246 |
|
247 | ### `CookieJar([store],[options])`
|
248 |
|
249 | 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.
|
250 |
|
251 | The `options` object can be omitted and can have the following properties:
|
252 |
|
253 | * _rejectPublicSuffixes_ - boolean - default `true` - reject cookies with domains like "com" and "co.uk"
|
254 | * _looseMode_ - boolean - default `false` - accept malformed cookies like `bar` and `=bar`, which have an implied empty name.
|
255 | * _prefixSecurity_ - string - default `silent` - set to `'unsafe-disabled'`, `'silent'`, or `'strict'`. See [Cookie Prefixes] below.
|
256 | * _allowSpecialUseDomain_ - boolean - default `false` - accepts special-use domain suffixes, such as `local`. Useful for testing purposes.
|
257 | This is not in the standard, but is used sometimes on the web and is accepted by (most) browsers.
|
258 |
|
259 | Since eventually this module would like to support database/remote/etc. CookieJars, continuation passing style is used for CookieJar methods.
|
260 |
|
261 | ### `.setCookie(cookieOrString, currentUrl, [{options},] cb(err,cookie))`
|
262 |
|
263 | 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.
|
264 |
|
265 | The `options` object can be omitted and can have the following properties:
|
266 |
|
267 | * _http_ - boolean - default `true` - indicates if this is an HTTP or non-HTTP API. Affects HttpOnly cookies.
|
268 | * _secure_ - boolean - autodetect from url - indicates if this is a "Secure" API. If the currentUrl starts with `https:` or `wss:` then this is defaulted to `true`, otherwise `false`.
|
269 | * _now_ - Date - default `new Date()` - what to use for the creation/access time of cookies
|
270 | * _ignoreError_ - boolean - default `false` - silently ignore things like parse errors and invalid domains. `Store` errors aren't ignored by this option.
|
271 | * _sameSiteContext_ - string - default unset - set to `'none'`, `'lax'`, or `'strict'` See [SameSite Cookies] below.
|
272 |
|
273 | 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).
|
274 |
|
275 | ### `.setCookieSync(cookieOrString, currentUrl, [{options}])`
|
276 |
|
277 | Synchronous version of `setCookie`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).
|
278 |
|
279 | ### `.getCookies(currentUrl, [{options},] cb(err,cookies))`
|
280 |
|
281 | Retrieve the list of cookies that can be sent in a Cookie header for the current url.
|
282 |
|
283 | If an error is encountered, that's passed as `err` to the callback, otherwise an `Array` of `Cookie` objects is passed. The array is sorted with `cookieCompare()` unless the `{sort:false}` option is given.
|
284 |
|
285 | The `options` object can be omitted and can have the following properties:
|
286 |
|
287 | * _http_ - boolean - default `true` - indicates if this is an HTTP or non-HTTP API. Affects HttpOnly cookies.
|
288 | * _secure_ - boolean - autodetect from url - indicates if this is a "Secure" API. If the currentUrl starts with `https:` or `wss:` then this is defaulted to `true`, otherwise `false`.
|
289 | * _now_ - Date - default `new Date()` - what to use for the creation/access time of cookies
|
290 | * _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).
|
291 | * _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).
|
292 | * _sameSiteContext_ - string - default unset - Set this to `'none'`, `'lax'` or `'strict'` to enforce SameSite cookies upon retrival. See [SameSite Cookies] below.
|
293 |
|
294 | The `.lastAccessed` property of the returned cookies will have been updated.
|
295 |
|
296 | ### `.getCookiesSync(currentUrl, [{options}])`
|
297 |
|
298 | Synchronous version of `getCookies`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).
|
299 |
|
300 | ### `.getCookieString(...)`
|
301 |
|
302 | 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()`.
|
303 |
|
304 | ### `.getCookieStringSync(...)`
|
305 |
|
306 | Synchronous version of `getCookieString`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).
|
307 |
|
308 | ### `.getSetCookieStrings(...)`
|
309 |
|
310 | Returns an array of strings suitable for **Set-Cookie** headers. Accepts the same options as `.getCookies()`. Simply maps the cookie array via `.toString()`.
|
311 |
|
312 | ### `.getSetCookieStringsSync(...)`
|
313 |
|
314 | Synchronous version of `getSetCookieStrings`; only works with synchronous stores (e.g. the default `MemoryCookieStore`).
|
315 |
|
316 | ### `.serialize(cb(err,serializedObject))`
|
317 |
|
318 | Serialize the Jar if the underlying store supports `.getAllCookies`.
|
319 |
|
320 | **NOTE**: Custom `Cookie` properties will be discarded. If you want a property to be serialized, add the property name to the `Cookie.serializableProperties` Array.
|
321 |
|
322 | See [Serialization Format].
|
323 |
|
324 | ### `.serializeSync()`
|
325 |
|
326 | Sync version of .serialize
|
327 |
|
328 | ### `.toJSON()`
|
329 |
|
330 | Alias of .serializeSync() for the convenience of `JSON.stringify(cookiejar)`.
|
331 |
|
332 | ### `CookieJar.deserialize(serialized, [store], cb(err,object))`
|
333 |
|
334 | 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.
|
335 |
|
336 | The `store` argument is optional, but should be an instance of `Store`. By default, a new instance of `MemoryCookieStore` is created.
|
337 |
|
338 | 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.
|
339 |
|
340 | ### `CookieJar.deserializeSync(serialized, [store])`
|
341 |
|
342 | Sync version of `.deserialize`. _Note_ that the `store` must be synchronous for this to work.
|
343 |
|
344 | ### `CookieJar.fromJSON(string)`
|
345 |
|
346 | Alias of `.deserializeSync` to provide consistency with `Cookie.fromJSON()`.
|
347 |
|
348 | ### `.clone([store,]cb(err,newJar))`
|
349 |
|
350 | Produces a deep clone of this jar. Modifications to the original won't affect the clone, and vice versa.
|
351 |
|
352 | 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()`.
|
353 |
|
354 | ### `.cloneSync([store])`
|
355 |
|
356 | Synchronous version of `.clone`, returning a new `CookieJar` instance.
|
357 |
|
358 | The `store` argument is optional, but must be a _synchronous_ `Store` instance if specified. If not passed, a new instance of `MemoryCookieStore` is used.
|
359 |
|
360 | 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.
|
361 |
|
362 | ### `.removeAllCookies(cb(err))`
|
363 |
|
364 | Removes all cookies from the jar.
|
365 |
|
366 | This is a new backwards-compatible feature of `tough-cookie` version 2.5, so not all Stores will implement it efficiently. For Stores that do not implement `removeAllCookies`, the fallback is to call `removeCookie` after `getAllCookies`. If `getAllCookies` fails or isn't implemented in the Store, that error is returned. If one or more of the `removeCookie` calls fail, only the first error is returned.
|
367 |
|
368 | ### `.removeAllCookiesSync()`
|
369 |
|
370 | Sync version of `.removeAllCookies()`
|
371 |
|
372 | ## Store
|
373 |
|
374 | Base class for CookieJar stores. Available as `tough.Store`.
|
375 |
|
376 | ## Store API
|
377 |
|
378 | 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.
|
379 |
|
380 | Stores should inherit from the base `Store` class, which is available as `require('tough-cookie').Store`.
|
381 |
|
382 | 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
|
383 |
|
384 | All `domain` parameters will have been normalized before calling.
|
385 |
|
386 | The Cookie store must have all of the following methods.
|
387 |
|
388 | ### `store.findCookie(domain, path, key, cb(err,cookie))`
|
389 |
|
390 | 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.
|
391 |
|
392 | Callback takes an error and the resulting `Cookie` object. If no cookie is found then `null` MUST be passed instead (i.e. not an error).
|
393 |
|
394 | ### `store.findCookies(domain, path, cb(err,cookies))`
|
395 |
|
396 | Locates cookies matching the given domain and path. This is most often called in the context of `cookiejar.getCookies()` above.
|
397 |
|
398 | If no cookies are found, the callback MUST be passed an empty array.
|
399 |
|
400 | The resulting list will be checked for applicability to the current request according to the RFC (domain-match, path-match, http-only-flag, secure-flag, expiry, etc.), so it's OK to use an optimistic search algorithm when implementing this method. However, the search algorithm used SHOULD try to find cookies that `domainMatch()` the domain and `pathMatch()` the path in order to limit the amount of checking that needs to be done.
|
401 |
|
402 | As of version 0.9.12, the `allPaths` option to `cookiejar.getCookies()` above will cause the path here to be `null`. If the path is `null`, path-matching MUST NOT be performed (i.e. domain-matching only).
|
403 |
|
404 | ### `store.putCookie(cookie, cb(err))`
|
405 |
|
406 | 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.
|
407 |
|
408 | The `cookie` object MUST NOT be modified; the caller will have already updated the `.creation` and `.lastAccessed` properties.
|
409 |
|
410 | Pass an error if the cookie cannot be stored.
|
411 |
|
412 | ### `store.updateCookie(oldCookie, newCookie, cb(err))`
|
413 |
|
414 | 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.
|
415 |
|
416 | 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).
|
417 |
|
418 | 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.
|
419 |
|
420 | The `newCookie` and `oldCookie` objects MUST NOT be modified.
|
421 |
|
422 | Pass an error if the newCookie cannot be stored.
|
423 |
|
424 | ### `store.removeCookie(domain, path, key, cb(err))`
|
425 |
|
426 | Remove a cookie from the store (see notes on `findCookie` about the uniqueness constraint).
|
427 |
|
428 | The implementation MUST NOT pass an error if the cookie doesn't exist; only pass an error due to the failure to remove an existing cookie.
|
429 |
|
430 | ### `store.removeCookies(domain, path, cb(err))`
|
431 |
|
432 | Removes matching cookies from the store. The `path` parameter is optional, and if missing means all paths in a domain should be removed.
|
433 |
|
434 | Pass an error ONLY if removing any existing cookies failed.
|
435 |
|
436 | ### `store.removeAllCookies(cb(err))`
|
437 |
|
438 | _Optional_. Removes all cookies from the store.
|
439 |
|
440 | Pass an error if one or more cookies can't be removed.
|
441 |
|
442 | **Note**: New method as of `tough-cookie` version 2.5, so not all Stores will implement this, plus some stores may choose not to implement this.
|
443 |
|
444 | ### `store.getAllCookies(cb(err, cookies))`
|
445 |
|
446 | _Optional_. 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.
|
447 |
|
448 | 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.
|
449 |
|
450 | Pass an error if retrieval fails.
|
451 |
|
452 | **Note**: not all Stores can implement this due to technical limitations, so it is optional.
|
453 |
|
454 | ## MemoryCookieStore
|
455 |
|
456 | Inherits from `Store`.
|
457 |
|
458 | 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. Supports serialization, `getAllCookies`, and `removeAllCookies`.
|
459 |
|
460 | ## Community Cookie Stores
|
461 |
|
462 | These are some Store implementations authored and maintained by the community. They aren't official and we don't vouch for them but you may be interested to have a look:
|
463 |
|
464 | - [`db-cookie-store`](https://github.com/JSBizon/db-cookie-store): SQL including SQLite-based databases
|
465 | - [`file-cookie-store`](https://github.com/JSBizon/file-cookie-store): Netscape cookie file format on disk
|
466 | - [`redis-cookie-store`](https://github.com/benkroeger/redis-cookie-store): Redis
|
467 | - [`tough-cookie-filestore`](https://github.com/mitsuru/tough-cookie-filestore): JSON on disk
|
468 | - [`tough-cookie-web-storage-store`](https://github.com/exponentjs/tough-cookie-web-storage-store): DOM localStorage and sessionStorage
|
469 |
|
470 |
|
471 | # Serialization Format
|
472 |
|
473 | **NOTE**: if you want to have custom `Cookie` properties serialized, add the property name to `Cookie.serializableProperties`.
|
474 |
|
475 | ```js
|
476 | {
|
477 | // The version of tough-cookie that serialized this jar.
|
478 | version: 'tough-cookie@1.x.y',
|
479 |
|
480 | // add the store type, to make humans happy:
|
481 | storeType: 'MemoryCookieStore',
|
482 |
|
483 | // CookieJar configuration:
|
484 | rejectPublicSuffixes: true,
|
485 | // ... future items go here
|
486 |
|
487 | // Gets filled from jar.store.getAllCookies():
|
488 | cookies: [
|
489 | {
|
490 | key: 'string',
|
491 | value: 'string',
|
492 | // ...
|
493 | /* other Cookie.serializableProperties go here */
|
494 | }
|
495 | ]
|
496 | }
|
497 | ```
|
498 |
|
499 | # RFC6265bis
|
500 |
|
501 | Support for RFC6265bis revision 02 is being developed. Since this is a bit of an omnibus revision to the RFC6252, support is broken up into the functional areas.
|
502 |
|
503 | ## Leave Secure Cookies Alone
|
504 |
|
505 | Not yet supported.
|
506 |
|
507 | This change makes it so that if a cookie is sent from the server to the client with a `Secure` attribute, the channel must also be secure or the cookie is ignored.
|
508 |
|
509 | ## SameSite Cookies
|
510 |
|
511 | Supported.
|
512 |
|
513 | This change makes it possible for servers, and supporting clients, to mitigate certain types of CSRF attacks by disallowing `SameSite` cookies from being sent cross-origin.
|
514 |
|
515 | On the Cookie object itself, you can get/set the `.sameSite` attribute, which will be serialized into the `SameSite=` cookie attribute. When unset or `undefined`, no `SameSite=` attribute will be serialized. The valid values of this attribute are `'none'`, `'lax'`, or `'strict'`. Other values will be serialized as-is.
|
516 |
|
517 | When parsing cookies with a `SameSite` cookie attribute, values other than `'lax'` or `'strict'` are parsed as `'none'`. For example, `SomeCookie=SomeValue; SameSite=garbage` will parse so that `cookie.sameSite === 'none'`.
|
518 |
|
519 | In order to support SameSite cookies, you must provide a `sameSiteContext` option to _both_ `setCookie` and `getCookies`. Valid values for this option are just like for the Cookie object, but have particular meanings:
|
520 | 1. `'strict'` mode - If the request is on the same "site for cookies" (see the RFC draft for what this means), pass this option to add a layer of defense against CSRF.
|
521 | 2. `'lax'` mode - If the request is from another site, _but_ is directly because of navigation by the user, e.g., `<link type=prefetch>` or `<a href="...">`, pass `sameSiteContext: 'lax'`.
|
522 | 3. `'none'` - Otherwise, pass `sameSiteContext: 'none'` (this indicates a cross-origin request).
|
523 | 4. unset/`undefined` - SameSite **will not** be enforced! This can be a valid use-case for when CSRF isn't in the threat model of the system being built.
|
524 |
|
525 | It is highly recommended that you read RFC 6265bis for fine details on SameSite cookies. In particular [Section 8.8](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02#section-8.8) discusses security considerations and defense in depth.
|
526 |
|
527 | ## Cookie Prefixes
|
528 |
|
529 | Supported.
|
530 |
|
531 | Cookie prefixes are a way to indicate that a given cookie was set with a set of attributes simply by inspecting the first few characters of the cookie's name.
|
532 |
|
533 | Cookie prefixes are defined in [Section 4.1.3 of 6265bis](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.3). Two prefixes are defined:
|
534 |
|
535 | 1. `"__Secure-" Prefix`: If a cookie's name begins with a case-sensitive match for the string "__Secure-", then the cookie will have been set with a "Secure" attribute.
|
536 | 2. `"__Host-" Prefix`: If a cookie's name begins with a case-sensitive match for the string "__Host-", then the cookie will have been set with a "Secure" attribute, a "Path" attribute with a value of "/", and no "Domain" attribute.
|
537 |
|
538 | If `prefixSecurity` is enabled for `CookieJar`, then cookies that match the prefixes defined above but do not obey the attribute restrictions will not be added.
|
539 |
|
540 | You can define this functionality by passing in `prefixSecurity` option to `CookieJar`. It can be one of 3 values:
|
541 |
|
542 | 1. `silent`: Enable cookie prefix checking but silently fail to add the cookie if conditions not met. Default.
|
543 | 2. `strict`: Enable cookie prefix checking and error out if conditions not met.
|
544 | 3. `unsafe-disabled`: Disable cookie prefix checking.
|
545 |
|
546 | Note that if `ignoreError` is passed in as `true` then the error will be silent regardless of `prefixSecurity` option (assuming it's enabled).
|
547 |
|
548 |
|
549 | # Copyright and License
|
550 |
|
551 | BSD-3-Clause:
|
552 |
|
553 | ```text
|
554 | Copyright (c) 2015, Salesforce.com, Inc.
|
555 | All rights reserved.
|
556 |
|
557 | Redistribution and use in source and binary forms, with or without
|
558 | modification, are permitted provided that the following conditions are met:
|
559 |
|
560 | 1. Redistributions of source code must retain the above copyright notice,
|
561 | this list of conditions and the following disclaimer.
|
562 |
|
563 | 2. Redistributions in binary form must reproduce the above copyright notice,
|
564 | this list of conditions and the following disclaimer in the documentation
|
565 | and/or other materials provided with the distribution.
|
566 |
|
567 | 3. Neither the name of Salesforce.com nor the names of its contributors may
|
568 | be used to endorse or promote products derived from this software without
|
569 | specific prior written permission.
|
570 |
|
571 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
572 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
573 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
574 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
575 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
576 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
577 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
578 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
579 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
580 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
581 | POSSIBILITY OF SUCH DAMAGE.
|
582 | ```
|