tor-browser

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

keypath-exceptions.any.js (10452B)


      1 // META: global=window,worker
      2 // META: title=IndexedDB: Exceptions in extracting keys from values (ES bindings)
      3 // META: script=resources/support.js
      4 
      5 // Spec: https://w3c.github.io/IndexedDB/#extract-key-from-value
      6 
      7 'use strict';
      8 
      9 indexeddb_test(
     10    (t, db) => {
     11      db.createObjectStore('store', {autoIncrement: true, keyPath: 'a.b.c'});
     12    },
     13    (t, db) => {
     14      const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'});
     15      assert_throws_dom('DataError', () => {
     16        tx.objectStore('store').put({a: {b: 'foo'}});
     17      }, 'Put should throw if key can not be inserted at key path location.');
     18      t.done();
     19    },
     20    'The last element of keypath is validated');
     21 
     22 const err = Error();
     23 err.name = 'getter';
     24 
     25 function throwingGetter() {
     26  throw err;
     27 }
     28 
     29 indexeddb_test(
     30    function(t, db) {
     31      const o = {};
     32      Object.defineProperty(
     33          o, 'throws',
     34          {get: throwingGetter, enumerable: false, configurable: true});
     35 
     36      // Value should be cloned before key path is evaluated,
     37      // and non-enumerable getter will be ignored. The clone
     38      // will have no such property, so key path evaluation
     39      // will fail.
     40      const s1 = db.createObjectStore('s1', {keyPath: 'throws'});
     41      assert_throws_dom('DataError', () => {
     42        s1.put(o);
     43      }, 'Key path failing to resolve should throw');
     44 
     45      // Value should be cloned before key path is evaluated,
     46      // and non-enumerable getter will be ignored. The clone
     47      // will have no such property, so key path evaluation
     48      // will fail.
     49      const s2 = db.createObjectStore('s2', {keyPath: 'throws.x'});
     50      assert_throws_dom('DataError', () => {
     51        s2.put(o);
     52      }, 'Key path failing to resolve should throw');
     53 
     54      // Value should be cloned before key path is evaluated,
     55      // and non-enumerable getter will be ignored. The clone
     56      // will have no such property, so generated key can be
     57      // inserted.
     58      const s3 =
     59          db.createObjectStore('s3', {keyPath: 'throws', autoIncrement: true});
     60      assert_class_string(
     61          s3.put(o), 'IDBRequest',
     62          'Key injectability test at throwing getter should succeed');
     63 
     64      // Value should be cloned before key path is evaluated,
     65      // and non-enumerable getter will be ignored. The clone
     66      // will have no such property, so intermediate object
     67      // and generated key can be inserted.
     68      const s4 = db.createObjectStore(
     69          's4', {keyPath: 'throws.x', autoIncrement: true});
     70      assert_class_string(
     71          s4.put(o), 'IDBRequest',
     72          'Key injectability test past throwing getter should succeed');
     73    },
     74    (t, db) => {
     75      t.done();
     76    },
     77    'Key path evaluation: Exceptions from non-enumerable getters');
     78 
     79 indexeddb_test(
     80    function(t, db) {
     81      const o = {};
     82      Object.defineProperty(
     83          o, 'throws',
     84          {get: throwingGetter, enumerable: true, configurable: true});
     85 
     86      // Value should be cloned before key path is evaluated,
     87      // and enumerable getter will rethrow.
     88      const s1 = db.createObjectStore('s1', {keyPath: 'throws'});
     89      assert_throws_exactly(err, () => {
     90        s1.put(o);
     91      }, 'Key path resolving to throwing getter rethrows');
     92 
     93      // Value should be cloned before key path is evaluated,
     94      // and enumerable getter will rethrow.
     95      const s2 = db.createObjectStore('s2', {keyPath: 'throws.x'});
     96      assert_throws_exactly(err, () => {
     97        s2.put(o);
     98      }, 'Key path resolving past throwing getter rethrows');
     99 
    100      // Value should be cloned before key path is evaluated,
    101      // and enumerable getter will rethrow.
    102      const s3 =
    103          db.createObjectStore('s3', {keyPath: 'throws', autoIncrement: true});
    104      assert_throws_exactly(err, () => {
    105        s3.put(o);
    106      }, 'Key injectability test at throwing getter should rethrow');
    107 
    108      // Value should be cloned before key path is evaluated,
    109      // and enumerable getter will rethrow.
    110      const s4 = db.createObjectStore(
    111          's4', {keyPath: 'throws.x', autoIncrement: true});
    112      assert_throws_exactly(err, () => {
    113        s4.put(o);
    114      }, 'Key injectability test past throwing getter should rethrow');
    115    },
    116    (t, db) => {
    117      t.done();
    118    },
    119    'Key path evaluation: Exceptions from enumerable getters');
    120 
    121 indexeddb_test(
    122    (t, db) => {
    123      // Implemented as function wrapper to clean up
    124      // immediately after use, otherwise it may
    125      // interfere with the test harness.
    126      function with_proto_getter(f) {
    127        return function() {
    128          Object.defineProperty(
    129              Object.prototype, 'throws',
    130              {get: throwingGetter, enumerable: false, configurable: true});
    131          try {
    132            f();
    133          } finally {
    134            delete Object.prototype['throws'];
    135          }
    136        };
    137      }
    138 
    139      // Value should be cloned before key path is evaluated,
    140      // and non-enumerable getter will be ignored. The clone
    141      // will have no own property, so key path evaluation will
    142      // fail and DataError should be thrown.
    143      const s1 = db.createObjectStore('s1', {keyPath: 'throws'});
    144      assert_throws_dom(
    145          'DataError', with_proto_getter(function() {
    146            s1.put({});
    147          }),
    148          'Key path resolving to no own property throws DataError');
    149 
    150      // Value should be cloned before key path is evaluated,
    151      // and non-enumerable getter will be ignored. The clone
    152      // will have no own property, so key path evaluation will
    153      // fail and DataError should be thrown.
    154      const s2 = db.createObjectStore('s2', {keyPath: 'throws.x'});
    155      assert_throws_dom(
    156          'DataError', with_proto_getter(function() {
    157            s2.put({});
    158          }),
    159          'Key path resolving past no own property throws DataError');
    160 
    161      // Value should be cloned before key path is evaluated,
    162      // and non-enumerable getter will be ignored. The clone
    163      // will have no own property, so key path evaluation will
    164      // fail and injection can succeed.
    165      const s3 =
    166          db.createObjectStore('s3', {keyPath: 'throws', autoIncrement: true});
    167      assert_equals(
    168          s3.put({}).readyState, 'pending',
    169          'put should not throw due to inherited property');
    170 
    171      // Value should be cloned before key path is evaluated,
    172      // and non-enumerable getter will be ignored. The clone
    173      // will have no own property, so key path evaluation will
    174      // fail and injection can succeed.
    175      const s4 = db.createObjectStore(
    176          's4', {keyPath: 'throws.x', autoIncrement: true});
    177      assert_equals(
    178          s4.put({}).readyState, 'pending',
    179          'put should not throw due to inherited property');
    180    },
    181    (t, db) => {
    182      t.done();
    183    },
    184    'Key path evaluation: Exceptions from non-enumerable getters on prototype');
    185 
    186 indexeddb_test(
    187    (t, db) => {
    188      // Implemented as function wrapper to clean up
    189      // immediately after use, otherwise it may
    190      // interfere with the test harness.
    191      function with_proto_getter(f) {
    192        return () => {
    193          Object.defineProperty(
    194              Object.prototype, 'throws',
    195              {get: throwingGetter, enumerable: true, configurable: true});
    196          try {
    197            f();
    198          } finally {
    199            delete Object.prototype['throws'];
    200          }
    201        };
    202      }
    203 
    204      // Value should be cloned before key path is evaluated.
    205      // The clone will have no own property, so key path
    206      // evaluation will fail and DataError should be thrown.
    207      const s1 = db.createObjectStore('s1', {keyPath: 'throws'});
    208      assert_throws_dom(
    209          'DataError', with_proto_getter(function() {
    210            s1.put({});
    211          }),
    212          'Key path resolving to no own property throws DataError');
    213 
    214      // Value should be cloned before key path is evaluated.
    215      // The clone will have no own property, so key path
    216      // evaluation will fail and DataError should be thrown.
    217      const s2 = db.createObjectStore('s2', {keyPath: 'throws.x'});
    218      assert_throws_dom(
    219          'DataError', with_proto_getter(function() {
    220            s2.put({});
    221          }),
    222          'Key path resolving past throwing getter rethrows');
    223 
    224      // Value should be cloned before key path is evaluated.
    225      // The clone will have no own property, so key path
    226      // evaluation will fail and injection can succeed.
    227      let s3 =
    228          db.createObjectStore('s3', {keyPath: 'throws', autoIncrement: true});
    229      assert_equals(
    230          s3.put({}).readyState, 'pending',
    231          'put should not throw due to inherited property');
    232 
    233      // Value should be cloned before key path is evaluated.
    234      // The clone will have no own property, so key path
    235      // evaluation will fail and injection can succeed.
    236      let s4 = db.createObjectStore(
    237          's4', {keyPath: 'throws.x', autoIncrement: true});
    238      assert_equals(
    239          s4.put({}).readyState, 'pending',
    240          'put should not throw due to inherited property');
    241    },
    242    (t, db) => {
    243      t.done();
    244    },
    245    'Key path evaluation: Exceptions from enumerable getters on prototype');
    246 
    247 indexeddb_test(
    248    (t, db) => {
    249      const store = db.createObjectStore('store');
    250      store.createIndex('index', 'index0');
    251    },
    252    (t, db) => {
    253      const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'});
    254 
    255      const array = [];
    256      array[99] = 1;
    257 
    258      // Implemented as function wrapper to clean up
    259      // immediately after use, otherwise it may
    260      // interfere with the test harness.
    261      let getter_called = 0;
    262      function with_proto_getter(f) {
    263        const prop = '50';
    264        Object.defineProperty(Object.prototype, prop, {
    265          enumerable: true,
    266          configurable: true,
    267          get: () => {
    268            ++getter_called;
    269            return 'foo';
    270          }
    271        });
    272        try {
    273          return f();
    274        } finally {
    275          delete Object.prototype[prop];
    276        }
    277      }
    278 
    279      const request = with_proto_getter(
    280          () => tx.objectStore('store').put({index0: array}, 'key'));
    281      request.onerror = t.unreached_func('put should not fail');
    282      request.onsuccess = t.step_func(function() {
    283        assert_equals(
    284            getter_called, 0, 'Prototype getter should not be called');
    285        t.done();
    286      });
    287    },
    288    'Array key conversion should not invoke prototype getters');