Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Native Support #227

Merged
14 changes: 11 additions & 3 deletions .eslintrc.json
@@ -1,4 +1,5 @@
{
"extends": ["plugin:prettier/recommended"],
"parserOptions": {
"ecmaVersion": 6
},
Expand All @@ -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"
]
}
}
34 changes: 21 additions & 13 deletions lib/cookie.js
Expand Up @@ -30,8 +30,8 @@
*/
"use strict";
const punycode = require("punycode");
const urlParse = require("url").parse;
const util = require("util");
const urlParse = require("url-parse");
const nodeUtil = require("./nodeUtil");
const pubsuffix = require("./pubsuffix-psl");
const Store = require("./store").Store;
const MemoryCookieStore = require("./memstore").MemoryCookieStore;
Expand Down Expand Up @@ -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}|:)|
Expand All @@ -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
Expand Down Expand Up @@ -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 "."
}

Expand Down Expand Up @@ -479,7 +481,7 @@ function parse(str, options) {
}

if (validators.isEmptyString(str) || !validators.isString(str)) {
return null
return null;
}

str = str.trim();
Expand Down Expand Up @@ -810,6 +812,7 @@ const cookieDefaults = {

class Cookie {
constructor(options = {}) {
const util = nodeUtil();
if (util.inspect.custom) {
this[util.inspect.custom] = this.inspect;
}
Expand Down Expand Up @@ -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)) {
Expand All @@ -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);
}

Expand Down Expand Up @@ -1646,7 +1654,7 @@ class CookieJar {
serialized = strOrObj;
}

const jar = new CookieJar(store, {
const jar = new CookieJar(store, {
rejectPublicSuffixes: serialized.rejectPublicSuffixes,
looseMode: serialized.enableLooseMode,
allowSpecialUseDomain: serialized.allowSpecialUseDomain,
Expand All @@ -1663,9 +1671,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:
Expand Down
4 changes: 3 additions & 1 deletion lib/memstore.js
Expand Up @@ -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 nodeUtil = require("./nodeUtil");

class MemoryCookieStore extends Store {
constructor() {
super();
this.synchronous = true;
this.idx = {};
const util = nodeUtil();
if (util.inspect.custom) {
this[util.inspect.custom] = this.inspect;
}
}

inspect() {
const util = nodeUtil();
return `{ idx: ${util.inspect(this.idx, false, 2)} }`;
colincasey marked this conversation as resolved.
Show resolved Hide resolved
}

Expand Down
101 changes: 101 additions & 0 deletions lib/nodeUtil.js
@@ -0,0 +1,101 @@
/*!
* Copyright (c) 2021, 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.
*/

const customInspectSymbol = Symbol.for("nodejs.util.inspect.custom");

function inspectFallback(val) {
colincasey marked this conversation as resolved.
Show resolved Hide resolved
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;
}

inspectFallback.custom = customInspectSymbol;

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[customInspectSymbol]()}`;
if (i < cookieNames.length - 1) {
result += ",";
}
result += "\n";
});
result += `${indent}}`;
return result;
}

const nodeUtilFallback = {
inspect: inspectFallback
};

module.exports = function nodeUtil() {
try {
const nodeUtilFallbackEnabled =
process &&
process.env &&
process.env.TOUGH_COOKIE_NODE_UTIL_FALLBACK === "enabled";
if (!nodeUtilFallbackEnabled) {
// we want the real "util" module if we are in a node environment
// eslint-disable-next-line no-restricted-modules
return require("util");
}
} catch (e) {
// ignored
}
return nodeUtilFallback;
};
2 changes: 1 addition & 1 deletion lib/permuteDomain.js
Expand Up @@ -70,7 +70,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"
Expand Down
28 changes: 14 additions & 14 deletions lib/validators.js
@@ -1,55 +1,55 @@
/* ************************************************************************************
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
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) {
return isInstanceStrict(data, Date) && isInteger(data.getTime());
}

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 {
Expand All @@ -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 */

Expand All @@ -83,7 +83,7 @@ class ParameterError extends Error {
constructor(...params) {
super(...params);
}
};
}

exports.ParameterError = ParameterError;
exports.isFunction = isFunction;
Expand All @@ -92,4 +92,4 @@ exports.isDate = isDate;
exports.isEmptyString = isEmptyString;
exports.isString = isString;
exports.isObject = isObject;
exports.validate = validate;
exports.validate = validate;
5 changes: 3 additions & 2 deletions package.json
Expand Up @@ -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}'",
Expand All @@ -104,6 +104,7 @@
"dependencies": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
"universalify": "^0.1.2"
"universalify": "^0.1.2",
"url-parse": "^1.5.3"
}
}
5 changes: 5 additions & 0 deletions test/.eslintrc.json
@@ -0,0 +1,5 @@
{
"rules": {
"no-restricted-modules": "off"
}
}