tor-browser

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

head_cookies.js (46466B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/
      3 */
      4 
      5 /* import-globals-from head_cache.js */
      6 
      7 "use strict";
      8 
      9 const { NetUtil } = ChromeUtils.importESModule(
     10  "resource://gre/modules/NetUtil.sys.mjs"
     11 );
     12 const { CookieXPCShellUtils } = ChromeUtils.importESModule(
     13  "resource://testing-common/CookieXPCShellUtils.sys.mjs"
     14 );
     15 
     16 // Don't pick up default permissions from profile.
     17 Services.prefs.setCharPref("permissions.manager.defaultsUrl", "");
     18 
     19 CookieXPCShellUtils.init(this);
     20 
     21 function do_check_throws(f, result, stack) {
     22  if (!stack) {
     23    stack = Components.stack.caller;
     24  }
     25 
     26  try {
     27    f();
     28  } catch (exc) {
     29    if (exc.result == result) {
     30      return;
     31    }
     32    do_throw("expected result " + result + ", caught " + exc, stack);
     33  }
     34  do_throw("expected result " + result + ", none thrown", stack);
     35 }
     36 
     37 // Helper to step a generator function and catch a StopIteration exception.
     38 function do_run_generator(generator) {
     39  try {
     40    generator.next();
     41  } catch (e) {
     42    do_throw("caught exception " + e, Components.stack.caller);
     43  }
     44 }
     45 
     46 // Helper to finish a generator function test.
     47 function do_finish_generator_test(generator) {
     48  executeSoon(function () {
     49    generator.return();
     50    do_test_finished();
     51  });
     52 }
     53 
     54 function _observer(generator, topic) {
     55  Services.obs.addObserver(this, topic);
     56 
     57  this.generator = generator;
     58  this.topic = topic;
     59 }
     60 
     61 _observer.prototype = {
     62  observe(subject, topic) {
     63    Assert.equal(this.topic, topic);
     64 
     65    Services.obs.removeObserver(this, this.topic);
     66 
     67    // Continue executing the generator function.
     68    if (this.generator) {
     69      do_run_generator(this.generator);
     70    }
     71 
     72    this.generator = null;
     73    this.topic = null;
     74  },
     75 };
     76 
     77 // Close the cookie database. If a generator is supplied, it will be invoked
     78 // once the close is complete.
     79 function do_close_profile(generator) {
     80  // Register an observer for db close.
     81  new _observer(generator, "cookie-db-closed");
     82 
     83  // Close the db.
     84  let service = Services.cookies.QueryInterface(Ci.nsIObserver);
     85  service.observe(null, "profile-before-change", null);
     86 }
     87 
     88 function _promise_observer(topic) {
     89  Services.obs.addObserver(this, topic);
     90 
     91  this.topic = topic;
     92  return new Promise(resolve => (this.resolve = resolve));
     93 }
     94 
     95 _promise_observer.prototype = {
     96  observe(subject, topic) {
     97    Assert.equal(this.topic, topic);
     98 
     99    Services.obs.removeObserver(this, this.topic);
    100    if (this.resolve) {
    101      this.resolve();
    102    }
    103 
    104    this.resolve = null;
    105    this.topic = null;
    106  },
    107 };
    108 
    109 // Close the cookie database. And resolve a promise.
    110 function promise_close_profile() {
    111  // Register an observer for db close.
    112  let promise = new _promise_observer("cookie-db-closed");
    113 
    114  // Close the db.
    115  let service = Services.cookies.QueryInterface(Ci.nsIObserver);
    116  service.observe(null, "profile-before-change", null);
    117 
    118  return promise;
    119 }
    120 
    121 // Load the cookie database.
    122 function promise_load_profile() {
    123  // Register an observer for read completion.
    124  let promise = new _promise_observer("cookie-db-read");
    125 
    126  // Load the profile.
    127  let service = Services.cookies.QueryInterface(Ci.nsIObserver);
    128  service.observe(null, "profile-do-change", "");
    129 
    130  return promise;
    131 }
    132 
    133 // Load the cookie database. If a generator is supplied, it will be invoked
    134 // once the load is complete.
    135 function do_load_profile(generator) {
    136  // Register an observer for read completion.
    137  new _observer(generator, "cookie-db-read");
    138 
    139  // Load the profile.
    140  let service = Services.cookies.QueryInterface(Ci.nsIObserver);
    141  service.observe(null, "profile-do-change", "");
    142 }
    143 
    144 // Set a single session cookie using http and test the cookie count
    145 // against 'expected'
    146 function do_set_single_http_cookie(uri, channel, expected) {
    147  Services.cookies.setCookieStringFromHttp(uri, "foo=bar", channel);
    148  Assert.equal(Services.cookies.countCookiesFromHost(uri.host), expected);
    149 }
    150 
    151 // Set two cookies; via document.channel and via http request.
    152 async function do_set_cookies(uri, channel, session, expected) {
    153  let suffix = session ? "" : "; max-age=1000";
    154 
    155  // via document.cookie
    156  const thirdPartyUrl = "http://third.com/";
    157  const contentPage = await CookieXPCShellUtils.loadContentPage(thirdPartyUrl);
    158  await contentPage.spawn(
    159    [
    160      {
    161        cookie: "can=has" + suffix,
    162        url: uri.spec,
    163      },
    164    ],
    165    async function (obj) {
    166      await new this.content.Promise(resolve => {
    167        let doc = this.content.document;
    168        let ifr = doc.createElement("iframe");
    169        ifr.src = obj.url;
    170        doc.body.appendChild(ifr);
    171        ifr.addEventListener("load", async () => {
    172          await this.SpecialPowers.spawn(ifr, [obj.cookie], cookie => {
    173            this.content.document.cookie = cookie;
    174          });
    175          resolve();
    176        });
    177      });
    178    }
    179  );
    180  await contentPage.close();
    181 
    182  Assert.equal(Services.cookies.countCookiesFromHost(uri.host), expected[0]);
    183 
    184  // via http request
    185  Services.cookies.setCookieStringFromHttp(uri, "hot=dog" + suffix, channel);
    186  Assert.equal(Services.cookies.countCookiesFromHost(uri.host), expected[1]);
    187 }
    188 
    189 function do_count_cookies() {
    190  return Services.cookies.cookies.length;
    191 }
    192 
    193 // Helper object to store cookie data.
    194 function Cookie(
    195  name,
    196  value,
    197  host,
    198  path,
    199  expiry,
    200  lastAccessed,
    201  creationTime,
    202  isSession,
    203  isSecure,
    204  isHttpOnly,
    205  inBrowserElement = false,
    206  originAttributes = {},
    207  sameSite = Ci.nsICookie.SAMESITE_UNSET,
    208  schemeMap = Ci.nsICookie.SCHEME_UNSET,
    209  isPartitioned = false,
    210  updateTime = null
    211 ) {
    212  this.name = name;
    213  this.value = value;
    214  this.host = host;
    215  this.path = path;
    216  this.expiry = expiry;
    217  this.lastAccessed = lastAccessed;
    218  this.creationTime = creationTime;
    219  this.isSession = isSession;
    220  this.isSecure = isSecure;
    221  this.isHttpOnly = isHttpOnly;
    222  this.inBrowserElement = inBrowserElement;
    223  this.originAttributes = originAttributes;
    224  this.sameSite = sameSite;
    225  this.schemeMap = schemeMap;
    226  this.isPartitioned = isPartitioned;
    227  this.updateTime = updateTime || creationTime;
    228 
    229  // For pre version 15 compatibility:
    230  this.rawSameSite = sameSite;
    231 
    232  let strippedHost = host.charAt(0) == "." ? host.slice(1) : host;
    233 
    234  try {
    235    this.baseDomain = Services.eTLD.getBaseDomainFromHost(strippedHost);
    236  } catch (e) {
    237    if (
    238      e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS ||
    239      e.result == Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS
    240    ) {
    241      this.baseDomain = strippedHost;
    242    }
    243  }
    244 }
    245 
    246 // Object representing a database connection and associated statements. The
    247 // implementation varies depending on schema version.
    248 function CookieDatabaseConnection(file, schema) {
    249  // Manually generate a cookies.sqlite file with appropriate rows, columns,
    250  // and schema version. If it already exists, just set up our statements.
    251  let exists = file.exists();
    252 
    253  this.db = Services.storage.openDatabase(file);
    254  this.schema = schema;
    255  if (!exists) {
    256    this.db.schemaVersion = schema;
    257  }
    258 
    259  switch (schema) {
    260    case 1: {
    261      if (!exists) {
    262        this.db.executeSimpleSQL(
    263          "CREATE TABLE moz_cookies (       \
    264             id INTEGER PRIMARY KEY,        \
    265             name TEXT,                     \
    266             value TEXT,                    \
    267             host TEXT,                     \
    268             path TEXT,                     \
    269             expiry INTEGER,                \
    270             isSecure INTEGER,              \
    271             isHttpOnly INTEGER)"
    272        );
    273      }
    274 
    275      this.stmtInsert = this.db.createStatement(
    276        "INSERT INTO moz_cookies (        \
    277           id,                            \
    278           name,                          \
    279           value,                         \
    280           host,                          \
    281           path,                          \
    282           expiry,                        \
    283           isSecure,                      \
    284           isHttpOnly)                    \
    285           VALUES (                       \
    286           :id,                           \
    287           :name,                         \
    288           :value,                        \
    289           :host,                         \
    290           :path,                         \
    291           :expiry,                       \
    292           :isSecure,                     \
    293           :isHttpOnly)"
    294      );
    295 
    296      this.stmtDelete = this.db.createStatement(
    297        "DELETE FROM moz_cookies WHERE id = :id"
    298      );
    299 
    300      break;
    301    }
    302 
    303    case 2: {
    304      if (!exists) {
    305        this.db.executeSimpleSQL(
    306          "CREATE TABLE moz_cookies (       \
    307             id INTEGER PRIMARY KEY,        \
    308             name TEXT,                     \
    309             value TEXT,                    \
    310             host TEXT,                     \
    311             path TEXT,                     \
    312             expiry INTEGER,                \
    313             lastAccessed INTEGER,          \
    314             isSecure INTEGER,              \
    315             isHttpOnly INTEGER)"
    316        );
    317      }
    318 
    319      this.stmtInsert = this.db.createStatement(
    320        "INSERT OR REPLACE INTO moz_cookies ( \
    321           id,                            \
    322           name,                          \
    323           value,                         \
    324           host,                          \
    325           path,                          \
    326           expiry,                        \
    327           lastAccessed,                  \
    328           isSecure,                      \
    329           isHttpOnly)                    \
    330           VALUES (                       \
    331           :id,                           \
    332           :name,                         \
    333           :value,                        \
    334           :host,                         \
    335           :path,                         \
    336           :expiry,                       \
    337           :lastAccessed,                 \
    338           :isSecure,                     \
    339           :isHttpOnly)"
    340      );
    341 
    342      this.stmtDelete = this.db.createStatement(
    343        "DELETE FROM moz_cookies WHERE id = :id"
    344      );
    345 
    346      this.stmtUpdate = this.db.createStatement(
    347        "UPDATE moz_cookies SET lastAccessed = :lastAccessed WHERE id = :id"
    348      );
    349 
    350      break;
    351    }
    352 
    353    case 3: {
    354      if (!exists) {
    355        this.db.executeSimpleSQL(
    356          "CREATE TABLE moz_cookies (       \
    357            id INTEGER PRIMARY KEY,         \
    358            baseDomain TEXT,                \
    359            name TEXT,                      \
    360            value TEXT,                     \
    361            host TEXT,                      \
    362            path TEXT,                      \
    363            expiry INTEGER,                 \
    364            lastAccessed INTEGER,           \
    365            isSecure INTEGER,               \
    366            isHttpOnly INTEGER)"
    367        );
    368 
    369        this.db.executeSimpleSQL(
    370          "CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)"
    371        );
    372      }
    373 
    374      this.stmtInsert = this.db.createStatement(
    375        "INSERT INTO moz_cookies (        \
    376           id,                            \
    377           baseDomain,                    \
    378           name,                          \
    379           value,                         \
    380           host,                          \
    381           path,                          \
    382           expiry,                        \
    383           lastAccessed,                  \
    384           isSecure,                      \
    385           isHttpOnly)                    \
    386           VALUES (                       \
    387           :id,                           \
    388           :baseDomain,                   \
    389           :name,                         \
    390           :value,                        \
    391           :host,                         \
    392           :path,                         \
    393           :expiry,                       \
    394           :lastAccessed,                 \
    395           :isSecure,                     \
    396           :isHttpOnly)"
    397      );
    398 
    399      this.stmtDelete = this.db.createStatement(
    400        "DELETE FROM moz_cookies WHERE id = :id"
    401      );
    402 
    403      this.stmtUpdate = this.db.createStatement(
    404        "UPDATE moz_cookies SET lastAccessed = :lastAccessed WHERE id = :id"
    405      );
    406 
    407      break;
    408    }
    409 
    410    case 4: {
    411      if (!exists) {
    412        this.db.executeSimpleSQL(
    413          "CREATE TABLE moz_cookies (       \
    414            id INTEGER PRIMARY KEY,         \
    415            baseDomain TEXT,                \
    416            name TEXT,                      \
    417            value TEXT,                     \
    418            host TEXT,                      \
    419            path TEXT,                      \
    420            expiry INTEGER,                 \
    421            lastAccessed INTEGER,           \
    422            creationTime INTEGER,           \
    423            isSecure INTEGER,               \
    424            isHttpOnly INTEGER              \
    425            CONSTRAINT moz_uniqueid UNIQUE (name, host, path))"
    426        );
    427 
    428        this.db.executeSimpleSQL(
    429          "CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)"
    430        );
    431 
    432        this.db.executeSimpleSQL("PRAGMA journal_mode = WAL");
    433      }
    434 
    435      this.stmtInsert = this.db.createStatement(
    436        "INSERT INTO moz_cookies (        \
    437           baseDomain,                    \
    438           name,                          \
    439           value,                         \
    440           host,                          \
    441           path,                          \
    442           expiry,                        \
    443           lastAccessed,                  \
    444           creationTime,                  \
    445           isSecure,                      \
    446           isHttpOnly)                    \
    447           VALUES (                       \
    448           :baseDomain,                   \
    449           :name,                         \
    450           :value,                        \
    451           :host,                         \
    452           :path,                         \
    453           :expiry,                       \
    454           :lastAccessed,                 \
    455           :creationTime,                 \
    456           :isSecure,                     \
    457           :isHttpOnly)"
    458      );
    459 
    460      this.stmtDelete = this.db.createStatement(
    461        "DELETE FROM moz_cookies          \
    462           WHERE name = :name AND host = :host AND path = :path"
    463      );
    464 
    465      this.stmtUpdate = this.db.createStatement(
    466        "UPDATE moz_cookies SET lastAccessed = :lastAccessed \
    467           WHERE name = :name AND host = :host AND path = :path"
    468      );
    469 
    470      break;
    471    }
    472 
    473    case 10: {
    474      if (!exists) {
    475        this.db.executeSimpleSQL(
    476          "CREATE TABLE moz_cookies (                  \
    477            id INTEGER PRIMARY KEY,                    \
    478            baseDomain TEXT,                           \
    479            originAttributes TEXT NOT NULL DEFAULT '', \
    480            name TEXT,                                 \
    481            value TEXT,                                \
    482            host TEXT,                                 \
    483            path TEXT,                                 \
    484            expiry INTEGER,                            \
    485            lastAccessed INTEGER,                      \
    486            creationTime INTEGER,                      \
    487            isSecure INTEGER,                          \
    488            isHttpOnly INTEGER,                        \
    489            inBrowserElement INTEGER DEFAULT 0,        \
    490            sameSite INTEGER DEFAULT 0,                \
    491            rawSameSite INTEGER DEFAULT 0,             \
    492            CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))"
    493        );
    494 
    495        this.db.executeSimpleSQL(
    496          "CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)"
    497        );
    498 
    499        this.db.executeSimpleSQL("PRAGMA journal_mode = WAL");
    500        this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16");
    501      }
    502 
    503      this.stmtInsert = this.db.createStatement(
    504        "INSERT INTO moz_cookies (        \
    505           name,                          \
    506           value,                         \
    507           host,                          \
    508           baseDomain,                    \
    509           path,                          \
    510           expiry,                        \
    511           lastAccessed,                  \
    512           creationTime,                  \
    513           isSecure,                      \
    514           isHttpOnly,                    \
    515           inBrowserElement,              \
    516           originAttributes,              \
    517           sameSite,                      \
    518           rawSameSite                    \
    519         ) VALUES (                       \
    520           :name,                         \
    521           :value,                        \
    522           :host,                         \
    523           :baseDomain,                   \
    524           :path,                         \
    525           :expiry,                       \
    526           :lastAccessed,                 \
    527           :creationTime,                 \
    528           :isSecure,                     \
    529           :isHttpOnly,                   \
    530           :inBrowserElement,             \
    531           :originAttributes,             \
    532           :sameSite,                     \
    533           :rawSameSite)"
    534      );
    535 
    536      this.stmtDelete = this.db.createStatement(
    537        "DELETE FROM moz_cookies          \
    538           WHERE name = :name AND host = :host AND path = :path AND \
    539                 originAttributes = :originAttributes"
    540      );
    541 
    542      this.stmtUpdate = this.db.createStatement(
    543        "UPDATE moz_cookies SET lastAccessed = :lastAccessed \
    544           WHERE name = :name AND host = :host AND path = :path AND \
    545                 originAttributes = :originAttributes"
    546      );
    547 
    548      break;
    549    }
    550 
    551    case 11: {
    552      if (!exists) {
    553        this.db.executeSimpleSQL(
    554          "CREATE TABLE moz_cookies (                  \
    555            id INTEGER PRIMARY KEY,                    \
    556            originAttributes TEXT NOT NULL DEFAULT '', \
    557            name TEXT,                                 \
    558            value TEXT,                                \
    559            host TEXT,                                 \
    560            path TEXT,                                 \
    561            expiry INTEGER,                            \
    562            lastAccessed INTEGER,                      \
    563            creationTime INTEGER,                      \
    564            isSecure INTEGER,                          \
    565            isHttpOnly INTEGER,                        \
    566            inBrowserElement INTEGER DEFAULT 0,        \
    567            sameSite INTEGER DEFAULT 0,                \
    568            rawSameSite INTEGER DEFAULT 0,             \
    569            CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))"
    570        );
    571 
    572        this.db.executeSimpleSQL("PRAGMA journal_mode = WAL");
    573        this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16");
    574      }
    575 
    576      this.stmtInsert = this.db.createStatement(
    577        "INSERT INTO moz_cookies (        \
    578           name,                          \
    579           value,                         \
    580           host,                          \
    581           path,                          \
    582           expiry,                        \
    583           lastAccessed,                  \
    584           creationTime,                  \
    585           isSecure,                      \
    586           isHttpOnly,                    \
    587           inBrowserElement,              \
    588           originAttributes,              \
    589           sameSite,                      \
    590           rawSameSite                    \
    591         ) VALUES (                       \
    592           :name,                         \
    593           :value,                        \
    594           :host,                         \
    595           :path,                         \
    596           :expiry,                       \
    597           :lastAccessed,                 \
    598           :creationTime,                 \
    599           :isSecure,                     \
    600           :isHttpOnly,                   \
    601           :inBrowserElement,             \
    602           :originAttributes,             \
    603           :sameSite,                     \
    604           :rawSameSite)"
    605      );
    606 
    607      this.stmtDelete = this.db.createStatement(
    608        "DELETE FROM moz_cookies          \
    609           WHERE name = :name AND host = :host AND path = :path AND \
    610                 originAttributes = :originAttributes"
    611      );
    612 
    613      this.stmtUpdate = this.db.createStatement(
    614        "UPDATE moz_cookies SET lastAccessed = :lastAccessed \
    615           WHERE name = :name AND host = :host AND path = :path AND \
    616                 originAttributes = :originAttributes"
    617      );
    618 
    619      break;
    620    }
    621 
    622    case 12: {
    623      if (!exists) {
    624        this.db.executeSimpleSQL(
    625          "CREATE TABLE moz_cookies (                  \
    626            id INTEGER PRIMARY KEY,                    \
    627            originAttributes TEXT NOT NULL DEFAULT '', \
    628            name TEXT,                                 \
    629            value TEXT,                                \
    630            host TEXT,                                 \
    631            path TEXT,                                 \
    632            expiry INTEGER,                            \
    633            lastAccessed INTEGER,                      \
    634            creationTime INTEGER,                      \
    635            isSecure INTEGER,                          \
    636            isHttpOnly INTEGER,                        \
    637            inBrowserElement INTEGER DEFAULT 0,        \
    638            sameSite INTEGER DEFAULT 0,                \
    639            rawSameSite INTEGER DEFAULT 0,             \
    640            schemeMap INTEGER DEFAULT 0,               \
    641            CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))"
    642        );
    643 
    644        this.db.executeSimpleSQL("PRAGMA journal_mode = WAL");
    645        this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16");
    646      }
    647 
    648      this.stmtInsert = this.db.createStatement(
    649        "INSERT INTO moz_cookies (        \
    650           name,                          \
    651           value,                         \
    652           host,                          \
    653           path,                          \
    654           expiry,                        \
    655           lastAccessed,                  \
    656           creationTime,                  \
    657           isSecure,                      \
    658           isHttpOnly,                    \
    659           inBrowserElement,              \
    660           originAttributes,              \
    661           sameSite,                      \
    662           rawSameSite,                   \
    663           schemeMap                      \
    664         ) VALUES (                       \
    665           :name,                         \
    666           :value,                        \
    667           :host,                         \
    668           :path,                         \
    669           :expiry,                       \
    670           :lastAccessed,                 \
    671           :creationTime,                 \
    672           :isSecure,                     \
    673           :isHttpOnly,                   \
    674           :inBrowserElement,             \
    675           :originAttributes,             \
    676           :sameSite,                     \
    677           :rawSameSite,                  \
    678           :schemeMap)"
    679      );
    680 
    681      this.stmtDelete = this.db.createStatement(
    682        "DELETE FROM moz_cookies          \
    683           WHERE name = :name AND host = :host AND path = :path AND \
    684                 originAttributes = :originAttributes"
    685      );
    686 
    687      this.stmtUpdate = this.db.createStatement(
    688        "UPDATE moz_cookies SET lastAccessed = :lastAccessed \
    689           WHERE name = :name AND host = :host AND path = :path AND \
    690                 originAttributes = :originAttributes"
    691      );
    692 
    693      break;
    694    }
    695 
    696    case 13:
    697    case 14: {
    698      if (!exists) {
    699        this.db.executeSimpleSQL(
    700          "CREATE TABLE moz_cookies (                     \
    701            id INTEGER PRIMARY KEY,                       \
    702            originAttributes TEXT NOT NULL DEFAULT '',    \
    703            name TEXT,                                    \
    704            value TEXT,                                   \
    705            host TEXT,                                    \
    706            path TEXT,                                    \
    707            expiry INTEGER,                               \
    708            lastAccessed INTEGER,                         \
    709            creationTime INTEGER,                         \
    710            isSecure INTEGER,                             \
    711            isHttpOnly INTEGER,                           \
    712            inBrowserElement INTEGER DEFAULT 0,           \
    713            sameSite INTEGER DEFAULT 0,                   \
    714            rawSameSite INTEGER DEFAULT 0,                \
    715            schemeMap INTEGER DEFAULT 0,                  \
    716            isPartitionedAttributeSet INTEGER DEFAULT 0,  \
    717            CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))"
    718        );
    719 
    720        this.db.executeSimpleSQL("PRAGMA journal_mode = WAL");
    721        this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16");
    722      }
    723 
    724      this.stmtInsert = this.db.createStatement(
    725        "INSERT INTO moz_cookies (        \
    726           name,                          \
    727           value,                         \
    728           host,                          \
    729           path,                          \
    730           expiry,                        \
    731           lastAccessed,                  \
    732           creationTime,                  \
    733           isSecure,                      \
    734           isHttpOnly,                    \
    735           inBrowserElement,              \
    736           originAttributes,              \
    737           sameSite,                      \
    738           rawSameSite,                   \
    739           schemeMap,                     \
    740           isPartitionedAttributeSet      \
    741         ) VALUES (                       \
    742           :name,                         \
    743           :value,                        \
    744           :host,                         \
    745           :path,                         \
    746           :expiry,                       \
    747           :lastAccessed,                 \
    748           :creationTime,                 \
    749           :isSecure,                     \
    750           :isHttpOnly,                   \
    751           :inBrowserElement,             \
    752           :originAttributes,             \
    753           :sameSite,                     \
    754           :rawSameSite,                  \
    755           :schemeMap,                    \
    756           :isPartitionedAttributeSet)"
    757      );
    758 
    759      this.stmtDelete = this.db.createStatement(
    760        "DELETE FROM moz_cookies          \
    761           WHERE name = :name AND host = :host AND path = :path AND \
    762                 originAttributes = :originAttributes"
    763      );
    764 
    765      this.stmtUpdate = this.db.createStatement(
    766        "UPDATE moz_cookies SET lastAccessed = :lastAccessed \
    767           WHERE name = :name AND host = :host AND path = :path AND \
    768                 originAttributes = :originAttributes"
    769      );
    770 
    771      break;
    772    }
    773    case 15:
    774    case 16: {
    775      if (!exists) {
    776        this.db.executeSimpleSQL(
    777          "CREATE TABLE moz_cookies (                     \
    778            id INTEGER PRIMARY KEY,                       \
    779            originAttributes TEXT NOT NULL DEFAULT '',    \
    780            name TEXT,                                    \
    781            value TEXT,                                   \
    782            host TEXT,                                    \
    783            path TEXT,                                    \
    784            expiry INTEGER,                               \
    785            lastAccessed INTEGER,                         \
    786            creationTime INTEGER,                         \
    787            isSecure INTEGER,                             \
    788            isHttpOnly INTEGER,                           \
    789            inBrowserElement INTEGER DEFAULT 0,           \
    790            sameSite INTEGER DEFAULT 0,                   \
    791            schemeMap INTEGER DEFAULT 0,                  \
    792            isPartitionedAttributeSet INTEGER DEFAULT 0,  \
    793            CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))"
    794        );
    795 
    796        this.db.executeSimpleSQL("PRAGMA journal_mode = WAL");
    797        this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16");
    798      }
    799 
    800      this.stmtInsert = this.db.createStatement(
    801        "INSERT INTO moz_cookies (        \
    802           name,                          \
    803           value,                         \
    804           host,                          \
    805           path,                          \
    806           expiry,                        \
    807           lastAccessed,                  \
    808           creationTime,                  \
    809           isSecure,                      \
    810           isHttpOnly,                    \
    811           inBrowserElement,              \
    812           originAttributes,              \
    813           sameSite,                      \
    814           schemeMap,                     \
    815           isPartitionedAttributeSet      \
    816         ) VALUES (                       \
    817           :name,                         \
    818           :value,                        \
    819           :host,                         \
    820           :path,                         \
    821           :expiry,                       \
    822           :lastAccessed,                 \
    823           :creationTime,                 \
    824           :isSecure,                     \
    825           :isHttpOnly,                   \
    826           :inBrowserElement,             \
    827           :originAttributes,             \
    828           :sameSite,                     \
    829           :schemeMap,                    \
    830           :isPartitionedAttributeSet)"
    831      );
    832 
    833      this.stmtDelete = this.db.createStatement(
    834        "DELETE FROM moz_cookies          \
    835           WHERE name = :name AND host = :host AND path = :path AND \
    836                 originAttributes = :originAttributes"
    837      );
    838 
    839      this.stmtUpdate = this.db.createStatement(
    840        "UPDATE moz_cookies SET lastAccessed = :lastAccessed \
    841           WHERE name = :name AND host = :host AND path = :path AND \
    842                 originAttributes = :originAttributes"
    843      );
    844 
    845      break;
    846    }
    847 
    848    case 17: {
    849      if (!exists) {
    850        this.db.executeSimpleSQL(
    851          "CREATE TABLE moz_cookies (                     \
    852            id INTEGER PRIMARY KEY,                       \
    853            originAttributes TEXT NOT NULL DEFAULT '',    \
    854            name TEXT,                                    \
    855            value TEXT,                                   \
    856            host TEXT,                                    \
    857            path TEXT,                                    \
    858            expiry INTEGER,                               \
    859            lastAccessed INTEGER,                         \
    860            creationTime INTEGER,                         \
    861            isSecure INTEGER,                             \
    862            isHttpOnly INTEGER,                           \
    863            inBrowserElement INTEGER DEFAULT 0,           \
    864            sameSite INTEGER DEFAULT 0,                   \
    865            schemeMap INTEGER DEFAULT 0,                  \
    866            isPartitionedAttributeSet INTEGER DEFAULT 0,  \
    867            updateTime INTEGER,                           \
    868            CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))"
    869        );
    870 
    871        this.db.executeSimpleSQL("PRAGMA journal_mode = WAL");
    872        this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16");
    873      }
    874 
    875      this.stmtInsert = this.db.createStatement(
    876        "INSERT INTO moz_cookies (        \
    877           name,                          \
    878           value,                         \
    879           host,                          \
    880           path,                          \
    881           expiry,                        \
    882           lastAccessed,                  \
    883           creationTime,                  \
    884           isSecure,                      \
    885           isHttpOnly,                    \
    886           inBrowserElement,              \
    887           originAttributes,              \
    888           sameSite,                      \
    889           schemeMap,                     \
    890           isPartitionedAttributeSet,     \
    891           updateTime                     \
    892         ) VALUES (                       \
    893           :name,                         \
    894           :value,                        \
    895           :host,                         \
    896           :path,                         \
    897           :expiry,                       \
    898           :lastAccessed,                 \
    899           :creationTime,                 \
    900           :isSecure,                     \
    901           :isHttpOnly,                   \
    902           :inBrowserElement,             \
    903           :originAttributes,             \
    904           :sameSite,                     \
    905           :schemeMap,                    \
    906           :isPartitionedAttributeSet,    \
    907           :updateTime)"
    908      );
    909 
    910      this.stmtDelete = this.db.createStatement(
    911        "DELETE FROM moz_cookies          \
    912           WHERE name = :name AND host = :host AND path = :path AND \
    913                 originAttributes = :originAttributes"
    914      );
    915 
    916      this.stmtUpdate = this.db.createStatement(
    917        "UPDATE moz_cookies SET lastAccessed = :lastAccessed \
    918           WHERE name = :name AND host = :host AND path = :path AND \
    919                 originAttributes = :originAttributes"
    920      );
    921 
    922      break;
    923    }
    924 
    925    default:
    926      do_throw("unrecognized schemaVersion!");
    927  }
    928 }
    929 
    930 CookieDatabaseConnection.prototype = {
    931  insertCookie(cookie) {
    932    if (!(cookie instanceof Cookie)) {
    933      do_throw("not a cookie");
    934    }
    935 
    936    switch (this.schema) {
    937      case 1:
    938        this.stmtInsert.bindByName("id", cookie.creationTime);
    939        this.stmtInsert.bindByName("name", cookie.name);
    940        this.stmtInsert.bindByName("value", cookie.value);
    941        this.stmtInsert.bindByName("host", cookie.host);
    942        this.stmtInsert.bindByName("path", cookie.path);
    943        this.stmtInsert.bindByName("expiry", cookie.expiry);
    944        this.stmtInsert.bindByName("isSecure", cookie.isSecure);
    945        this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
    946        break;
    947 
    948      case 2:
    949        this.stmtInsert.bindByName("id", cookie.creationTime);
    950        this.stmtInsert.bindByName("name", cookie.name);
    951        this.stmtInsert.bindByName("value", cookie.value);
    952        this.stmtInsert.bindByName("host", cookie.host);
    953        this.stmtInsert.bindByName("path", cookie.path);
    954        this.stmtInsert.bindByName("expiry", cookie.expiry);
    955        this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
    956        this.stmtInsert.bindByName("isSecure", cookie.isSecure);
    957        this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
    958        break;
    959 
    960      case 3:
    961        this.stmtInsert.bindByName("id", cookie.creationTime);
    962        this.stmtInsert.bindByName("baseDomain", cookie.baseDomain);
    963        this.stmtInsert.bindByName("name", cookie.name);
    964        this.stmtInsert.bindByName("value", cookie.value);
    965        this.stmtInsert.bindByName("host", cookie.host);
    966        this.stmtInsert.bindByName("path", cookie.path);
    967        this.stmtInsert.bindByName("expiry", cookie.expiry);
    968        this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
    969        this.stmtInsert.bindByName("isSecure", cookie.isSecure);
    970        this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
    971        break;
    972 
    973      case 4:
    974        this.stmtInsert.bindByName("baseDomain", cookie.baseDomain);
    975        this.stmtInsert.bindByName("name", cookie.name);
    976        this.stmtInsert.bindByName("value", cookie.value);
    977        this.stmtInsert.bindByName("host", cookie.host);
    978        this.stmtInsert.bindByName("path", cookie.path);
    979        this.stmtInsert.bindByName("expiry", cookie.expiry);
    980        this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
    981        this.stmtInsert.bindByName("creationTime", cookie.creationTime);
    982        this.stmtInsert.bindByName("isSecure", cookie.isSecure);
    983        this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
    984        break;
    985 
    986      case 10:
    987        this.stmtInsert.bindByName("name", cookie.name);
    988        this.stmtInsert.bindByName("value", cookie.value);
    989        this.stmtInsert.bindByName("host", cookie.host);
    990        this.stmtInsert.bindByName("baseDomain", cookie.baseDomain);
    991        this.stmtInsert.bindByName("path", cookie.path);
    992        this.stmtInsert.bindByName("expiry", cookie.expiry);
    993        this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
    994        this.stmtInsert.bindByName("creationTime", cookie.creationTime);
    995        this.stmtInsert.bindByName("isSecure", cookie.isSecure);
    996        this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
    997        this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement);
    998        this.stmtInsert.bindByName(
    999          "originAttributes",
   1000          ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
   1001        );
   1002        this.stmtInsert.bindByName("sameSite", cookie.sameSite);
   1003        this.stmtInsert.bindByName("rawSameSite", cookie.rawSameSite);
   1004        break;
   1005 
   1006      case 11:
   1007        this.stmtInsert.bindByName("name", cookie.name);
   1008        this.stmtInsert.bindByName("value", cookie.value);
   1009        this.stmtInsert.bindByName("host", cookie.host);
   1010        this.stmtInsert.bindByName("path", cookie.path);
   1011        this.stmtInsert.bindByName("expiry", cookie.expiry);
   1012        this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
   1013        this.stmtInsert.bindByName("creationTime", cookie.creationTime);
   1014        this.stmtInsert.bindByName("isSecure", cookie.isSecure);
   1015        this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
   1016        this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement);
   1017        this.stmtInsert.bindByName(
   1018          "originAttributes",
   1019          ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
   1020        );
   1021        this.stmtInsert.bindByName("sameSite", cookie.sameSite);
   1022        this.stmtInsert.bindByName("rawSameSite", cookie.rawSameSite);
   1023        break;
   1024 
   1025      case 12:
   1026        this.stmtInsert.bindByName("name", cookie.name);
   1027        this.stmtInsert.bindByName("value", cookie.value);
   1028        this.stmtInsert.bindByName("host", cookie.host);
   1029        this.stmtInsert.bindByName("path", cookie.path);
   1030        this.stmtInsert.bindByName("expiry", cookie.expiry);
   1031        this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
   1032        this.stmtInsert.bindByName("creationTime", cookie.creationTime);
   1033        this.stmtInsert.bindByName("isSecure", cookie.isSecure);
   1034        this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
   1035        this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement);
   1036        this.stmtInsert.bindByName(
   1037          "originAttributes",
   1038          ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
   1039        );
   1040        this.stmtInsert.bindByName("sameSite", cookie.sameSite);
   1041        this.stmtInsert.bindByName("rawSameSite", cookie.rawSameSite);
   1042        this.stmtInsert.bindByName("schemeMap", cookie.schemeMap);
   1043        break;
   1044 
   1045      case 13:
   1046      case 14:
   1047        this.stmtInsert.bindByName("name", cookie.name);
   1048        this.stmtInsert.bindByName("value", cookie.value);
   1049        this.stmtInsert.bindByName("host", cookie.host);
   1050        this.stmtInsert.bindByName("path", cookie.path);
   1051        this.stmtInsert.bindByName("expiry", cookie.expiry);
   1052        this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
   1053        this.stmtInsert.bindByName("creationTime", cookie.creationTime);
   1054        this.stmtInsert.bindByName("isSecure", cookie.isSecure);
   1055        this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
   1056        this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement);
   1057        this.stmtInsert.bindByName(
   1058          "originAttributes",
   1059          ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
   1060        );
   1061        this.stmtInsert.bindByName("sameSite", cookie.sameSite);
   1062        this.stmtInsert.bindByName("rawSameSite", cookie.rawSameSite);
   1063        this.stmtInsert.bindByName("schemeMap", cookie.schemeMap);
   1064        this.stmtInsert.bindByName(
   1065          "isPartitionedAttributeSet",
   1066          cookie.isPartitioned
   1067        );
   1068        break;
   1069 
   1070      case 15:
   1071      case 16:
   1072        this.stmtInsert.bindByName("name", cookie.name);
   1073        this.stmtInsert.bindByName("value", cookie.value);
   1074        this.stmtInsert.bindByName("host", cookie.host);
   1075        this.stmtInsert.bindByName("path", cookie.path);
   1076        this.stmtInsert.bindByName("expiry", cookie.expiry);
   1077        this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
   1078        this.stmtInsert.bindByName("creationTime", cookie.creationTime);
   1079        this.stmtInsert.bindByName("isSecure", cookie.isSecure);
   1080        this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
   1081        this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement);
   1082        this.stmtInsert.bindByName(
   1083          "originAttributes",
   1084          ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
   1085        );
   1086        this.stmtInsert.bindByName("sameSite", cookie.sameSite);
   1087        this.stmtInsert.bindByName("schemeMap", cookie.schemeMap);
   1088        this.stmtInsert.bindByName(
   1089          "isPartitionedAttributeSet",
   1090          cookie.isPartitioned
   1091        );
   1092        break;
   1093 
   1094      case 17:
   1095        this.stmtInsert.bindByName("name", cookie.name);
   1096        this.stmtInsert.bindByName("value", cookie.value);
   1097        this.stmtInsert.bindByName("host", cookie.host);
   1098        this.stmtInsert.bindByName("path", cookie.path);
   1099        this.stmtInsert.bindByName("expiry", cookie.expiry);
   1100        this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
   1101        this.stmtInsert.bindByName("creationTime", cookie.creationTime);
   1102        this.stmtInsert.bindByName("isSecure", cookie.isSecure);
   1103        this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
   1104        this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement);
   1105        this.stmtInsert.bindByName(
   1106          "originAttributes",
   1107          ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
   1108        );
   1109        this.stmtInsert.bindByName("sameSite", cookie.sameSite);
   1110        this.stmtInsert.bindByName("schemeMap", cookie.schemeMap);
   1111        this.stmtInsert.bindByName(
   1112          "isPartitionedAttributeSet",
   1113          cookie.isPartitioned
   1114        );
   1115        this.stmtInsert.bindByName("updateTime", cookie.updateTime);
   1116        break;
   1117 
   1118      default:
   1119        do_throw("unrecognized schemaVersion!");
   1120    }
   1121 
   1122    do_execute_stmt(this.stmtInsert);
   1123  },
   1124 
   1125  deleteCookie(cookie) {
   1126    if (!(cookie instanceof Cookie)) {
   1127      do_throw("not a cookie");
   1128    }
   1129 
   1130    switch (this.db.schemaVersion) {
   1131      case 1:
   1132      case 2:
   1133      case 3:
   1134        this.stmtDelete.bindByName("id", cookie.creationTime);
   1135        break;
   1136 
   1137      case 4:
   1138        this.stmtDelete.bindByName("name", cookie.name);
   1139        this.stmtDelete.bindByName("host", cookie.host);
   1140        this.stmtDelete.bindByName("path", cookie.path);
   1141        break;
   1142 
   1143      case 10:
   1144      case 11:
   1145      case 12:
   1146      case 13:
   1147      case 14:
   1148      case 15:
   1149      case 16:
   1150      case 17:
   1151        this.stmtDelete.bindByName("name", cookie.name);
   1152        this.stmtDelete.bindByName("host", cookie.host);
   1153        this.stmtDelete.bindByName("path", cookie.path);
   1154        this.stmtDelete.bindByName(
   1155          "originAttributes",
   1156          ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
   1157        );
   1158        break;
   1159 
   1160      default:
   1161        do_throw("unrecognized schemaVersion!");
   1162    }
   1163 
   1164    do_execute_stmt(this.stmtDelete);
   1165  },
   1166 
   1167  updateCookie(cookie) {
   1168    if (!(cookie instanceof Cookie)) {
   1169      do_throw("not a cookie");
   1170    }
   1171 
   1172    switch (this.db.schemaVersion) {
   1173      case 1:
   1174        do_throw("can't update a schema 1 cookie!");
   1175        break;
   1176      case 2:
   1177      case 3:
   1178        this.stmtUpdate.bindByName("id", cookie.creationTime);
   1179        this.stmtUpdate.bindByName("lastAccessed", cookie.lastAccessed);
   1180        break;
   1181 
   1182      case 4:
   1183        this.stmtDelete.bindByName("name", cookie.name);
   1184        this.stmtDelete.bindByName("host", cookie.host);
   1185        this.stmtDelete.bindByName("path", cookie.path);
   1186        this.stmtUpdate.bindByName("name", cookie.name);
   1187        this.stmtUpdate.bindByName("host", cookie.host);
   1188        this.stmtUpdate.bindByName("path", cookie.path);
   1189        this.stmtUpdate.bindByName("lastAccessed", cookie.lastAccessed);
   1190        break;
   1191 
   1192      case 10:
   1193      case 11:
   1194      case 12:
   1195      case 13:
   1196      case 14:
   1197      case 15:
   1198      case 16:
   1199      case 17:
   1200        this.stmtDelete.bindByName("name", cookie.name);
   1201        this.stmtDelete.bindByName("host", cookie.host);
   1202        this.stmtDelete.bindByName("path", cookie.path);
   1203        this.stmtDelete.bindByName(
   1204          "originAttributes",
   1205          ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
   1206        );
   1207        this.stmtUpdate.bindByName("name", cookie.name);
   1208        this.stmtUpdate.bindByName("host", cookie.host);
   1209        this.stmtUpdate.bindByName("path", cookie.path);
   1210        this.stmtUpdate.bindByName(
   1211          "originAttributes",
   1212          ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
   1213        );
   1214        this.stmtUpdate.bindByName("lastAccessed", cookie.lastAccessed);
   1215        break;
   1216 
   1217      default:
   1218        do_throw("unrecognized schemaVersion!");
   1219    }
   1220 
   1221    do_execute_stmt(this.stmtUpdate);
   1222  },
   1223 
   1224  close() {
   1225    this.stmtInsert.finalize();
   1226    this.stmtDelete.finalize();
   1227    if (this.stmtUpdate) {
   1228      this.stmtUpdate.finalize();
   1229    }
   1230    this.db.close();
   1231 
   1232    this.stmtInsert = null;
   1233    this.stmtDelete = null;
   1234    this.stmtUpdate = null;
   1235    this.db = null;
   1236  },
   1237 };
   1238 
   1239 function do_get_cookie_file(profile) {
   1240  let file = profile.clone();
   1241  file.append("cookies.sqlite");
   1242  return file;
   1243 }
   1244 
   1245 // Count the cookies from 'host' in a database. If 'host' is null, count all
   1246 // cookies.
   1247 function do_count_cookies_in_db(connection, host) {
   1248  let select = null;
   1249  if (host) {
   1250    select = connection.createStatement(
   1251      "SELECT COUNT(1) FROM moz_cookies WHERE host = :host"
   1252    );
   1253    select.bindByName("host", host);
   1254  } else {
   1255    select = connection.createStatement("SELECT COUNT(1) FROM moz_cookies");
   1256  }
   1257 
   1258  select.executeStep();
   1259  let result = select.getInt32(0);
   1260  select.reset();
   1261  select.finalize();
   1262  return result;
   1263 }
   1264 
   1265 // Execute 'stmt', ensuring that we reset it if it throws.
   1266 function do_execute_stmt(stmt) {
   1267  try {
   1268    stmt.executeStep();
   1269    stmt.reset();
   1270  } catch (e) {
   1271    stmt.reset();
   1272    throw e;
   1273  }
   1274 }