diff options
Diffstat (limited to 'toolkit/components/webextensions/ExtensionStorage.jsm')
-rw-r--r-- | toolkit/components/webextensions/ExtensionStorage.jsm | 241 |
1 files changed, 0 insertions, 241 deletions
diff --git a/toolkit/components/webextensions/ExtensionStorage.jsm b/toolkit/components/webextensions/ExtensionStorage.jsm deleted file mode 100644 index 0b0ffb000..000000000 --- a/toolkit/components/webextensions/ExtensionStorage.jsm +++ /dev/null @@ -1,241 +0,0 @@ -/* 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"; - -this.EXPORTED_SYMBOLS = ["ExtensionStorage"]; - -const Ci = Components.interfaces; -const Cc = Components.classes; -const Cu = Components.utils; -const Cr = Components.results; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "OS", - "resource://gre/modules/osfile.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown", - "resource://gre/modules/AsyncShutdown.jsm"); - -function jsonReplacer(key, value) { - switch (typeof(value)) { - // Serialize primitive types as-is. - case "string": - case "number": - case "boolean": - return value; - - case "object": - if (value === null) { - return value; - } - - switch (Cu.getClassName(value, true)) { - // Serialize arrays and ordinary objects as-is. - case "Array": - case "Object": - return value; - - // Serialize Date objects and regular expressions as their - // string representations. - case "Date": - case "RegExp": - return String(value); - } - break; - } - - if (!key) { - // If this is the root object, and we can't serialize it, serialize - // the value to an empty object. - return {}; - } - - // Everything else, omit entirely. - return undefined; -} - -this.ExtensionStorage = { - cache: new Map(), - listeners: new Map(), - - /** - * Sanitizes the given value, and returns a JSON-compatible - * representation of it, based on the privileges of the given global. - * - * @param {value} value - * The value to sanitize. - * @param {Context} context - * The extension context in which to sanitize the value - * @returns {value} - * The sanitized value. - */ - sanitize(value, context) { - let json = context.jsonStringify(value, jsonReplacer); - return JSON.parse(json); - }, - - getExtensionDir(extensionId) { - return OS.Path.join(this.extensionDir, extensionId); - }, - - getStorageFile(extensionId) { - return OS.Path.join(this.extensionDir, extensionId, "storage.js"); - }, - - read(extensionId) { - if (this.cache.has(extensionId)) { - return this.cache.get(extensionId); - } - - let path = this.getStorageFile(extensionId); - let decoder = new TextDecoder(); - let promise = OS.File.read(path); - promise = promise.then(array => { - return JSON.parse(decoder.decode(array)); - }).catch((error) => { - if (!error.becauseNoSuchFile) { - Cu.reportError("Unable to parse JSON data for extension storage."); - } - return {}; - }); - this.cache.set(extensionId, promise); - return promise; - }, - - write(extensionId) { - let promise = this.read(extensionId).then(extData => { - let encoder = new TextEncoder(); - let array = encoder.encode(JSON.stringify(extData)); - let path = this.getStorageFile(extensionId); - OS.File.makeDir(this.getExtensionDir(extensionId), { - ignoreExisting: true, - from: OS.Constants.Path.profileDir, - }); - let promise = OS.File.writeAtomic(path, array); - return promise; - }).catch(() => { - // Make sure this promise is never rejected. - Cu.reportError("Unable to write JSON data for extension storage."); - }); - - AsyncShutdown.profileBeforeChange.addBlocker( - "ExtensionStorage: Finish writing extension data", - promise); - - return promise.then(() => { - AsyncShutdown.profileBeforeChange.removeBlocker(promise); - }); - }, - - set(extensionId, items, context) { - return this.read(extensionId).then(extData => { - let changes = {}; - for (let prop in items) { - let item = this.sanitize(items[prop], context); - changes[prop] = {oldValue: extData[prop], newValue: item}; - extData[prop] = item; - } - - this.notifyListeners(extensionId, changes); - - return this.write(extensionId); - }); - }, - - remove(extensionId, items) { - return this.read(extensionId).then(extData => { - let changes = {}; - for (let prop of [].concat(items)) { - changes[prop] = {oldValue: extData[prop]}; - delete extData[prop]; - } - - this.notifyListeners(extensionId, changes); - - return this.write(extensionId); - }); - }, - - clear(extensionId) { - return this.read(extensionId).then(extData => { - let changes = {}; - for (let prop of Object.keys(extData)) { - changes[prop] = {oldValue: extData[prop]}; - delete extData[prop]; - } - - this.notifyListeners(extensionId, changes); - - return this.write(extensionId); - }); - }, - - get(extensionId, keys) { - return this.read(extensionId).then(extData => { - let result = {}; - if (keys === null) { - Object.assign(result, extData); - } else if (typeof(keys) == "object" && !Array.isArray(keys)) { - for (let prop in keys) { - if (prop in extData) { - result[prop] = extData[prop]; - } else { - result[prop] = keys[prop]; - } - } - } else { - for (let prop of [].concat(keys)) { - if (prop in extData) { - result[prop] = extData[prop]; - } - } - } - - return result; - }); - }, - - addOnChangedListener(extensionId, listener) { - let listeners = this.listeners.get(extensionId) || new Set(); - listeners.add(listener); - this.listeners.set(extensionId, listeners); - }, - - removeOnChangedListener(extensionId, listener) { - let listeners = this.listeners.get(extensionId); - listeners.delete(listener); - }, - - notifyListeners(extensionId, changes) { - let listeners = this.listeners.get(extensionId); - if (listeners) { - for (let listener of listeners) { - listener(changes); - } - } - }, - - init() { - if (Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_DEFAULT) { - return; - } - Services.obs.addObserver(this, "extension-invalidate-storage-cache", false); - Services.obs.addObserver(this, "xpcom-shutdown", false); - }, - - observe(subject, topic, data) { - if (topic == "xpcom-shutdown") { - Services.obs.removeObserver(this, "extension-invalidate-storage-cache"); - Services.obs.removeObserver(this, "xpcom-shutdown"); - } else if (topic == "extension-invalidate-storage-cache") { - this.cache.clear(); - } - }, -}; - -XPCOMUtils.defineLazyGetter(ExtensionStorage, "extensionDir", - () => OS.Path.join(OS.Constants.Path.profileDir, "browser-extension-data")); - -ExtensionStorage.init(); |