"use strict";

XPCOMUtils.defineLazyModuleGetter(this, "ExtensionStorage",
                                  "resource://gre/modules/ExtensionStorage.jsm");
Cu.import("resource://gre/modules/Services.jsm");

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: 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,
            ]);
          },
        },
      },
    };
  }
};
