tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

utils.js (4052B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 loader.lazyRequireGetter(
      8  this,
      9  "validator",
     10  "resource://devtools/shared/storage/vendor/stringvalidator/validator.js"
     11 );
     12 loader.lazyRequireGetter(
     13  this,
     14  "JSON5",
     15  "resource://devtools/shared/storage/vendor/json5.js"
     16 );
     17 
     18 const MATH_REGEX =
     19  /(?:(?:^|[-+_*/])(?:\s*-?\d+(\.\d+)?(?:[eE][+-]?\d+)?\s*))+$/;
     20 
     21 /**
     22 * Tries to parse a string into an object on the basis of key-value pairs,
     23 * separated by various separators. If failed, tries to parse for single
     24 * separator separated values to form an array.
     25 *
     26 * @param {string} value
     27 *        The string to be parsed into an object or array
     28 */
     29 function _extractKeyValPairs(value) {
     30  const makeObject = (keySep, pairSep) => {
     31    const object = {};
     32    for (const pair of value.split(pairSep)) {
     33      const [key, val] = pair.split(keySep);
     34      object[key] = val;
     35    }
     36    return object;
     37  };
     38 
     39  // Possible separators.
     40  const separators = ["=", ":", "~", "#", "&", "\\*", ",", "\\."];
     41  // Testing for object
     42  for (let i = 0; i < separators.length; i++) {
     43    const kv = separators[i];
     44    for (let j = 0; j < separators.length; j++) {
     45      if (i == j) {
     46        continue;
     47      }
     48      const p = separators[j];
     49      const word = `[^${kv}${p}]*`;
     50      const keyValue = `${word}${kv}${word}`;
     51      const keyValueList = `${keyValue}(${p}${keyValue})*`;
     52      const regex = new RegExp(`^${keyValueList}$`);
     53      if (
     54        value.match &&
     55        value.match(regex) &&
     56        value.includes(kv) &&
     57        (value.includes(p) || value.split(kv).length == 2)
     58      ) {
     59        return makeObject(kv, p);
     60      }
     61    }
     62  }
     63  // Testing for array
     64  for (const p of separators) {
     65    const word = `[^${p}]*`;
     66    const wordList = `(${word}${p})+${word}`;
     67    const regex = new RegExp(`^${wordList}$`);
     68 
     69    if (regex.test(value)) {
     70      const pNoBackslash = p.replace(/\\*/g, "");
     71      return value.split(pNoBackslash);
     72    }
     73  }
     74  return null;
     75 }
     76 
     77 /**
     78 * Check whether the value string represents something that should be
     79 * displayed as text. If so then it shouldn't be parsed into a tree.
     80 *
     81 * @param  {string} value
     82 *         The value to be parsed.
     83 */
     84 function _shouldParse(value) {
     85  const validators = [
     86    "isBase64",
     87    "isBoolean",
     88    "isCurrency",
     89    "isDataURI",
     90    "isEmail",
     91    "isFQDN",
     92    "isHexColor",
     93    "isIP",
     94    "isISO8601",
     95    "isMACAddress",
     96    "isSemVer",
     97    "isURL",
     98  ];
     99 
    100  // Check for minus calculations e.g. 8-3 because otherwise 5 will be displayed.
    101  if (MATH_REGEX.test(value)) {
    102    return false;
    103  }
    104 
    105  // Check for any other types that shouldn't be parsed.
    106  for (const test of validators) {
    107    if (validator[test](value)) {
    108      return false;
    109    }
    110  }
    111 
    112  // Seems like this is data that should be parsed.
    113  return true;
    114 }
    115 
    116 /**
    117 * Tries to parse a string value into either a json or a key-value separated
    118 * object. The value can also be a key separated array.
    119 *
    120 * @param {string} originalValue
    121 *        The string to be parsed into an object
    122 */
    123 function parseItemValue(originalValue) {
    124  // Find if value is URLEncoded ie
    125  let decodedValue = "";
    126  try {
    127    decodedValue = decodeURIComponent(originalValue);
    128  } catch (e) {
    129    // Unable to decode, nothing to do
    130  }
    131  const value =
    132    decodedValue && decodedValue !== originalValue
    133      ? decodedValue
    134      : originalValue;
    135 
    136  if (!_shouldParse(value)) {
    137    return value;
    138  }
    139 
    140  let obj = null;
    141  try {
    142    obj = JSON5.parse(value);
    143  } catch (ex) {
    144    obj = null;
    145  }
    146 
    147  if (!obj && value) {
    148    obj = _extractKeyValPairs(value);
    149  }
    150 
    151  // return if obj is null, or same as value, or just a string.
    152  if (!obj || obj === value || typeof obj === "string") {
    153    return value;
    154  }
    155 
    156  // If we got this far, originalValue is an object literal or array,
    157  // and we have successfully parsed it
    158  return obj;
    159 }
    160 
    161 exports.parseItemValue = parseItemValue;