forked from mirrors/gecko-dev
* Update the extensionStorage actor to enable some writing to extension storage.local through the Storage panel client.
* All values in the client are displayed as strings, so the actor must stringify them before sending them to the client and parse them when receiving changes from the client. For this reason, there is currently limited write support.
* Item values that are JSONifiable (numbers, strings, booleans, object literals, arrays and null) can be edited from the Storage panel.
* Object literals and arrays are only editable if their values are JSONifiable, with a maximum nested depth of 2 (e.g. an object with a nested object is editable, provided the nested object contains only primitive values). Object literals' keys must also be strings to be editable.
* Non-JSONifiable values cannot be edited, and will be represented by "{}" in most cases in the panel, though some non-JSONifiable values (undefined, Date, and BigInt) will be displayed as more readable strings.
* Some modifications are a little more complex, requiring an IndexedDB transaction. This will be handled in a separate patch.
* Item names cannot be edited from the Storage panel.
* New items cannot be added from the Storage panel.
* Any item can be removed.
* All items can be removed at once.
* In-line comments referencing Bugs 1542038 and 1542039 indicate places where the implementation may differ for local storage versus the other storage areas in the actor.
* The parseItemValue method used in the client was moved to a shared directory, so that the actor could parse string values from the client in its editItem method.
Differential Revision: https://phabricator.services.mozilla.com/D34416
--HG--
rename : devtools/client/shared/vendor/JSON5_LICENSE => devtools/shared/storage/vendor/JSON5_LICENSE
rename : devtools/client/shared/vendor/JSON5_UPGRADING.md => devtools/shared/storage/vendor/JSON5_UPGRADING.md
rename : devtools/client/shared/vendor/json5.js => devtools/shared/storage/vendor/json5.js
rename : devtools/client/shared/vendor/stringvalidator/UPDATING.md => devtools/shared/storage/vendor/stringvalidator/UPDATING.md
rename : devtools/client/shared/vendor/stringvalidator/moz.build => devtools/shared/storage/vendor/stringvalidator/moz.build
rename : devtools/client/shared/vendor/stringvalidator/tests/unit/head_stringvalidator.js => devtools/shared/storage/vendor/stringvalidator/tests/unit/head_stringvalidator.js
rename : devtools/client/shared/vendor/stringvalidator/tests/unit/test_sanitizers.js => devtools/shared/storage/vendor/stringvalidator/tests/unit/test_sanitizers.js
rename : devtools/client/shared/vendor/stringvalidator/tests/unit/test_validators.js => devtools/shared/storage/vendor/stringvalidator/tests/unit/test_validators.js
rename : devtools/client/shared/vendor/stringvalidator/tests/unit/xpcshell.ini => devtools/shared/storage/vendor/stringvalidator/tests/unit/xpcshell.ini
rename : devtools/client/shared/vendor/stringvalidator/util/assert.js => devtools/shared/storage/vendor/stringvalidator/util/assert.js
rename : devtools/client/shared/vendor/stringvalidator/util/moz.build => devtools/shared/storage/vendor/stringvalidator/util/moz.build
rename : devtools/client/shared/vendor/stringvalidator/validator.js => devtools/shared/storage/vendor/stringvalidator/validator.js
extra : moz-landing-system : lando
156 lines
3.9 KiB
JavaScript
156 lines
3.9 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
"use strict";
|
|
|
|
loader.lazyRequireGetter(
|
|
this,
|
|
"validator",
|
|
"devtools/shared/storage/vendor/stringvalidator/validator"
|
|
);
|
|
loader.lazyRequireGetter(this, "JSON5", "devtools/shared/storage/vendor/json5");
|
|
|
|
const MATH_REGEX = /(?:(?:^|[-+_*/])(?:\s*-?\d+(\.\d+)?(?:[eE][+-]?\d+)?\s*))+$/;
|
|
|
|
/**
|
|
* Tries to parse a string into an object on the basis of key-value pairs,
|
|
* separated by various separators. If failed, tries to parse for single
|
|
* separator separated values to form an array.
|
|
*
|
|
* @param {string} value
|
|
* The string to be parsed into an object or array
|
|
*/
|
|
function _extractKeyValPairs(value) {
|
|
const makeObject = (keySep, pairSep) => {
|
|
const object = {};
|
|
for (const pair of value.split(pairSep)) {
|
|
const [key, val] = pair.split(keySep);
|
|
object[key] = val;
|
|
}
|
|
return object;
|
|
};
|
|
|
|
// Possible separators.
|
|
const separators = ["=", ":", "~", "#", "&", "\\*", ",", "\\."];
|
|
// Testing for object
|
|
for (let i = 0; i < separators.length; i++) {
|
|
const kv = separators[i];
|
|
for (let j = 0; j < separators.length; j++) {
|
|
if (i == j) {
|
|
continue;
|
|
}
|
|
const p = separators[j];
|
|
const word = `[^${kv}${p}]*`;
|
|
const keyValue = `${word}${kv}${word}`;
|
|
const keyValueList = `${keyValue}(${p}${keyValue})*`;
|
|
const regex = new RegExp(`^${keyValueList}$`);
|
|
if (
|
|
value.match &&
|
|
value.match(regex) &&
|
|
value.includes(kv) &&
|
|
(value.includes(p) || value.split(kv).length == 2)
|
|
) {
|
|
return makeObject(kv, p);
|
|
}
|
|
}
|
|
}
|
|
// Testing for array
|
|
for (const p of separators) {
|
|
const word = `[^${p}]*`;
|
|
const wordList = `(${word}${p})+${word}`;
|
|
const regex = new RegExp(`^${wordList}$`);
|
|
|
|
if (regex.test(value)) {
|
|
const pNoBackslash = p.replace(/\\*/g, "");
|
|
return value.split(pNoBackslash);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Check whether the value string represents something that should be
|
|
* displayed as text. If so then it shouldn't be parsed into a tree.
|
|
*
|
|
* @param {String} value
|
|
* The value to be parsed.
|
|
*/
|
|
function _shouldParse(value) {
|
|
const validators = [
|
|
"isBase64",
|
|
"isBoolean",
|
|
"isCurrency",
|
|
"isDataURI",
|
|
"isEmail",
|
|
"isFQDN",
|
|
"isHexColor",
|
|
"isIP",
|
|
"isISO8601",
|
|
"isMACAddress",
|
|
"isSemVer",
|
|
"isURL",
|
|
];
|
|
|
|
// Check for minus calculations e.g. 8-3 because otherwise 5 will be displayed.
|
|
if (MATH_REGEX.test(value)) {
|
|
return false;
|
|
}
|
|
|
|
// Check for any other types that shouldn't be parsed.
|
|
for (const test of validators) {
|
|
if (validator[test](value)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Seems like this is data that should be parsed.
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Tries to parse a string value into either a json or a key-value separated
|
|
* object. The value can also be a key separated array.
|
|
*
|
|
* @param {string} originalValue
|
|
* The string to be parsed into an object
|
|
*/
|
|
function parseItemValue(originalValue) {
|
|
// Find if value is URLEncoded ie
|
|
let decodedValue = "";
|
|
try {
|
|
decodedValue = decodeURIComponent(originalValue);
|
|
} catch (e) {
|
|
// Unable to decode, nothing to do
|
|
}
|
|
const value =
|
|
decodedValue && decodedValue !== originalValue
|
|
? decodedValue
|
|
: originalValue;
|
|
|
|
if (!_shouldParse(value)) {
|
|
return value;
|
|
}
|
|
|
|
let obj = null;
|
|
try {
|
|
obj = JSON5.parse(value);
|
|
} catch (ex) {
|
|
obj = null;
|
|
}
|
|
|
|
if (!obj && value) {
|
|
obj = _extractKeyValPairs(value);
|
|
}
|
|
|
|
// return if obj is null, or same as value, or just a string.
|
|
if (!obj || obj === value || typeof obj === "string") {
|
|
return value;
|
|
}
|
|
|
|
// If we got this far, originalValue is an object literal or array,
|
|
// and we have successfully parsed it
|
|
return obj;
|
|
}
|
|
|
|
exports.parseItemValue = parseItemValue;
|