tough-cookie 5.0.0-rc.4 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,33 @@
1
+ import type { Nullable } from '../utils';
2
+ /**
3
+ * Transforms a domain name into a canonical domain name. The canonical domain name is a domain name
4
+ * that has been trimmed, lowercased, stripped of leading dot, and optionally punycode-encoded
5
+ * ({@link https://www.rfc-editor.org/rfc/rfc6265.html#section-5.1.2 | Section 5.1.2 of RFC 6265}). For
6
+ * the most part, this function is idempotent (calling the function with the output from a previous call
7
+ * returns the same output).
8
+ *
9
+ * @remarks
10
+ * A canonicalized host name is the string generated by the following
11
+ * algorithm:
12
+ *
13
+ * 1. Convert the host name to a sequence of individual domain name
14
+ * labels.
15
+ *
16
+ * 2. Convert each label that is not a Non-Reserved LDH (NR-LDH) label,
17
+ * to an A-label (see Section 2.3.2.1 of [RFC5890] for the former
18
+ * and latter), or to a "punycode label" (a label resulting from the
19
+ * "ToASCII" conversion in Section 4 of [RFC3490]), as appropriate
20
+ * (see Section 6.3 of this specification).
21
+ *
22
+ * 3. Concatenate the resulting labels, separated by a %x2E (".")
23
+ * character.
24
+ *
25
+ * @example
26
+ * ```
27
+ * canonicalDomain('.EXAMPLE.com') === 'example.com'
28
+ * ```
29
+ *
30
+ * @param domainName - the domain name to generate the canonical domain from
31
+ * @public
32
+ */
33
+ export declare function canonicalDomain(domainName: Nullable<string>): string | undefined;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.canonicalDomain = canonicalDomain;
4
4
  const constants_1 = require("./constants");
5
+ const node_url_1 = require("node:url");
5
6
  /**
6
7
  * Transforms a domain name into a canonical domain name. The canonical domain name is a domain name
7
8
  * that has been trimmed, lowercased, stripped of leading dot, and optionally punycode-encoded
@@ -45,12 +46,12 @@ function canonicalDomain(domainName) {
45
46
  if (!str.endsWith(']')) {
46
47
  str = str + ']';
47
48
  }
48
- return new URL(`http://${str}`).hostname.slice(1, -1); // remove [ and ]
49
+ return (0, node_url_1.domainToASCII)(str).slice(1, -1); // remove [ and ]
49
50
  }
50
51
  // convert to IDN if any non-ASCII characters
51
52
  // eslint-disable-next-line no-control-regex
52
53
  if (/[^\u0001-\u007f]/.test(str)) {
53
- return new URL(`http://${str}`).hostname;
54
+ return (0, node_url_1.domainToASCII)(str);
54
55
  }
55
56
  // ASCII-only domain - not canonicalized with new URL() because it may be a malformed URL
56
57
  return str.toLowerCase();
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Cookie prefixes are a way to indicate that a given cookie was set with a set of attributes simply by inspecting the
3
+ * first few characters of the cookie's name. These are defined in {@link https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-13#section-4.1.3 | RFC6265bis - Section 4.1.3}.
4
+ *
5
+ * The following values can be used to configure how a {@link CookieJar} enforces attribute restrictions for Cookie prefixes:
6
+ *
7
+ * - `silent` - Enable cookie prefix checking but silently ignores the cookie if conditions are not met. This is the default configuration for a {@link CookieJar}.
8
+ *
9
+ * - `strict` - Enables cookie prefix checking and will raise an error if conditions are not met.
10
+ *
11
+ * - `unsafe-disabled` - Disables cookie prefix checking.
12
+ * @public
13
+ */
14
+ export declare const PrefixSecurityEnum: Readonly<{
15
+ SILENT: "silent";
16
+ STRICT: "strict";
17
+ DISABLED: "unsafe-disabled";
18
+ }>;
19
+ export declare const IP_V6_REGEX_OBJECT: RegExp;
20
+ /**
21
+ * A JSON representation of a {@link CookieJar}.
22
+ * @public
23
+ */
24
+ export interface SerializedCookieJar {
25
+ /**
26
+ * The version of `tough-cookie` used during serialization.
27
+ */
28
+ version: string;
29
+ /**
30
+ * The name of the store used during serialization.
31
+ */
32
+ storeType: string | null;
33
+ /**
34
+ * The value of {@link CreateCookieJarOptions.rejectPublicSuffixes} configured on the {@link CookieJar}.
35
+ */
36
+ rejectPublicSuffixes: boolean;
37
+ /**
38
+ * Other configuration settings on the {@link CookieJar}.
39
+ */
40
+ [key: string]: unknown;
41
+ /**
42
+ * The list of {@link Cookie} values serialized as JSON objects.
43
+ */
44
+ cookies: SerializedCookie[];
45
+ }
46
+ /**
47
+ * A JSON object that is created when {@link Cookie.toJSON} is called. This object will contain the properties defined in {@link Cookie.serializableProperties}.
48
+ * @public
49
+ */
50
+ export type SerializedCookie = {
51
+ key?: string;
52
+ value?: string;
53
+ [key: string]: unknown;
54
+ };
@@ -0,0 +1,315 @@
1
+ import type { SerializedCookie } from './constants';
2
+ /**
3
+ * Optional configuration to be used when parsing cookies.
4
+ * @public
5
+ */
6
+ export interface ParseCookieOptions {
7
+ /**
8
+ * If `true` then keyless cookies like `=abc` and `=` which are not RFC-compliant will be parsed.
9
+ */
10
+ loose?: boolean | undefined;
11
+ }
12
+ /**
13
+ * Configurable values that can be set when creating a {@link Cookie}.
14
+ * @public
15
+ */
16
+ export interface CreateCookieOptions {
17
+ /** {@inheritDoc Cookie.key} */
18
+ key?: string;
19
+ /** {@inheritDoc Cookie.value} */
20
+ value?: string;
21
+ /** {@inheritDoc Cookie.expires} */
22
+ expires?: Date | 'Infinity' | null;
23
+ /** {@inheritDoc Cookie.maxAge} */
24
+ maxAge?: number | 'Infinity' | '-Infinity' | null;
25
+ /** {@inheritDoc Cookie.domain} */
26
+ domain?: string | null;
27
+ /** {@inheritDoc Cookie.path} */
28
+ path?: string | null;
29
+ /** {@inheritDoc Cookie.secure} */
30
+ secure?: boolean;
31
+ /** {@inheritDoc Cookie.httpOnly} */
32
+ httpOnly?: boolean;
33
+ /** {@inheritDoc Cookie.extensions} */
34
+ extensions?: string[] | null;
35
+ /** {@inheritDoc Cookie.creation} */
36
+ creation?: Date | 'Infinity' | null;
37
+ /** {@inheritDoc Cookie.hostOnly} */
38
+ hostOnly?: boolean | null;
39
+ /** {@inheritDoc Cookie.pathIsDefault} */
40
+ pathIsDefault?: boolean | null;
41
+ /** {@inheritDoc Cookie.lastAccessed} */
42
+ lastAccessed?: Date | 'Infinity' | null;
43
+ /** {@inheritDoc Cookie.sameSite} */
44
+ sameSite?: string | undefined;
45
+ }
46
+ /**
47
+ * An HTTP cookie (web cookie, browser cookie) is a small piece of data that a server sends to a user's web browser.
48
+ * It is defined in {@link https://www.rfc-editor.org/rfc/rfc6265.html | RFC6265}.
49
+ * @public
50
+ */
51
+ export declare class Cookie {
52
+ /**
53
+ * The name or key of the cookie
54
+ */
55
+ key: string;
56
+ /**
57
+ * The value of the cookie
58
+ */
59
+ value: string;
60
+ /**
61
+ * The 'Expires' attribute of the cookie
62
+ * (See {@link https://www.rfc-editor.org/rfc/rfc6265.html#section-5.2.1 | RFC6265 Section 5.2.1}).
63
+ */
64
+ expires: Date | 'Infinity' | null;
65
+ /**
66
+ * The 'Max-Age' attribute of the cookie
67
+ * (See {@link https://www.rfc-editor.org/rfc/rfc6265.html#section-5.2.2 | RFC6265 Section 5.2.2}).
68
+ */
69
+ maxAge: number | 'Infinity' | '-Infinity' | null;
70
+ /**
71
+ * The 'Domain' attribute of the cookie represents the domain the cookie belongs to
72
+ * (See {@link https://www.rfc-editor.org/rfc/rfc6265.html#section-5.2.3 | RFC6265 Section 5.2.3}).
73
+ */
74
+ domain: string | null;
75
+ /**
76
+ * The 'Path' attribute of the cookie represents the path of the cookie
77
+ * (See {@link https://www.rfc-editor.org/rfc/rfc6265.html#section-5.2.4 | RFC6265 Section 5.2.4}).
78
+ */
79
+ path: string | null;
80
+ /**
81
+ * The 'Secure' flag of the cookie indicates if the scope of the cookie is
82
+ * limited to secure channels (e.g.; HTTPS) or not
83
+ * (See {@link https://www.rfc-editor.org/rfc/rfc6265.html#section-5.2.5 | RFC6265 Section 5.2.5}).
84
+ */
85
+ secure: boolean;
86
+ /**
87
+ * The 'HttpOnly' flag of the cookie indicates if the cookie is inaccessible to
88
+ * client scripts or not
89
+ * (See {@link https://www.rfc-editor.org/rfc/rfc6265.html#section-5.2.6 | RFC6265 Section 5.2.6}).
90
+ */
91
+ httpOnly: boolean;
92
+ /**
93
+ * Contains attributes which are not part of the defined spec but match the `extension-av` syntax
94
+ * defined in Section 4.1.1 of RFC6265
95
+ * (See {@link https://www.rfc-editor.org/rfc/rfc6265.html#section-4.1.1 | RFC6265 Section 4.1.1}).
96
+ */
97
+ extensions: string[] | null;
98
+ /**
99
+ * Set to the date and time when a Cookie is initially stored or a matching cookie is
100
+ * received that replaces an existing cookie
101
+ * (See {@link https://www.rfc-editor.org/rfc/rfc6265.html#section-5.3 | RFC6265 Section 5.3}).
102
+ *
103
+ * Also used to maintain ordering among cookies. Among cookies that have equal-length path fields,
104
+ * cookies with earlier creation-times are listed before cookies with later creation-times
105
+ * (See {@link https://www.rfc-editor.org/rfc/rfc6265.html#section-5.4 | RFC6265 Section 5.4}).
106
+ */
107
+ creation: Date | 'Infinity' | null;
108
+ /**
109
+ * A global counter used to break ordering ties between two cookies that have equal-length path fields
110
+ * and the same creation-time.
111
+ */
112
+ creationIndex: number;
113
+ /**
114
+ * A boolean flag indicating if a cookie is a host-only cookie (i.e.; when the request's host exactly
115
+ * matches the domain of the cookie) or not
116
+ * (See {@link https://www.rfc-editor.org/rfc/rfc6265.html#section-5.3 | RFC6265 Section 5.3}).
117
+ */
118
+ hostOnly: boolean | null;
119
+ /**
120
+ * A boolean flag indicating if a cookie had no 'Path' attribute and the default path
121
+ * was used
122
+ * (See {@link https://www.rfc-editor.org/rfc/rfc6265.html#section-5.2.4 | RFC6265 Section 5.2.4}).
123
+ */
124
+ pathIsDefault: boolean | null;
125
+ /**
126
+ * Set to the date and time when a cookie was initially stored ({@link https://www.rfc-editor.org/rfc/rfc6265.html#section-5.3 | RFC6265 Section 5.3}) and updated whenever
127
+ * the cookie is retrieved from the {@link CookieJar} ({@link https://www.rfc-editor.org/rfc/rfc6265.html#section-5.4 | RFC6265 Section 5.4}).
128
+ */
129
+ lastAccessed: Date | 'Infinity' | null;
130
+ /**
131
+ * The 'SameSite' attribute of a cookie as defined in RFC6265bis
132
+ * (See {@link https://www.ietf.org/archive/id/draft-ietf-httpbis-rfc6265bis-13.html#section-5.2 | RFC6265bis (v13) Section 5.2 }).
133
+ */
134
+ sameSite: string | undefined;
135
+ /**
136
+ * Create a new Cookie instance.
137
+ * @public
138
+ * @param options - The attributes to set on the cookie
139
+ */
140
+ constructor(options?: CreateCookieOptions);
141
+ /**
142
+ * For convenience in using `JSON.stringify(cookie)`. Returns a plain-old Object that can be JSON-serialized.
143
+ *
144
+ * @remarks
145
+ * - Any `Date` properties (such as {@link Cookie.expires}, {@link Cookie.creation}, and {@link Cookie.lastAccessed}) are exported in ISO format (`Date.toISOString()`).
146
+ *
147
+ * - Custom Cookie properties are discarded. In tough-cookie 1.x, since there was no {@link Cookie.toJSON} method explicitly defined, all enumerable properties were captured.
148
+ * If you want a property to be serialized, add the property name to {@link Cookie.serializableProperties}.
149
+ */
150
+ toJSON(): SerializedCookie;
151
+ /**
152
+ * Does a deep clone of this cookie, implemented exactly as `Cookie.fromJSON(cookie.toJSON())`.
153
+ * @public
154
+ */
155
+ clone(): Cookie | undefined;
156
+ /**
157
+ * Validates cookie attributes for semantic correctness. Useful for "lint" checking any `Set-Cookie` headers you generate.
158
+ * For now, it returns a boolean, but eventually could return a reason string.
159
+ *
160
+ * @remarks
161
+ * Works for a few things, but is by no means comprehensive.
162
+ *
163
+ * @beta
164
+ */
165
+ validate(): boolean;
166
+ /**
167
+ * Sets the 'Expires' attribute on a cookie.
168
+ *
169
+ * @remarks
170
+ * When given a `string` value it will be parsed with {@link parseDate}. If the value can't be parsed as a cookie date
171
+ * then the 'Expires' attribute will be set to `"Infinity"`.
172
+ *
173
+ * @param exp - the new value for the 'Expires' attribute of the cookie.
174
+ */
175
+ setExpires(exp: string | Date): void;
176
+ /**
177
+ * Sets the 'Max-Age' attribute (in seconds) on a cookie.
178
+ *
179
+ * @remarks
180
+ * Coerces `-Infinity` to `"-Infinity"` and `Infinity` to `"Infinity"` so it can be serialized to JSON.
181
+ *
182
+ * @param age - the new value for the 'Max-Age' attribute (in seconds).
183
+ */
184
+ setMaxAge(age: number): void;
185
+ /**
186
+ * Encodes to a `Cookie` header value (specifically, the {@link Cookie.key} and {@link Cookie.value} properties joined with "=").
187
+ * @public
188
+ */
189
+ cookieString(): string;
190
+ /**
191
+ * Encodes to a `Set-Cookie header` value.
192
+ * @public
193
+ */
194
+ toString(): string;
195
+ /**
196
+ * Computes the TTL relative to now (milliseconds).
197
+ *
198
+ * @remarks
199
+ * - `Infinity` is returned for cookies without an explicit expiry
200
+ *
201
+ * - `0` is returned if the cookie is expired.
202
+ *
203
+ * - Otherwise a time-to-live in milliseconds is returned.
204
+ *
205
+ * @param now - passing an explicit value is mostly used for testing purposes since this defaults to the `Date.now()`
206
+ * @public
207
+ */
208
+ TTL(now?: number): number;
209
+ /**
210
+ * Computes the absolute unix-epoch milliseconds that this cookie expires.
211
+ *
212
+ * The "Max-Age" attribute takes precedence over "Expires" (as per the RFC). The {@link Cookie.lastAccessed} attribute
213
+ * (or the `now` parameter if given) is used to offset the {@link Cookie.maxAge} attribute.
214
+ *
215
+ * If Expires ({@link Cookie.expires}) is set, that's returned.
216
+ *
217
+ * @param now - can be used to provide a time offset (instead of {@link Cookie.lastAccessed}) to use when calculating the "Max-Age" value
218
+ */
219
+ expiryTime(now?: Date): number | undefined;
220
+ /**
221
+ * Indicates if the cookie has been persisted to a store or not.
222
+ * @public
223
+ */
224
+ isPersistent(): boolean;
225
+ /**
226
+ * Calls {@link canonicalDomain} with the {@link Cookie.domain} property.
227
+ * @public
228
+ */
229
+ canonicalizedDomain(): string | undefined;
230
+ /**
231
+ * Alias for {@link Cookie.canonicalizedDomain}
232
+ * @public
233
+ */
234
+ cdomain(): string | undefined;
235
+ /**
236
+ * Parses a string into a Cookie object.
237
+ *
238
+ * @remarks
239
+ * Note: when parsing a `Cookie` header it must be split by ';' before each Cookie string can be parsed.
240
+ *
241
+ * @example
242
+ * ```
243
+ * // parse a `Set-Cookie` header
244
+ * const setCookieHeader = 'a=bcd; Expires=Tue, 18 Oct 2011 07:05:03 GMT'
245
+ * const cookie = Cookie.parse(setCookieHeader)
246
+ * cookie.key === 'a'
247
+ * cookie.value === 'bcd'
248
+ * cookie.expires === new Date(Date.parse('Tue, 18 Oct 2011 07:05:03 GMT'))
249
+ * ```
250
+ *
251
+ * @example
252
+ * ```
253
+ * // parse a `Cookie` header
254
+ * const cookieHeader = 'name=value; name2=value2; name3=value3'
255
+ * const cookies = cookieHeader.split(';').map(Cookie.parse)
256
+ * cookies[0].name === 'name'
257
+ * cookies[0].value === 'value'
258
+ * cookies[1].name === 'name2'
259
+ * cookies[1].value === 'value2'
260
+ * cookies[2].name === 'name3'
261
+ * cookies[2].value === 'value3'
262
+ * ```
263
+ *
264
+ * @param str - The `Set-Cookie` header or a Cookie string to parse.
265
+ * @param options - Configures `strict` or `loose` mode for cookie parsing
266
+ */
267
+ static parse(str: string, options?: ParseCookieOptions): Cookie | undefined;
268
+ /**
269
+ * Does the reverse of {@link Cookie.toJSON}.
270
+ *
271
+ * @remarks
272
+ * Any Date properties (such as .expires, .creation, and .lastAccessed) are parsed via Date.parse, not tough-cookie's parseDate, since ISO timestamps are being handled at this layer.
273
+ *
274
+ * @example
275
+ * ```
276
+ * const json = JSON.stringify({
277
+ * key: 'alpha',
278
+ * value: 'beta',
279
+ * domain: 'example.com',
280
+ * path: '/foo',
281
+ * expires: '2038-01-19T03:14:07.000Z',
282
+ * })
283
+ * const cookie = Cookie.fromJSON(json)
284
+ * cookie.key === 'alpha'
285
+ * cookie.value === 'beta'
286
+ * cookie.domain === 'example.com'
287
+ * cookie.path === '/foo'
288
+ * cookie.expires === new Date(Date.parse('2038-01-19T03:14:07.000Z'))
289
+ * ```
290
+ *
291
+ * @param str - An unparsed JSON string or a value that has already been parsed as JSON
292
+ */
293
+ static fromJSON(str: unknown): Cookie | undefined;
294
+ private static cookiesCreated;
295
+ /**
296
+ * @internal
297
+ */
298
+ static sameSiteLevel: {
299
+ readonly strict: 3;
300
+ readonly lax: 2;
301
+ readonly none: 1;
302
+ };
303
+ /**
304
+ * @internal
305
+ */
306
+ static sameSiteCanonical: {
307
+ readonly strict: "Strict";
308
+ readonly lax: "Lax";
309
+ };
310
+ /**
311
+ * Cookie properties that will be serialized when using {@link Cookie.fromJSON} and {@link Cookie.toJSON}.
312
+ * @public
313
+ */
314
+ static serializableProperties: readonly ["key", "value", "expires", "maxAge", "domain", "path", "secure", "httpOnly", "extensions", "hostOnly", "pathIsDefault", "creation", "lastAccessed", "sameSite"];
315
+ }
@@ -90,7 +90,7 @@ function parseCookiePair(cookiePair, looseMode) {
90
90
  if (looseMode) {
91
91
  if (firstEq === 0) {
92
92
  // '=' is immediately at start
93
- cookiePair = cookiePair.substr(1);
93
+ cookiePair = cookiePair.substring(1);
94
94
  firstEq = cookiePair.indexOf('='); // might still need to split on '='
95
95
  }
96
96
  }
@@ -267,7 +267,7 @@ function fromJSON(str) {
267
267
  try {
268
268
  obj = JSON.parse(str);
269
269
  }
270
- catch (e) {
270
+ catch {
271
271
  return undefined;
272
272
  }
273
273
  }
@@ -0,0 +1,58 @@
1
+ import type { Cookie } from './cookie';
2
+ /**
3
+ * A comparison function that can be used with {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort | Array.sort()},
4
+ * which orders a list of cookies into the recommended order given in Step 2 of {@link https://www.rfc-editor.org/rfc/rfc6265.html#section-5.4 | RFC6265 - Section 5.4}.
5
+ *
6
+ * The sort algorithm is, in order of precedence:
7
+ *
8
+ * - Longest {@link Cookie.path}
9
+ *
10
+ * - Oldest {@link Cookie.creation} (which has a 1-ms precision, same as Date)
11
+ *
12
+ * - Lowest {@link Cookie.creationIndex} (to get beyond the 1-ms precision)
13
+ *
14
+ * @remarks
15
+ * ### RFC6265 - Section 5.4 - Step 2
16
+ *
17
+ * The user agent SHOULD sort the cookie-list in the following order:
18
+ *
19
+ * - Cookies with longer paths are listed before cookies with shorter paths.
20
+ *
21
+ * - Among cookies that have equal-length path fields, cookies with
22
+ * earlier creation-times are listed before cookies with later
23
+ * creation-times.
24
+ *
25
+ * NOTE: Not all user agents sort the cookie-list in this order, but
26
+ * this order reflects common practice when this document was
27
+ * written, and, historically, there have been servers that
28
+ * (erroneously) depended on this order.
29
+ *
30
+ * ### Custom Store Implementors
31
+ *
32
+ * Since the JavaScript Date is limited to a 1-ms precision, cookies within the same millisecond are entirely possible.
33
+ * This is especially true when using the `now` option to `CookieJar.setCookie(...)`. The {@link Cookie.creationIndex}
34
+ * property is a per-process global counter, assigned during construction with `new Cookie()`, which preserves the spirit
35
+ * of the RFC sorting: older cookies go first. This works great for {@link MemoryCookieStore} since `Set-Cookie` headers
36
+ * are parsed in order, but is not so great for distributed systems.
37
+ *
38
+ * Sophisticated Stores may wish to set this to some other
39
+ * logical clock so that if cookies `A` and `B` are created in the same millisecond, but cookie `A` is created before
40
+ * cookie `B`, then `A.creationIndex < B.creationIndex`.
41
+ *
42
+ * @example
43
+ * ```
44
+ * const cookies = [
45
+ * new Cookie({ key: 'a', value: '' }),
46
+ * new Cookie({ key: 'b', value: '' }),
47
+ * new Cookie({ key: 'c', value: '', path: '/path' }),
48
+ * new Cookie({ key: 'd', value: '', path: '/path' }),
49
+ * ]
50
+ * cookies.sort(cookieCompare)
51
+ * // cookie sort order would be ['c', 'd', 'a', 'b']
52
+ * ```
53
+ *
54
+ * @param a - the first Cookie for comparison
55
+ * @param b - the second Cookie for comparison
56
+ * @public
57
+ */
58
+ export declare function cookieCompare(a: Cookie, b: Cookie): number;