tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

local-and-session-storage.js (4933B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 const {
      8  BaseStorageActor,
      9  DEFAULT_VALUE,
     10 } = require("resource://devtools/server/actors/resources/storage/index.js");
     11 const {
     12  LongStringActor,
     13 } = require("resource://devtools/server/actors/string.js");
     14 
     15 class LocalOrSessionStorageActor extends BaseStorageActor {
     16  constructor(storageActor, typeName) {
     17    super(storageActor, typeName);
     18 
     19    Services.obs.addObserver(this, "dom-storage2-changed");
     20    Services.obs.addObserver(this, "dom-private-storage2-changed");
     21  }
     22 
     23  destroy() {
     24    if (this.isDestroyed()) {
     25      return;
     26    }
     27    Services.obs.removeObserver(this, "dom-storage2-changed");
     28    Services.obs.removeObserver(this, "dom-private-storage2-changed");
     29 
     30    super.destroy();
     31  }
     32 
     33  getNamesForHost(host) {
     34    const storage = this.hostVsStores.get(host);
     35    return storage ? Object.keys(storage) : [];
     36  }
     37 
     38  getValuesForHost(host, name) {
     39    const storage = this.hostVsStores.get(host);
     40    if (!storage) {
     41      return [];
     42    }
     43    if (name) {
     44      const value = storage ? storage.getItem(name) : null;
     45      return [{ name, value }];
     46    }
     47    if (!storage) {
     48      return [];
     49    }
     50 
     51    // local and session storage cannot be iterated over using Object.keys()
     52    // because it skips keys that are duplicated on the prototype
     53    // e.g. "key", "getKeys" so we need to gather the real keys using the
     54    // storage.key() function.
     55    const storageArray = [];
     56    for (let i = 0; i < storage.length; i++) {
     57      const key = storage.key(i);
     58      storageArray.push({
     59        name: key,
     60        value: storage.getItem(key),
     61      });
     62    }
     63    return storageArray;
     64  }
     65 
     66  // We need to override this method as populateStoresForHost expect the window object
     67  populateStoresForHosts() {
     68    this.hostVsStores = new Map();
     69    for (const window of this.windows) {
     70      const host = this.getHostName(window.location);
     71      if (host) {
     72        this.populateStoresForHost(host, window);
     73      }
     74    }
     75  }
     76 
     77  populateStoresForHost(host, window) {
     78    try {
     79      this.hostVsStores.set(host, window[this.typeName]);
     80    } catch (ex) {
     81      console.warn(
     82        `Failed to enumerate ${this.typeName} for host ${host}: ${ex}`
     83      );
     84    }
     85  }
     86 
     87  async getFields() {
     88    return [
     89      { name: "name", editable: true },
     90      { name: "value", editable: true },
     91    ];
     92  }
     93 
     94  async addItem(guid, host) {
     95    const storage = this.hostVsStores.get(host);
     96    if (!storage) {
     97      return;
     98    }
     99    storage.setItem(guid, DEFAULT_VALUE);
    100  }
    101 
    102  /**
    103   * Edit localStorage or sessionStorage fields.
    104   *
    105   * @param {object} data
    106   *        See editCookie() for format details.
    107   */
    108  async editItem({ host, field, oldValue, items }) {
    109    const storage = this.hostVsStores.get(host);
    110    if (!storage) {
    111      return;
    112    }
    113 
    114    if (field === "name") {
    115      storage.removeItem(oldValue);
    116    }
    117 
    118    storage.setItem(items.name, items.value);
    119  }
    120 
    121  async removeItem(host, name) {
    122    const storage = this.hostVsStores.get(host);
    123    if (!storage) {
    124      return;
    125    }
    126    storage.removeItem(name);
    127  }
    128 
    129  async removeAll(host) {
    130    const storage = this.hostVsStores.get(host);
    131    if (!storage) {
    132      return;
    133    }
    134    storage.clear();
    135  }
    136 
    137  observe(subject, topic, data) {
    138    if (
    139      (topic != "dom-storage2-changed" &&
    140        topic != "dom-private-storage2-changed") ||
    141      data != this.typeName
    142    ) {
    143      return null;
    144    }
    145 
    146    const host = this.getSchemaAndHost(subject.url);
    147 
    148    if (!this.hostVsStores.has(host)) {
    149      return null;
    150    }
    151 
    152    let action = "changed";
    153    if (subject.key == null) {
    154      return this.storageActor.update("cleared", this.typeName, [host]);
    155    } else if (subject.oldValue == null) {
    156      action = "added";
    157    } else if (subject.newValue == null) {
    158      action = "deleted";
    159    }
    160    const updateData = {};
    161    updateData[host] = [subject.key];
    162    return this.storageActor.update(action, this.typeName, updateData);
    163  }
    164 
    165  /**
    166   * Given a url, correctly determine its protocol + hostname part.
    167   */
    168  getSchemaAndHost(url) {
    169    const uri = Services.io.newURI(url);
    170    if (!uri.host) {
    171      return uri.spec;
    172    }
    173    return uri.scheme + "://" + uri.hostPort;
    174  }
    175 
    176  toStoreObject(item) {
    177    if (!item) {
    178      return null;
    179    }
    180 
    181    return {
    182      name: item.name,
    183      value: new LongStringActor(this.conn, item.value || ""),
    184    };
    185  }
    186 }
    187 
    188 class LocalStorageActor extends LocalOrSessionStorageActor {
    189  constructor(storageActor) {
    190    super(storageActor, "localStorage");
    191  }
    192 }
    193 exports.LocalStorageActor = LocalStorageActor;
    194 
    195 class SessionStorageActor extends LocalOrSessionStorageActor {
    196  constructor(storageActor) {
    197    super(storageActor, "sessionStorage");
    198  }
    199 }
    200 exports.SessionStorageActor = SessionStorageActor;