tough-cookie 4.0.0 → 4.1.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.
package/lib/cookie.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2015, Salesforce.com, Inc.
2
+ * Copyright (c) 2015-2020, Salesforce.com, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * Redistribution and use in source and binary forms, with or without
@@ -29,15 +29,16 @@
29
29
  * POSSIBILITY OF SUCH DAMAGE.
30
30
  */
31
31
  "use strict";
32
- const punycode = require("punycode");
33
- const urlParse = require("url").parse;
34
- const util = require("util");
32
+ const punycode = require("punycode/");
33
+ const urlParse = require("url-parse");
35
34
  const pubsuffix = require("./pubsuffix-psl");
36
35
  const Store = require("./store").Store;
37
36
  const MemoryCookieStore = require("./memstore").MemoryCookieStore;
38
37
  const pathMatch = require("./pathMatch").pathMatch;
38
+ const validators = require("./validators.js");
39
39
  const VERSION = require("./version");
40
40
  const { fromCallback } = require("universalify");
41
+ const { getCustomInspectSymbol } = require("./utilHelper");
41
42
 
42
43
  // From RFC6265 S4.1.1
43
44
  // note that it excludes \x3B ";"
@@ -79,6 +80,7 @@ const SAME_SITE_CONTEXT_VAL_ERR =
79
80
  'Invalid sameSiteContext option for getCookies(); expected one of "strict", "lax", or "none"';
80
81
 
81
82
  function checkSameSiteContext(value) {
83
+ validators.validate(validators.isNonEmptyString(value), value);
82
84
  const context = String(value).toLowerCase();
83
85
  if (context === "none" || context === "lax" || context === "strict") {
84
86
  return context;
@@ -97,7 +99,23 @@ const PrefixSecurityEnum = Object.freeze({
97
99
  // * all capturing groups converted to non-capturing -- "(?:)"
98
100
  // * support for IPv6 Scoped Literal ("%eth1") removed
99
101
  // * lowercase hexadecimal only
100
- var IP_REGEX_LOWERCASE =/(?:^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$)|(?:^(?:(?:[a-f\d]{1,4}:){7}(?:[a-f\d]{1,4}|:)|(?:[a-f\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-f\d]{1,4}|:)|(?:[a-f\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,2}|:)|(?:[a-f\d]{1,4}:){4}(?:(?::[a-f\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,3}|:)|(?:[a-f\d]{1,4}:){3}(?:(?::[a-f\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,4}|:)|(?:[a-f\d]{1,4}:){2}(?:(?::[a-f\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,5}|:)|(?:[a-f\d]{1,4}:){1}(?:(?::[a-f\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,6}|:)|(?::(?:(?::[a-f\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,7}|:)))$)/;
102
+ const IP_REGEX_LOWERCASE = /(?:^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$)|(?:^(?:(?:[a-f\d]{1,4}:){7}(?:[a-f\d]{1,4}|:)|(?:[a-f\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-f\d]{1,4}|:)|(?:[a-f\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,2}|:)|(?:[a-f\d]{1,4}:){4}(?:(?::[a-f\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,3}|:)|(?:[a-f\d]{1,4}:){3}(?:(?::[a-f\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,4}|:)|(?:[a-f\d]{1,4}:){2}(?:(?::[a-f\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,5}|:)|(?:[a-f\d]{1,4}:){1}(?:(?::[a-f\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,6}|:)|(?::(?:(?::[a-f\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,7}|:)))$)/;
103
+ const IP_V6_REGEX = `
104
+ \\[?(?:
105
+ (?:[a-fA-F\\d]{1,4}:){7}(?:[a-fA-F\\d]{1,4}|:)|
106
+ (?:[a-fA-F\\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|:[a-fA-F\\d]{1,4}|:)|
107
+ (?:[a-fA-F\\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,2}|:)|
108
+ (?:[a-fA-F\\d]{1,4}:){4}(?:(?::[a-fA-F\\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,3}|:)|
109
+ (?:[a-fA-F\\d]{1,4}:){3}(?:(?::[a-fA-F\\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,4}|:)|
110
+ (?:[a-fA-F\\d]{1,4}:){2}(?:(?::[a-fA-F\\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,5}|:)|
111
+ (?:[a-fA-F\\d]{1,4}:){1}(?:(?::[a-fA-F\\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,6}|:)|
112
+ (?::(?:(?::[a-fA-F\\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,7}|:))
113
+ )(?:%[0-9a-zA-Z]{1,})?\\]?
114
+ `
115
+ .replace(/\s*\/\/.*$/gm, "")
116
+ .replace(/\n/g, "")
117
+ .trim();
118
+ const IP_V6_REGEX_OBJECT = new RegExp(`^${IP_V6_REGEX}$`);
101
119
 
102
120
  /*
103
121
  * Parses a Natural number (i.e., non-negative integer) with either the
@@ -301,6 +319,7 @@ function parseDate(str) {
301
319
  }
302
320
 
303
321
  function formatDate(date) {
322
+ validators.validate(validators.isDate(date), date);
304
323
  return date.toUTCString();
305
324
  }
306
325
 
@@ -311,6 +330,10 @@ function canonicalDomain(str) {
311
330
  }
312
331
  str = str.trim().replace(/^\./, ""); // S4.1.2.3 & S5.2.3: ignore leading .
313
332
 
333
+ if (IP_V6_REGEX_OBJECT.test(str)) {
334
+ str = str.replace("[", "").replace("]", "");
335
+ }
336
+
314
337
  // convert to IDN if any non-ASCII characters
315
338
  if (punycode && /[^\u0001-\u007f]/.test(str)) {
316
339
  str = punycode.toASCII(str);
@@ -345,7 +368,7 @@ function domainMatch(str, domStr, canonicalize) {
345
368
  /* " o All of the following [three] conditions hold:" */
346
369
 
347
370
  /* "* The domain string is a suffix of the string" */
348
- const idx = str.indexOf(domStr);
371
+ const idx = str.lastIndexOf(domStr);
349
372
  if (idx <= 0) {
350
373
  return false; // it's a non-match (-1) or prefix (0)
351
374
  }
@@ -359,7 +382,7 @@ function domainMatch(str, domStr, canonicalize) {
359
382
 
360
383
  /* " * The last character of the string that is not included in the
361
384
  * domain string is a %x2E (".") character." */
362
- if (str.substr(idx-1,1) !== '.') {
385
+ if (str.substr(idx - 1, 1) !== ".") {
363
386
  return false; // doesn't align on "."
364
387
  }
365
388
 
@@ -403,6 +426,7 @@ function defaultPath(path) {
403
426
  }
404
427
 
405
428
  function trimTerminator(str) {
429
+ if (validators.isEmptyString(str)) return str;
406
430
  for (let t = 0; t < TERMINATORS.length; t++) {
407
431
  const terminatorIdx = str.indexOf(TERMINATORS[t]);
408
432
  if (terminatorIdx !== -1) {
@@ -415,6 +439,7 @@ function trimTerminator(str) {
415
439
 
416
440
  function parseCookiePair(cookiePair, looseMode) {
417
441
  cookiePair = trimTerminator(cookiePair);
442
+ validators.validate(validators.isString(cookiePair), cookiePair);
418
443
 
419
444
  let firstEq = cookiePair.indexOf("=");
420
445
  if (looseMode) {
@@ -454,6 +479,11 @@ function parse(str, options) {
454
479
  if (!options || typeof options !== "object") {
455
480
  options = {};
456
481
  }
482
+
483
+ if (validators.isEmptyString(str) || !validators.isString(str)) {
484
+ return null;
485
+ }
486
+
457
487
  str = str.trim();
458
488
 
459
489
  // We use a regex to parse the "name-value-pair" part of S5.2
@@ -589,11 +619,11 @@ function parse(str, options) {
589
619
  case "lax":
590
620
  c.sameSite = "lax";
591
621
  break;
622
+ case "none":
623
+ c.sameSite = "none";
624
+ break;
592
625
  default:
593
- // RFC6265bis-02 S5.3.7 step 1:
594
- // "If cookie-av's attribute-value is not a case-insensitive match
595
- // for "Strict" or "Lax", ignore the "cookie-av"."
596
- // This effectively sets it to 'none' from the prototype.
626
+ c.sameSite = undefined;
597
627
  break;
598
628
  }
599
629
  break;
@@ -616,6 +646,7 @@ function parse(str, options) {
616
646
  * @returns boolean
617
647
  */
618
648
  function isSecurePrefixConditionMet(cookie) {
649
+ validators.validate(validators.isObject(cookie), cookie);
619
650
  return !cookie.key.startsWith("__Secure-") || cookie.secure;
620
651
  }
621
652
 
@@ -631,6 +662,7 @@ function isSecurePrefixConditionMet(cookie) {
631
662
  * @returns boolean
632
663
  */
633
664
  function isHostPrefixConditionMet(cookie) {
665
+ validators.validate(validators.isObject(cookie));
634
666
  return (
635
667
  !cookie.key.startsWith("__Host-") ||
636
668
  (cookie.secure &&
@@ -652,7 +684,7 @@ function jsonParse(str) {
652
684
  }
653
685
 
654
686
  function fromJSON(str) {
655
- if (!str) {
687
+ if (!str || validators.isEmptyString(str)) {
656
688
  return null;
657
689
  }
658
690
 
@@ -698,6 +730,8 @@ function fromJSON(str) {
698
730
  */
699
731
 
700
732
  function cookieCompare(a, b) {
733
+ validators.validate(validators.isObject(a), a);
734
+ validators.validate(validators.isObject(b), b);
701
735
  let cmp = 0;
702
736
 
703
737
  // descending for length: b CMP a
@@ -725,6 +759,7 @@ function cookieCompare(a, b) {
725
759
  // Gives the permutation of all possible pathMatch()es of a given path. The
726
760
  // array is in longest-to-shortest order. Handy for indexing.
727
761
  function permutePath(path) {
762
+ validators.validate(validators.isString(path));
728
763
  if (path === "/") {
729
764
  return ["/"];
730
765
  }
@@ -772,13 +807,14 @@ const cookieDefaults = {
772
807
  pathIsDefault: null,
773
808
  creation: null,
774
809
  lastAccessed: null,
775
- sameSite: "none"
810
+ sameSite: undefined
776
811
  };
777
812
 
778
813
  class Cookie {
779
814
  constructor(options = {}) {
780
- if (util.inspect.custom) {
781
- this[util.inspect.custom] = this.inspect;
815
+ const customInspectSymbol = getCustomInspectSymbol();
816
+ if (customInspectSymbol) {
817
+ this[customInspectSymbol] = this.inspect;
782
818
  }
783
819
 
784
820
  Object.assign(this, cookieDefaults, options);
@@ -1060,6 +1096,7 @@ class CookieJar {
1060
1096
  if (typeof options === "boolean") {
1061
1097
  options = { rejectPublicSuffixes: options };
1062
1098
  }
1099
+ validators.validate(validators.isObject(options), options);
1063
1100
  this.rejectPublicSuffixes = options.rejectPublicSuffixes;
1064
1101
  this.enableLooseMode = !!options.looseMode;
1065
1102
  this.allowSpecialUseDomain = !!options.allowSpecialUseDomain;
@@ -1076,13 +1113,31 @@ class CookieJar {
1076
1113
  }
1077
1114
 
1078
1115
  setCookie(cookie, url, options, cb) {
1116
+ validators.validate(validators.isNonEmptyString(url), cb, options);
1079
1117
  let err;
1118
+
1119
+ if (validators.isFunction(url)) {
1120
+ cb = url;
1121
+ return cb(new Error("No URL was specified"));
1122
+ }
1123
+
1080
1124
  const context = getCookieContext(url);
1081
- if (typeof options === "function") {
1125
+ if (validators.isFunction(options)) {
1082
1126
  cb = options;
1083
1127
  options = {};
1084
1128
  }
1085
1129
 
1130
+ validators.validate(validators.isFunction(cb), cb);
1131
+
1132
+ if (
1133
+ !validators.isNonEmptyString(cookie) &&
1134
+ !validators.isObject(cookie) &&
1135
+ cookie instanceof String &&
1136
+ cookie.length == 0
1137
+ ) {
1138
+ return cb(null);
1139
+ }
1140
+
1086
1141
  const host = canonicalDomain(context.hostname);
1087
1142
  const loose = options.loose || this.enableLooseMode;
1088
1143
 
@@ -1119,8 +1174,11 @@ class CookieJar {
1119
1174
 
1120
1175
  // S5.3 step 5: public suffixes
1121
1176
  if (this.rejectPublicSuffixes && cookie.domain) {
1122
- const suffix = pubsuffix.getPublicSuffix(cookie.cdomain());
1123
- if (suffix == null) {
1177
+ const suffix = pubsuffix.getPublicSuffix(cookie.cdomain(), {
1178
+ allowSpecialUseDomain: this.allowSpecialUseDomain,
1179
+ ignoreError: options.ignoreError
1180
+ });
1181
+ if (suffix == null && !IP_V6_REGEX_OBJECT.test(cookie.domain)) {
1124
1182
  // e.g. "com"
1125
1183
  err = new Error("Cookie has domain set to a public suffix");
1126
1184
  return cb(options.ignoreError ? null : err);
@@ -1163,7 +1221,11 @@ class CookieJar {
1163
1221
  }
1164
1222
 
1165
1223
  // 6252bis-02 S5.4 Step 13 & 14:
1166
- if (cookie.sameSite !== "none" && sameSiteContext) {
1224
+ if (
1225
+ cookie.sameSite !== "none" &&
1226
+ cookie.sameSite !== undefined &&
1227
+ sameSiteContext
1228
+ ) {
1167
1229
  // "If the cookie's "same-site-flag" is not "None", and the cookie
1168
1230
  // is being set from a context whose "site for cookies" is not an
1169
1231
  // exact match for request-uri's host's registered domain, then
@@ -1249,11 +1311,14 @@ class CookieJar {
1249
1311
 
1250
1312
  // RFC6365 S5.4
1251
1313
  getCookies(url, options, cb) {
1314
+ validators.validate(validators.isNonEmptyString(url), cb, url);
1252
1315
  const context = getCookieContext(url);
1253
- if (typeof options === "function") {
1316
+ if (validators.isFunction(options)) {
1254
1317
  cb = options;
1255
1318
  options = {};
1256
1319
  }
1320
+ validators.validate(validators.isObject(options), cb, options);
1321
+ validators.validate(validators.isFunction(cb), cb);
1257
1322
 
1258
1323
  const host = canonicalDomain(context.hostname);
1259
1324
  const path = context.pathname || "/";
@@ -1369,6 +1434,7 @@ class CookieJar {
1369
1434
 
1370
1435
  getCookieString(...args) {
1371
1436
  const cb = args.pop();
1437
+ validators.validate(validators.isFunction(cb), cb);
1372
1438
  const next = function(err, cookies) {
1373
1439
  if (err) {
1374
1440
  cb(err);
@@ -1388,6 +1454,7 @@ class CookieJar {
1388
1454
 
1389
1455
  getSetCookieStrings(...args) {
1390
1456
  const cb = args.pop();
1457
+ validators.validate(validators.isFunction(cb), cb);
1391
1458
  const next = function(err, cookies) {
1392
1459
  if (err) {
1393
1460
  cb(err);
@@ -1405,8 +1472,9 @@ class CookieJar {
1405
1472
  }
1406
1473
 
1407
1474
  serialize(cb) {
1475
+ validators.validate(validators.isFunction(cb), cb);
1408
1476
  let type = this.store.constructor.name;
1409
- if (type === "Object") {
1477
+ if (validators.isObject(type)) {
1410
1478
  type = null;
1411
1479
  }
1412
1480
 
@@ -1422,6 +1490,9 @@ class CookieJar {
1422
1490
 
1423
1491
  // CookieJar configuration:
1424
1492
  rejectPublicSuffixes: !!this.rejectPublicSuffixes,
1493
+ enableLooseMode: !!this.enableLooseMode,
1494
+ allowSpecialUseDomain: !!this.allowSpecialUseDomain,
1495
+ prefixSecurity: getNormalizedPrefixSecurity(this.prefixSecurity),
1425
1496
 
1426
1497
  // this gets filled from getAllCookies:
1427
1498
  cookies: []
@@ -1524,6 +1595,7 @@ class CookieJar {
1524
1595
  }
1525
1596
 
1526
1597
  removeAllCookies(cb) {
1598
+ validators.validate(validators.isFunction(cb), cb);
1527
1599
  const store = this.store;
1528
1600
 
1529
1601
  // Check that the store implements its own removeAllCookies(). The default
@@ -1577,6 +1649,7 @@ class CookieJar {
1577
1649
  cb = store;
1578
1650
  store = null;
1579
1651
  }
1652
+ validators.validate(validators.isFunction(cb), cb);
1580
1653
 
1581
1654
  let serialized;
1582
1655
  if (typeof strOrObj === "string") {
@@ -1588,7 +1661,12 @@ class CookieJar {
1588
1661
  serialized = strOrObj;
1589
1662
  }
1590
1663
 
1591
- const jar = new CookieJar(store, serialized.rejectPublicSuffixes);
1664
+ const jar = new CookieJar(store, {
1665
+ rejectPublicSuffixes: serialized.rejectPublicSuffixes,
1666
+ looseMode: serialized.enableLooseMode,
1667
+ allowSpecialUseDomain: serialized.allowSpecialUseDomain,
1668
+ prefixSecurity: serialized.prefixSecurity
1669
+ });
1592
1670
  jar._importCookies(serialized, err => {
1593
1671
  if (err) {
1594
1672
  return cb(err);
@@ -1600,7 +1678,10 @@ class CookieJar {
1600
1678
  static deserializeSync(strOrObj, store) {
1601
1679
  const serialized =
1602
1680
  typeof strOrObj === "string" ? JSON.parse(strOrObj) : strOrObj;
1603
- const jar = new CookieJar(store, serialized.rejectPublicSuffixes);
1681
+ const jar = new CookieJar(store, {
1682
+ rejectPublicSuffixes: serialized.rejectPublicSuffixes,
1683
+ looseMode: serialized.enableLooseMode
1684
+ });
1604
1685
 
1605
1686
  // catch this mistake early:
1606
1687
  if (!jar.store.synchronous) {
@@ -1669,3 +1750,4 @@ exports.permuteDomain = require("./permuteDomain").permuteDomain;
1669
1750
  exports.permutePath = permutePath;
1670
1751
  exports.canonicalDomain = canonicalDomain;
1671
1752
  exports.PrefixSecurityEnum = PrefixSecurityEnum;
1753
+ exports.ParameterError = validators.ParameterError;
package/lib/memstore.js CHANGED
@@ -33,19 +33,21 @@ const { fromCallback } = require("universalify");
33
33
  const Store = require("./store").Store;
34
34
  const permuteDomain = require("./permuteDomain").permuteDomain;
35
35
  const pathMatch = require("./pathMatch").pathMatch;
36
- const util = require("util");
36
+ const { getCustomInspectSymbol, getUtilInspect } = require("./utilHelper");
37
37
 
38
38
  class MemoryCookieStore extends Store {
39
39
  constructor() {
40
40
  super();
41
41
  this.synchronous = true;
42
42
  this.idx = {};
43
- if (util.inspect.custom) {
44
- this[util.inspect.custom] = this.inspect;
43
+ const customInspectSymbol = getCustomInspectSymbol();
44
+ if (customInspectSymbol) {
45
+ this[customInspectSymbol] = this.inspect;
45
46
  }
46
47
  }
47
48
 
48
49
  inspect() {
50
+ const util = { inspect: getUtilInspect(inspectFallback) };
49
51
  return `{ idx: ${util.inspect(this.idx, false, 2)} }`;
50
52
  }
51
53
 
@@ -184,7 +186,57 @@ class MemoryCookieStore extends Store {
184
186
  "removeAllCookies",
185
187
  "getAllCookies"
186
188
  ].forEach(name => {
187
- MemoryCookieStore[name] = fromCallback(MemoryCookieStore.prototype[name]);
189
+ MemoryCookieStore.prototype[name] = fromCallback(
190
+ MemoryCookieStore.prototype[name]
191
+ );
188
192
  });
189
193
 
190
194
  exports.MemoryCookieStore = MemoryCookieStore;
195
+
196
+ function inspectFallback(val) {
197
+ const domains = Object.keys(val);
198
+ if (domains.length === 0) {
199
+ return "{}";
200
+ }
201
+ let result = "{\n";
202
+ Object.keys(val).forEach((domain, i) => {
203
+ result += formatDomain(domain, val[domain]);
204
+ if (i < domains.length - 1) {
205
+ result += ",";
206
+ }
207
+ result += "\n";
208
+ });
209
+ result += "}";
210
+ return result;
211
+ }
212
+
213
+ function formatDomain(domainName, domainValue) {
214
+ const indent = " ";
215
+ let result = `${indent}'${domainName}': {\n`;
216
+ Object.keys(domainValue).forEach((path, i, paths) => {
217
+ result += formatPath(path, domainValue[path]);
218
+ if (i < paths.length - 1) {
219
+ result += ",";
220
+ }
221
+ result += "\n";
222
+ });
223
+ result += `${indent}}`;
224
+ return result;
225
+ }
226
+
227
+ function formatPath(pathName, pathValue) {
228
+ const indent = " ";
229
+ let result = `${indent}'${pathName}': {\n`;
230
+ Object.keys(pathValue).forEach((cookieName, i, cookieNames) => {
231
+ const cookie = pathValue[cookieName];
232
+ result += ` ${cookieName}: ${cookie.inspect()}`;
233
+ if (i < cookieNames.length - 1) {
234
+ result += ",";
235
+ }
236
+ result += "\n";
237
+ });
238
+ result += `${indent}}`;
239
+ return result;
240
+ }
241
+
242
+ exports.inspectFallback = inspectFallback;
@@ -33,21 +33,11 @@ const pubsuffix = require("./pubsuffix-psl");
33
33
 
34
34
  // Gives the permutation of all possible domainMatch()es of a given domain. The
35
35
  // array is in shortest-to-longest order. Handy for indexing.
36
- const SPECIAL_USE_DOMAINS = ["local"]; // RFC 6761
36
+
37
37
  function permuteDomain(domain, allowSpecialUseDomain) {
38
- let pubSuf = null;
39
- if (allowSpecialUseDomain) {
40
- const domainParts = domain.split(".");
41
- if (SPECIAL_USE_DOMAINS.includes(domainParts[domainParts.length - 1])) {
42
- pubSuf = `${domainParts[domainParts.length - 2]}.${
43
- domainParts[domainParts.length - 1]
44
- }`;
45
- } else {
46
- pubSuf = pubsuffix.getPublicSuffix(domain);
47
- }
48
- } else {
49
- pubSuf = pubsuffix.getPublicSuffix(domain);
50
- }
38
+ const pubSuf = pubsuffix.getPublicSuffix(domain, {
39
+ allowSpecialUseDomain: allowSpecialUseDomain
40
+ });
51
41
 
52
42
  if (!pubSuf) {
53
43
  return null;
@@ -56,6 +46,11 @@ function permuteDomain(domain, allowSpecialUseDomain) {
56
46
  return [domain];
57
47
  }
58
48
 
49
+ // Nuke trailing dot
50
+ if (domain.slice(-1) == ".") {
51
+ domain = domain.slice(0, -1);
52
+ }
53
+
59
54
  const prefix = domain.slice(0, -(pubSuf.length + 1)); // ".example.com"
60
55
  const parts = prefix.split(".").reverse();
61
56
  let cur = pubSuf;
@@ -31,7 +31,39 @@
31
31
  "use strict";
32
32
  const psl = require("psl");
33
33
 
34
- function getPublicSuffix(domain) {
34
+ // RFC 6761
35
+ const SPECIAL_USE_DOMAINS = [
36
+ "local",
37
+ "example",
38
+ "invalid",
39
+ "localhost",
40
+ "test"
41
+ ];
42
+
43
+ function getPublicSuffix(domain, options = {}) {
44
+ const domainParts = domain.split(".");
45
+ const topLevelDomain = domainParts[domainParts.length - 1];
46
+ const allowSpecialUseDomain = !!options.allowSpecialUseDomain;
47
+ const ignoreError = !!options.ignoreError;
48
+
49
+ if (
50
+ allowSpecialUseDomain &&
51
+ domainParts.length > 1 &&
52
+ SPECIAL_USE_DOMAINS.includes(topLevelDomain)
53
+ ) {
54
+ // If the right-most label in the name is a special-use domain (e.g. bananas.apple.localhost),
55
+ // then don't use PSL. This is because most special-use domains are not listed on PSL.
56
+ const secondLevelDomain = domainParts[domainParts.length - 2];
57
+ // In aforementioned example, the eTLD/pubSuf will be apple.localhost
58
+ return `${secondLevelDomain}.${topLevelDomain}`;
59
+ }
60
+
61
+ if (!ignoreError && SPECIAL_USE_DOMAINS.includes(topLevelDomain)) {
62
+ throw new Error(
63
+ `Cookie has domain set to the public suffix "${topLevelDomain}" which is a special use domain. To allow this, configure your CookieJar with {allowSpecialUseDomain:true, rejectPublicSuffixes: false}.`
64
+ );
65
+ }
66
+
35
67
  return psl.get(domain);
36
68
  }
37
69
 
@@ -0,0 +1,39 @@
1
+ function requireUtil() {
2
+ try {
3
+ // eslint-disable-next-line no-restricted-modules
4
+ return require("util");
5
+ } catch (e) {
6
+ return null;
7
+ }
8
+ }
9
+
10
+ // for v10.12.0+
11
+ function lookupCustomInspectSymbol() {
12
+ return Symbol.for("nodejs.util.inspect.custom");
13
+ }
14
+
15
+ // for older node environments
16
+ function tryReadingCustomSymbolFromUtilInspect(options) {
17
+ const _requireUtil = options.requireUtil || requireUtil;
18
+ const util = _requireUtil();
19
+ return util ? util.inspect.custom : null;
20
+ }
21
+
22
+ exports.getUtilInspect = function getUtilInspect(fallback, options = {}) {
23
+ const _requireUtil = options.requireUtil || requireUtil;
24
+ const util = _requireUtil();
25
+ return function inspect(value, showHidden, depth) {
26
+ return util ? util.inspect(value, showHidden, depth) : fallback(value);
27
+ };
28
+ };
29
+
30
+ exports.getCustomInspectSymbol = function getCustomInspectSymbol(options = {}) {
31
+ const _lookupCustomInspectSymbol =
32
+ options.lookupCustomInspectSymbol || lookupCustomInspectSymbol;
33
+
34
+ // get custom inspect symbol for node environments
35
+ return (
36
+ _lookupCustomInspectSymbol() ||
37
+ tryReadingCustomSymbolFromUtilInspect(options)
38
+ );
39
+ };
@@ -0,0 +1,95 @@
1
+ /* ************************************************************************************
2
+ Extracted from check-types.js
3
+ https://gitlab.com/philbooth/check-types.js
4
+
5
+ MIT License
6
+
7
+ Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Phil Booth
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
26
+
27
+ ************************************************************************************ */
28
+ "use strict";
29
+
30
+ /* Validation functions copied from check-types package - https://www.npmjs.com/package/check-types */
31
+ function isFunction(data) {
32
+ return typeof data === "function";
33
+ }
34
+
35
+ function isNonEmptyString(data) {
36
+ return isString(data) && data !== "";
37
+ }
38
+
39
+ function isDate(data) {
40
+ return isInstanceStrict(data, Date) && isInteger(data.getTime());
41
+ }
42
+
43
+ function isEmptyString(data) {
44
+ return data === "" || (data instanceof String && data.toString() === "");
45
+ }
46
+
47
+ function isString(data) {
48
+ return typeof data === "string" || data instanceof String;
49
+ }
50
+
51
+ function isObject(data) {
52
+ return toString.call(data) === "[object Object]";
53
+ }
54
+ function isInstanceStrict(data, prototype) {
55
+ try {
56
+ return data instanceof prototype;
57
+ } catch (error) {
58
+ return false;
59
+ }
60
+ }
61
+
62
+ function isInteger(data) {
63
+ return typeof data === "number" && data % 1 === 0;
64
+ }
65
+ /* End validation functions */
66
+
67
+ function validate(bool, cb, options) {
68
+ if (!isFunction(cb)) {
69
+ options = cb;
70
+ cb = null;
71
+ }
72
+ if (!isObject(options)) options = { Error: "Failed Check" };
73
+ if (!bool) {
74
+ if (cb) {
75
+ cb(new ParameterError(options));
76
+ } else {
77
+ throw new ParameterError(options);
78
+ }
79
+ }
80
+ }
81
+
82
+ class ParameterError extends Error {
83
+ constructor(...params) {
84
+ super(...params);
85
+ }
86
+ }
87
+
88
+ exports.ParameterError = ParameterError;
89
+ exports.isFunction = isFunction;
90
+ exports.isNonEmptyString = isNonEmptyString;
91
+ exports.isDate = isDate;
92
+ exports.isEmptyString = isEmptyString;
93
+ exports.isString = isString;
94
+ exports.isObject = isObject;
95
+ exports.validate = validate;
package/lib/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // generated by genversion
2
- module.exports = '4.0.0'
2
+ module.exports = '4.1.0'
package/package.json CHANGED
@@ -67,7 +67,7 @@
67
67
  "RFC6265",
68
68
  "RFC2965"
69
69
  ],
70
- "version": "4.0.0",
70
+ "version": "4.1.0",
71
71
  "homepage": "https://github.com/salesforce/tough-cookie",
72
72
  "repository": {
73
73
  "type": "git",
@@ -82,7 +82,7 @@
82
82
  ],
83
83
  "scripts": {
84
84
  "version": "genversion lib/version.js && git add lib/version.js",
85
- "test": "vows test/*_test.js",
85
+ "test": "vows test/*_test.js && npm run eslint",
86
86
  "cover": "nyc --reporter=lcov --reporter=html vows test/*_test.js",
87
87
  "eslint": "eslint --env node --ext .js .",
88
88
  "prettier": "prettier '**/*.{json,ts,yaml,md}'",
@@ -104,6 +104,7 @@
104
104
  "dependencies": {
105
105
  "psl": "^1.1.33",
106
106
  "punycode": "^2.1.1",
107
- "universalify": "^0.1.2"
107
+ "universalify": "^0.2.0",
108
+ "url-parse": "^1.5.3"
108
109
  }
109
110
  }