Files
tubestation/toolkit/components/extensions/ext-c-storage.js
2017-06-19 13:00:19 -04:00

86 lines
3.2 KiB
JavaScript

"use strict";
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionStorage",
"resource://gre/modules/ExtensionStorage.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
"resource://gre/modules/TelemetryStopwatch.jsm");
Cu.import("resource://gre/modules/Services.jsm");
const storageGetHistogram = "WEBEXT_STORAGE_LOCAL_GET_MS";
const storageSetHistogram = "WEBEXT_STORAGE_LOCAL_SET_MS";
this.storage = class extends ExtensionAPI {
getAPI(context) {
function sanitize(items) {
// The schema validator already takes care of arrays (which are only allowed
// to contain strings). Strings and null are safe values.
if (typeof items != "object" || items === null || Array.isArray(items)) {
return items;
}
// If we got here, then `items` is an object generated by `ObjectType`'s
// `normalize` method from Schemas.jsm. The object returned by `normalize`
// lives in this compartment, while the values live in compartment of
// `context.contentWindow`. The `sanitize` method runs with the principal
// of `context`, so we cannot just use `ExtensionStorage.sanitize` because
// it is not allowed to access properties of `items`.
// So we enumerate all properties and sanitize each value individually.
let sanitized = {};
for (let [key, value] of Object.entries(items)) {
sanitized[key] = ExtensionStorage.sanitize(value, context);
}
return sanitized;
}
return {
storage: {
local: {
get: async function(keys) {
const stopwatchKey = {};
TelemetryStopwatch.start(storageGetHistogram, stopwatchKey);
try {
keys = sanitize(keys);
let result = await context.childManager.callParentAsyncFunction("storage.local.get", [
keys,
]);
TelemetryStopwatch.finish(storageGetHistogram, stopwatchKey);
return result;
} catch (e) {
TelemetryStopwatch.cancel(storageGetHistogram, stopwatchKey);
throw e;
}
},
set: async function(items) {
const stopwatchKey = {};
TelemetryStopwatch.start(storageSetHistogram, stopwatchKey);
try {
items = sanitize(items);
let result = await context.childManager.callParentAsyncFunction("storage.local.set", [
items,
]);
TelemetryStopwatch.finish(storageSetHistogram, stopwatchKey);
return result;
} catch (e) {
TelemetryStopwatch.cancel(storageSetHistogram, stopwatchKey);
throw e;
}
},
},
sync: {
get: function(keys) {
keys = sanitize(keys);
return context.childManager.callParentAsyncFunction("storage.sync.get", [
keys,
]);
},
set: function(items) {
items = sanitize(items);
return context.childManager.callParentAsyncFunction("storage.sync.set", [
items,
]);
},
},
},
};
}
};