"use strict"; XPCOMUtils.defineLazyModuleGetter(this, "ExtensionStorage", "resource://gre/modules/ExtensionStorage.jsm"); Cu.import("resource://gre/modules/Services.jsm"); function storageApiFactory(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: function(keys) { keys = sanitize(keys); return context.childManager.callParentAsyncFunction("storage.local.get", [ keys, ]); }, set: function(items) { items = sanitize(items); return context.childManager.callParentAsyncFunction("storage.local.set", [ items, ]); }, }, 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, ]); }, }, }, }; } extensions.registerSchemaAPI("storage", "addon_child", storageApiFactory); extensions.registerSchemaAPI("storage", "content_child", storageApiFactory);