diff --git a/.eslintrc.json b/.eslintrc.json index 7dcba34d..76a4200c 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,4 +1,5 @@ { + "extends": ["plugin:prettier/recommended"], "parserOptions": { "ecmaVersion": 6 }, @@ -7,7 +8,14 @@ "no-var": "error", "prefer-arrow-callback": "error", "prefer-const": "error", - "prefer-template": "error" - }, - "extends": ["plugin:prettier/recommended"] + "prefer-template": "error", + "no-restricted-modules": ["error", + // we can't rely on node standard modules in "native" or "browser" environments + // - exceptions: + // "punycode": since it's a package.json dependency + "assert", "buffer", "child_process", "cluster", "crypto", "dgram", "dns", "domain", "events", "freelist", "fs", + "http", "https", "module", "net", "os", "path", "querystring", "readline", "repl", "smalloc", "stream", + "string_decoder", "sys", "timers", "tls", "tracing", "tty", "url", "util", "vm", "zlib" + ] + } } diff --git a/lib/cookie.js b/lib/cookie.js index f6ba38fd..73af4c8d 100644 --- a/lib/cookie.js +++ b/lib/cookie.js @@ -30,8 +30,7 @@ */ "use strict"; const punycode = require("punycode"); -const urlParse = require("url").parse; -const util = require("util"); +const urlParse = require("url-parse"); const pubsuffix = require("./pubsuffix-psl"); const Store = require("./store").Store; const MemoryCookieStore = require("./memstore").MemoryCookieStore; @@ -39,6 +38,7 @@ const pathMatch = require("./pathMatch").pathMatch; const validators = require("./validators.js"); const VERSION = require("./version"); const { fromCallback } = require("universalify"); +const { getCustomInspectSymbol } = require("./utilHelper"); // From RFC6265 S4.1.1 // note that it excludes \x3B ";" @@ -99,7 +99,7 @@ const PrefixSecurityEnum = Object.freeze({ // * all capturing groups converted to non-capturing -- "(?:)" // * support for IPv6 Scoped Literal ("%eth1") removed // * lowercase hexadecimal only -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}|:)))$)/; +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}|:)))$)/; const IP_V6_REGEX = ` \\[?(?: (?:[a-fA-F\\d]{1,4}:){7}(?:[a-fA-F\\d]{1,4}|:)| @@ -111,9 +111,11 @@ const IP_V6_REGEX = ` (?:[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}|:)| (?::(?:(?::[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}|:)) )(?:%[0-9a-zA-Z]{1,})?\\]? -`.replace(/\s*\/\/.*$/gm, '').replace(/\n/g, '').trim(); -const IP_V6_REGEX_OBJECT = new RegExp(`^${IP_V6_REGEX}$`) - +` + .replace(/\s*\/\/.*$/gm, "") + .replace(/\n/g, "") + .trim(); +const IP_V6_REGEX_OBJECT = new RegExp(`^${IP_V6_REGEX}$`); /* * Parses a Natural number (i.e., non-negative integer) with either the @@ -380,7 +382,7 @@ function domainMatch(str, domStr, canonicalize) { /* " * The last character of the string that is not included in the * domain string is a %x2E (".") character." */ - if (str.substr(idx-1,1) !== '.') { + if (str.substr(idx - 1, 1) !== ".") { return false; // doesn't align on "." } @@ -479,7 +481,7 @@ function parse(str, options) { } if (validators.isEmptyString(str) || !validators.isString(str)) { - return null + return null; } str = str.trim(); @@ -810,8 +812,9 @@ const cookieDefaults = { class Cookie { constructor(options = {}) { - if (util.inspect.custom) { - this[util.inspect.custom] = this.inspect; + const customInspectSymbol = getCustomInspectSymbol(); + if (customInspectSymbol) { + this[customInspectSymbol] = this.inspect; } Object.assign(this, cookieDefaults, options); @@ -1110,7 +1113,7 @@ class CookieJar { } setCookie(cookie, url, options, cb) { - validators.validate(validators.isNonEmptyString(url), cb, options); + validators.validate(validators.isNonEmptyString(url), cb, options); let err; if (validators.isFunction(url)) { @@ -1126,7 +1129,12 @@ class CookieJar { validators.validate(validators.isFunction(cb), cb); - if(!validators.isNonEmptyString(cookie) && !validators.isObject(cookie) && ( cookie instanceof String && cookie.length == 0)) { + if ( + !validators.isNonEmptyString(cookie) && + !validators.isObject(cookie) && + cookie instanceof String && + cookie.length == 0 + ) { return cb(null); } @@ -1649,7 +1657,7 @@ class CookieJar { serialized = strOrObj; } - const jar = new CookieJar(store, { + const jar = new CookieJar(store, { rejectPublicSuffixes: serialized.rejectPublicSuffixes, looseMode: serialized.enableLooseMode, allowSpecialUseDomain: serialized.allowSpecialUseDomain, @@ -1666,9 +1674,9 @@ class CookieJar { static deserializeSync(strOrObj, store) { const serialized = typeof strOrObj === "string" ? JSON.parse(strOrObj) : strOrObj; - const jar = new CookieJar(store, { + const jar = new CookieJar(store, { rejectPublicSuffixes: serialized.rejectPublicSuffixes, - looseMode: serialized.enableLooseMode + looseMode: serialized.enableLooseMode }); // catch this mistake early: diff --git a/lib/memstore.js b/lib/memstore.js index 0b7b3cc6..7c9ea0fb 100644 --- a/lib/memstore.js +++ b/lib/memstore.js @@ -33,19 +33,21 @@ const { fromCallback } = require("universalify"); const Store = require("./store").Store; const permuteDomain = require("./permuteDomain").permuteDomain; const pathMatch = require("./pathMatch").pathMatch; -const util = require("util"); +const { getCustomInspectSymbol, getUtilInspect } = require("./utilHelper"); class MemoryCookieStore extends Store { constructor() { super(); this.synchronous = true; this.idx = {}; - if (util.inspect.custom) { - this[util.inspect.custom] = this.inspect; + const customInspectSymbol = getCustomInspectSymbol(); + if (customInspectSymbol) { + this[customInspectSymbol] = this.inspect; } } inspect() { + const util = { inspect: getUtilInspect(inspectFallback) }; return `{ idx: ${util.inspect(this.idx, false, 2)} }`; } @@ -190,3 +192,51 @@ class MemoryCookieStore extends Store { }); exports.MemoryCookieStore = MemoryCookieStore; + +function inspectFallback(val) { + const domains = Object.keys(val); + if (domains.length === 0) { + return "{}"; + } + let result = "{\n"; + Object.keys(val).forEach((domain, i) => { + result += formatDomain(domain, val[domain]); + if (i < domains.length - 1) { + result += ","; + } + result += "\n"; + }); + result += "}"; + return result; +} + +function formatDomain(domainName, domainValue) { + const indent = " "; + let result = `${indent}'${domainName}': {\n`; + Object.keys(domainValue).forEach((path, i, paths) => { + result += formatPath(path, domainValue[path]); + if (i < paths.length - 1) { + result += ","; + } + result += "\n"; + }); + result += `${indent}}`; + return result; +} + +function formatPath(pathName, pathValue) { + const indent = " "; + let result = `${indent}'${pathName}': {\n`; + Object.keys(pathValue).forEach((cookieName, i, cookieNames) => { + const cookie = pathValue[cookieName]; + result += ` ${cookieName}: ${cookie.inspect()}`; + if (i < cookieNames.length - 1) { + result += ","; + } + result += "\n"; + }); + result += `${indent}}`; + return result; +} + +exports.inspectFallback = inspectFallback; diff --git a/lib/permuteDomain.js b/lib/permuteDomain.js index 35ab0228..75531241 100644 --- a/lib/permuteDomain.js +++ b/lib/permuteDomain.js @@ -48,7 +48,7 @@ function permuteDomain(domain, allowSpecialUseDomain) { // Nuke trailing dot if (domain.slice(-1) == ".") { - domain = domain.slice(0, -1) + domain = domain.slice(0, -1); } const prefix = domain.slice(0, -(pubSuf.length + 1)); // ".example.com" diff --git a/lib/utilHelper.js b/lib/utilHelper.js new file mode 100644 index 00000000..feac1250 --- /dev/null +++ b/lib/utilHelper.js @@ -0,0 +1,39 @@ +function requireUtil() { + try { + // eslint-disable-next-line no-restricted-modules + return require("util"); + } catch (e) { + return null; + } +} + +// for v10.12.0+ +function lookupCustomInspectSymbol() { + return Symbol.for("nodejs.util.inspect.custom"); +} + +// for older node environments +function tryReadingCustomSymbolFromUtilInspect(options) { + const _requireUtil = options.requireUtil || requireUtil; + const util = _requireUtil(); + return util ? util.inspect.custom : null; +} + +exports.getUtilInspect = function getUtilInspect(fallback, options = {}) { + const _requireUtil = options.requireUtil || requireUtil; + const util = _requireUtil(); + return function inspect(value, showHidden, depth) { + return util ? util.inspect(value, showHidden, depth) : fallback(value); + }; +}; + +exports.getCustomInspectSymbol = function getCustomInspectSymbol(options = {}) { + const _lookupCustomInspectSymbol = + options.lookupCustomInspectSymbol || lookupCustomInspectSymbol; + + // get custom inspect symbol for node environments + return ( + _lookupCustomInspectSymbol() || + tryReadingCustomSymbolFromUtilInspect(options) + ); +}; diff --git a/lib/validators.js b/lib/validators.js index d2f39deb..85581641 100644 --- a/lib/validators.js +++ b/lib/validators.js @@ -1,21 +1,21 @@ /* ************************************************************************************ Extracted from check-types.js https://gitlab.com/philbooth/check-types.js - + MIT License - + Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Phil Booth - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -23,17 +23,17 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + ************************************************************************************ */ "use strict"; /* Validation functions copied from check-types package - https://www.npmjs.com/package/check-types */ function isFunction(data) { - return typeof data === 'function'; + return typeof data === "function"; } function isNonEmptyString(data) { - return isString(data) && data !== ''; + return isString(data) && data !== ""; } function isDate(data) { @@ -41,15 +41,15 @@ function isDate(data) { } function isEmptyString(data) { - return data === '' || (data instanceof String && data.toString() === ''); + return data === "" || (data instanceof String && data.toString() === ""); } function isString(data) { - return typeof data === 'string' || data instanceof String + return typeof data === "string" || data instanceof String; } function isObject(data) { - return toString.call(data) === '[object Object]'; + return toString.call(data) === "[object Object]"; } function isInstanceStrict(data, prototype) { try { @@ -60,7 +60,7 @@ function isInstanceStrict(data, prototype) { } function isInteger(data) { - return typeof data === 'number' && data % 1 === 0; + return typeof data === "number" && data % 1 === 0; } /* End validation functions */ @@ -83,7 +83,7 @@ class ParameterError extends Error { constructor(...params) { super(...params); } -}; +} exports.ParameterError = ParameterError; exports.isFunction = isFunction; @@ -92,4 +92,4 @@ exports.isDate = isDate; exports.isEmptyString = isEmptyString; exports.isString = isString; exports.isObject = isObject; -exports.validate = validate; \ No newline at end of file +exports.validate = validate; diff --git a/package.json b/package.json index d9c5cc84..4d4f70fd 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ ], "scripts": { "version": "genversion lib/version.js && git add lib/version.js", - "test": "vows test/*_test.js", + "test": "vows test/*_test.js && npm run eslint", "cover": "nyc --reporter=lcov --reporter=html vows test/*_test.js", "eslint": "eslint --env node --ext .js .", "prettier": "prettier '**/*.{json,ts,yaml,md}'", @@ -104,6 +104,7 @@ "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", - "universalify": "^0.2.0" + "universalify": "^0.2.0", + "url-parse": "^1.5.3" } } diff --git a/test/.eslintrc.json b/test/.eslintrc.json new file mode 100644 index 00000000..e4149bbb --- /dev/null +++ b/test/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "no-restricted-modules": "off" + } +} diff --git a/test/cookie_jar_test.js b/test/cookie_jar_test.js index 328a639b..676e50db 100644 --- a/test/cookie_jar_test.js +++ b/test/cookie_jar_test.js @@ -281,7 +281,7 @@ vows assert.equal(c.TTL(), Infinity); assert.ok(!c.isPersistent()); } - }, + } }) .addBatch({ "Store eight cookies": { @@ -750,18 +750,21 @@ vows "of undefined": { topic: function() { const jar = new tough.CookieJar(); - const cookieString = `AWSELB=69b2c0038b16e8e27056d1178e0d556c; - Path=/, jses_WS41=5f8dc2f6-ea37-49de-8dfa-b58336c2d9ce; path=/; + const cookieString = `AWSELB=69b2c0038b16e8e27056d1178e0d556c; + Path=/, jses_WS41=5f8dc2f6-ea37-49de-8dfa-b58336c2d9ce; path=/; Secure; HttpOnly, AuthToken=EFKFFFCH@K@GHIHEJCJMMGJM>CDHDEK>CFGK?MHJ >>JI@B??@CAEHBJH@H@A@GCFDLIMLJEEJEIFGALA?BIM?@G@DEDI@JE?I?HKJBIDDHJMEFEFM - >G@J?I??B@C>>LAH?GCGJ@FMEGHBGAF; expires=Sun, 31-Jan-9021 02:39:04 GMT; - path=/; Secure; HttpOnly, FirstReferrer=; expires=Fri, 31-Jan-9020 20:50:44 + >G@J?I??B@C>>LAH?GCGJ@FMEGHBGAF; expires=Sun, 31-Jan-9021 02:39:04 GMT; + path=/; Secure; HttpOnly, FirstReferrer=; expires=Fri, 31-Jan-9020 20:50:44 GMT; path=/`; jar.setCookieSync(cookieString, "https://google.com"); - jar.getCookies("https://google.com", this.callback) + jar.getCookies("https://google.com", this.callback); }, - "results in a 1-length array with a valid cookie": function(err, cookies) { + "results in a 1-length array with a valid cookie": function( + err, + cookies + ) { assert(!err, err); assert(cookies.length == 1); assert.instanceOf(cookies[0], Cookie); @@ -780,7 +783,10 @@ vows this.callback ); }, - "results in a error being returned because of missing parameters": function(err, cookies) { + "results in a error being returned because of missing parameters": function( + err, + cookies + ) { assert(err != null); assert(err instanceof tough.ParameterError); } @@ -792,13 +798,12 @@ vows "with missing parameters": { topic: function() { const jar = new tough.CookieJar(); - jar.setCookie( - '', - "https://google.com", - this.callback - ); + jar.setCookie("", "https://google.com", this.callback); }, - "results in a error being returned because of missing parameters": function(err, cookies) { + "results in a error being returned because of missing parameters": function( + err, + cookies + ) { assert(cookies == undefined); } } diff --git a/test/domain_and_path_test.js b/test/domain_and_path_test.js index de15f317..4291c5be 100644 --- a/test/domain_and_path_test.js +++ b/test/domain_and_path_test.js @@ -50,15 +50,15 @@ function matchVows(func, table) { } function transformVows(fn, table) { - var theVows = {}; - table.forEach(function (item) { - var str = item[0]; - var expect = item[1]; - var label = str + " gives " + expect; + const theVows = {}; + table.forEach(item => { + const str = item[0]; + const expect = item[1]; + let label = `${str} gives ${expect}`; if (item.length >= 3) { - label += " (" + item[2] + ")"; + label += ` (${item[2]})`; } - theVows[label] = function () { + theVows[label] = function() { assert.equal(fn(str), expect); }; }); @@ -75,7 +75,7 @@ vows ["EXAMPLE.com.", "example.com.", "trailing dot"], [".EXAMPLE.com.", "example.com.", "leading and trailing dot"], [".EXAMPLE...com.", "example...com.", "internal dots"], - ["δοκιμή.δοκιμή","xn--jxalpdlp.xn--jxalpdlp", "IDN: test.test in greek"], + ["δοκιμή.δοκιμή", "xn--jxalpdlp.xn--jxalpdlp", "IDN: test.test in greek"] ]) }) .addBatch({ @@ -142,12 +142,12 @@ vows // exact length "TLD" tests: ["com", "net", false], // same len, non-match ["com", "com", true], // "are identical" rule - ["NOTATLD", "notaTLD", true], // "are identical" rule (after canonicalization) + ["NOTATLD", "notaTLD", true] // "are identical" rule (after canonicalization) ]) }) .addBatch({ - "default-path": transformVows(tough.defaultPath,[ + "default-path": transformVows(tough.defaultPath, [ [null, "/"], ["/", "/"], ["/file", "/"], diff --git a/test/node_util_fallback_test.js b/test/node_util_fallback_test.js new file mode 100644 index 00000000..d8b859a0 --- /dev/null +++ b/test/node_util_fallback_test.js @@ -0,0 +1,175 @@ +/*! + * Copyright (c) 2022, Salesforce.com, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Salesforce.com nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +"use strict"; +const vows = require("vows"); +const assert = require("assert"); +const tough = require("../lib/cookie"); +const util = require("util"); +const inspectFallback = require("../lib/memstore").inspectFallback; +const { getCustomInspectSymbol, getUtilInspect } = require("../lib/utilHelper"); +const Cookie = tough.Cookie; +const CookieJar = tough.CookieJar; + +function resetAgeFields(str) { + return str.replace(/\d+ms/g, "0ms"); +} + +vows + .describe("Node util module fallback for non-node environments") + .addBatch({ + getCustomInspectSymbol: { + "should not be null in a node environment": function() { + assert.equal( + getCustomInspectSymbol(), + Symbol.for("nodejs.util.inspect.custom") || util.inspect.custom + ); + }, + "should not be null in a node environment when custom inspect symbol cannot be retrieved (< node v10.12.0)": function() { + assert.equal( + getCustomInspectSymbol({ + lookupCustomInspectSymbol: () => null + }), + Symbol.for("nodejs.util.inspect.custom") || util.inspect.custom + ); + }, + "should be null in a non-node environment since 'util' features cannot be relied on": function() { + assert.equal( + getCustomInspectSymbol({ + lookupCustomInspectSymbol: () => null, + requireUtil: () => null + }), + null + ); + } + }, + getUtilInspect: { + "should use util.inspect in a node environment": function() { + const inspect = getUtilInspect(() => "fallback"); + assert.equal(inspect("util.inspect"), util.inspect("util.inspect")); + }, + "should use fallback inspect function in a non-node environment": function() { + const inspect = getUtilInspect(() => "fallback", { + requireUtil: () => null + }); + assert.equal(inspect("util.inspect"), "fallback"); + } + }, + "util usage in Cookie": { + "custom inspect for Cookie still works": function() { + const cookie = Cookie.parse("a=1; Domain=example.com; Path=/"); + assert.equal(cookie.inspect(), util.inspect(cookie)); + } + }, + "util usage in MemoryCookie": { + "when store is empty": { + topic: function() { + const cookieJar = new CookieJar(); + return cookieJar.store; + }, + "custom inspect for MemoryCookie still works": function(memoryStore) { + assert.equal( + resetAgeFields(util.inspect(memoryStore)), + resetAgeFields(memoryStore.inspect()) + ); + }, + "fallback produces equivalent output to custom inspect": function( + memoryStore + ) { + assert.equal( + resetAgeFields(util.inspect(memoryStore.idx)), + resetAgeFields(inspectFallback(memoryStore.idx)) + ); + } + }, + "when store has a single cookie": { + topic: function() { + const cookieJar = new CookieJar(); + cookieJar.setCookieSync( + "a=1; Domain=example.com; Path=/", + "http://example.com/index.html" + ); + return cookieJar.store; + }, + "custom inspect for MemoryCookie still works": function(memoryStore) { + assert.equal( + resetAgeFields(util.inspect(memoryStore)), + resetAgeFields(memoryStore.inspect()) + ); + }, + "fallback produces equivalent output to custom inspect": function( + memoryStore + ) { + assert.equal( + resetAgeFields(util.inspect(memoryStore.idx)), + resetAgeFields(inspectFallback(memoryStore.idx)) + ); + } + }, + "when store has a multiple cookies": { + topic: function() { + const cookieJar = new CookieJar(); + ["a", "b", "c"].forEach((cookieName, i) => { + cookieJar.setCookieSync( + `${cookieName}=${i}; Domain=example.com; Path=/`, + "http://example.com/index.html" + ); + }); + ["d", "e"].forEach((cookieName, i) => { + cookieJar.setCookieSync( + `${cookieName}=${i}; Domain=example.com; Path=/some-path/`, + "http://example.com/index.html" + ); + }); + cookieJar.setCookieSync( + `f=0; Domain=another.com; Path=/`, + "http://another.com/index.html" + ); + return cookieJar.store; + }, + "custom inspect for MemoryCookie still works": function(memoryStore) { + assert.equal( + resetAgeFields(util.inspect(memoryStore)), + resetAgeFields(memoryStore.inspect()) + ); + }, + "fallback produces equivalent output to custom inspect": function( + memoryStore + ) { + assert.equal( + resetAgeFields(util.inspect(memoryStore.idx)), + resetAgeFields(inspectFallback(memoryStore.idx)) + ); + } + } + } + }) + .export(module); diff --git a/test/parsing_test.js b/test/parsing_test.js index b26d4cfb..5a9e944c 100644 --- a/test/parsing_test.js +++ b/test/parsing_test.js @@ -693,35 +693,35 @@ vows } }, "empty string": { - topic: function () { - return Cookie.parse(''); + topic: function() { + return Cookie.parse(""); }, - "is empty": function (c) { + "is empty": function(c) { assert.isNull(c); } }, "missing string": { - topic: function () { + topic: function() { return Cookie.parse(); }, - "is empty": function (c) { + "is empty": function(c) { assert.isNull(c); } }, "some string object": { topic: function() { - return Cookie.parse(new String('')) + return Cookie.parse(new String("")); }, "is empty": function(c) { - assert.isNull(c,null) + assert.isNull(c, null); } }, "some empty string object": { topic: function() { - return Cookie.parse(new String()) + return Cookie.parse(new String()); }, "is empty": function(c) { - assert.isNull(c,null) + assert.isNull(c, null); } } })