tor-browser

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

PrefixedLocalStorage.js (4264B)


      1 /**
      2 * Supports pseudo-"namespacing" localStorage for a given test
      3 * by generating and using a unique prefix for keys. Why trounce on other
      4 * tests' localStorage items when you can keep it "separated"?
      5 *
      6 * PrefixedLocalStorageTest: Instantiate in testharness.js tests to generate
      7 *   a new unique-ish prefix
      8 * PrefixedLocalStorageResource: Instantiate in supporting test resource
      9 *   files to use/share a prefix generated by a test.
     10 */
     11 var PrefixedLocalStorage = function () {
     12  this.prefix = ''; // Prefix for localStorage keys
     13  this.param = 'prefixedLocalStorage'; // Param to use in querystrings
     14 };
     15 
     16 PrefixedLocalStorage.prototype.clear = function () {
     17  if (this.prefix === '') { return; }
     18  Object.keys(localStorage).forEach(sKey => {
     19    if (sKey.indexOf(this.prefix) === 0) {
     20      localStorage.removeItem(sKey);
     21    }
     22  });
     23 };
     24 
     25 /**
     26 * Append/replace prefix parameter and value in URI querystring
     27 * Use to generate URLs to resource files that will share the prefix.
     28 */
     29 PrefixedLocalStorage.prototype.url = function (uri) {
     30  function updateUrlParameter (uri, key, value) {
     31    var i         = uri.indexOf('#');
     32    var hash      = (i === -1) ? '' : uri.substr(i);
     33    uri           = (i === -1) ? uri : uri.substr(0, i);
     34    var re        = new RegExp(`([?&])${key}=.*?(&|$)`, 'i');
     35    var separator = uri.indexOf('?') !== -1 ? '&' : '?';
     36    uri = (uri.match(re)) ? uri.replace(re, `$1${key}=${value}$2`) :
     37      `${uri}${separator}${key}=${value}`;
     38    return uri + hash;
     39  }
     40  return updateUrlParameter(uri, this.param, this.prefix);
     41 };
     42 
     43 PrefixedLocalStorage.prototype.prefixedKey = function (baseKey) {
     44  return `${this.prefix}${baseKey}`;
     45 };
     46 
     47 PrefixedLocalStorage.prototype.setItem = function (baseKey, value) {
     48  localStorage.setItem(this.prefixedKey(baseKey), value);
     49 };
     50 
     51 /**
     52 * Listen for `storage` events pertaining to a particular key,
     53 * prefixed with this object's prefix. Ignore when value is being set to null
     54 * (i.e. removeItem).
     55 */
     56 PrefixedLocalStorage.prototype.onSet = function (baseKey, fn) {
     57  window.addEventListener('storage', e => {
     58    var match = this.prefixedKey(baseKey);
     59    if (e.newValue !== null && e.key.indexOf(match) === 0) {
     60      fn.call(this, e);
     61    }
     62  });
     63 };
     64 
     65 /*****************************************************************************
     66 * Use in a testharnessjs test to generate a new key prefix.
     67 * async_test(t => {
     68 *   var prefixedStorage = new PrefixedLocalStorageTest();
     69 *   t.add_cleanup(() => prefixedStorage.cleanup());
     70 *   /...
     71 * });
     72 */
     73 var PrefixedLocalStorageTest = function () {
     74  PrefixedLocalStorage.call(this);
     75  this.prefix = `${document.location.pathname}-${Math.random()}-${Date.now()}-`;
     76 };
     77 PrefixedLocalStorageTest.prototype = Object.create(PrefixedLocalStorage.prototype);
     78 PrefixedLocalStorageTest.prototype.constructor = PrefixedLocalStorageTest;
     79 
     80 /**
     81 * Use in a cleanup function to clear out prefixed entries in localStorage
     82 */
     83 PrefixedLocalStorageTest.prototype.cleanup = function () {
     84  this.setItem('closeAll', 'true');
     85  this.clear();
     86 };
     87 
     88 /*****************************************************************************
     89 * Use in test resource files to share a prefix generated by a
     90 * PrefixedLocalStorageTest. Will look in URL querystring for prefix.
     91 * Setting `close_on_cleanup` opt truthy will make this script's window listen
     92 * for storage `closeAll` event from controlling test and close itself.
     93 *
     94 * var PrefixedLocalStorageResource({ close_on_cleanup: true });
     95 */
     96 var PrefixedLocalStorageResource = function (options) {
     97  PrefixedLocalStorage.call(this);
     98  this.options = Object.assign({}, {
     99    close_on_cleanup: false
    100  }, options || {});
    101  // Check URL querystring for prefix to use
    102  var regex = new RegExp(`[?&]${this.param}(=([^&#]*)|&|#|$)`),
    103    results = regex.exec(document.location.href);
    104  if (results && results[2]) {
    105    this.prefix = results[2];
    106  }
    107  // Optionally have this window close itself when the PrefixedLocalStorageTest
    108  // sets a `closeAll` item.
    109  if (this.options.close_on_cleanup) {
    110    this.onSet('closeAll', () => {
    111      window.close();
    112    });
    113  }
    114 };
    115 PrefixedLocalStorageResource.prototype = Object.create(PrefixedLocalStorage.prototype);
    116 PrefixedLocalStorageResource.prototype.constructor = PrefixedLocalStorageResource;