1163 lines
41 KiB
JavaScript
1163 lines
41 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/
|
|
*/
|
|
|
|
/* import-globals-from head_cache.js */
|
|
|
|
"use strict";
|
|
|
|
const { NetUtil } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/NetUtil.sys.mjs"
|
|
);
|
|
const { CookieXPCShellUtils } = ChromeUtils.importESModule(
|
|
"resource://testing-common/CookieXPCShellUtils.sys.mjs"
|
|
);
|
|
|
|
// Don't pick up default permissions from profile.
|
|
Services.prefs.setCharPref("permissions.manager.defaultsUrl", "");
|
|
|
|
CookieXPCShellUtils.init(this);
|
|
|
|
function do_check_throws(f, result, stack) {
|
|
if (!stack) {
|
|
stack = Components.stack.caller;
|
|
}
|
|
|
|
try {
|
|
f();
|
|
} catch (exc) {
|
|
if (exc.result == result) {
|
|
return;
|
|
}
|
|
do_throw("expected result " + result + ", caught " + exc, stack);
|
|
}
|
|
do_throw("expected result " + result + ", none thrown", stack);
|
|
}
|
|
|
|
// Helper to step a generator function and catch a StopIteration exception.
|
|
function do_run_generator(generator) {
|
|
try {
|
|
generator.next();
|
|
} catch (e) {
|
|
do_throw("caught exception " + e, Components.stack.caller);
|
|
}
|
|
}
|
|
|
|
// Helper to finish a generator function test.
|
|
function do_finish_generator_test(generator) {
|
|
executeSoon(function () {
|
|
generator.return();
|
|
do_test_finished();
|
|
});
|
|
}
|
|
|
|
function _observer(generator, topic) {
|
|
Services.obs.addObserver(this, topic);
|
|
|
|
this.generator = generator;
|
|
this.topic = topic;
|
|
}
|
|
|
|
_observer.prototype = {
|
|
observe(subject, topic) {
|
|
Assert.equal(this.topic, topic);
|
|
|
|
Services.obs.removeObserver(this, this.topic);
|
|
|
|
// Continue executing the generator function.
|
|
if (this.generator) {
|
|
do_run_generator(this.generator);
|
|
}
|
|
|
|
this.generator = null;
|
|
this.topic = null;
|
|
},
|
|
};
|
|
|
|
// Close the cookie database. If a generator is supplied, it will be invoked
|
|
// once the close is complete.
|
|
function do_close_profile(generator) {
|
|
// Register an observer for db close.
|
|
new _observer(generator, "cookie-db-closed");
|
|
|
|
// Close the db.
|
|
let service = Services.cookies.QueryInterface(Ci.nsIObserver);
|
|
service.observe(null, "profile-before-change", null);
|
|
}
|
|
|
|
function _promise_observer(topic) {
|
|
Services.obs.addObserver(this, topic);
|
|
|
|
this.topic = topic;
|
|
return new Promise(resolve => (this.resolve = resolve));
|
|
}
|
|
|
|
_promise_observer.prototype = {
|
|
observe(subject, topic) {
|
|
Assert.equal(this.topic, topic);
|
|
|
|
Services.obs.removeObserver(this, this.topic);
|
|
if (this.resolve) {
|
|
this.resolve();
|
|
}
|
|
|
|
this.resolve = null;
|
|
this.topic = null;
|
|
},
|
|
};
|
|
|
|
// Close the cookie database. And resolve a promise.
|
|
function promise_close_profile() {
|
|
// Register an observer for db close.
|
|
let promise = new _promise_observer("cookie-db-closed");
|
|
|
|
// Close the db.
|
|
let service = Services.cookies.QueryInterface(Ci.nsIObserver);
|
|
service.observe(null, "profile-before-change", null);
|
|
|
|
return promise;
|
|
}
|
|
|
|
// Load the cookie database.
|
|
function promise_load_profile() {
|
|
// Register an observer for read completion.
|
|
let promise = new _promise_observer("cookie-db-read");
|
|
|
|
// Load the profile.
|
|
let service = Services.cookies.QueryInterface(Ci.nsIObserver);
|
|
service.observe(null, "profile-do-change", "");
|
|
|
|
return promise;
|
|
}
|
|
|
|
// Load the cookie database. If a generator is supplied, it will be invoked
|
|
// once the load is complete.
|
|
function do_load_profile(generator) {
|
|
// Register an observer for read completion.
|
|
new _observer(generator, "cookie-db-read");
|
|
|
|
// Load the profile.
|
|
let service = Services.cookies.QueryInterface(Ci.nsIObserver);
|
|
service.observe(null, "profile-do-change", "");
|
|
}
|
|
|
|
// Set a single session cookie using http and test the cookie count
|
|
// against 'expected'
|
|
function do_set_single_http_cookie(uri, channel, expected) {
|
|
Services.cookies.setCookieStringFromHttp(uri, "foo=bar", channel);
|
|
Assert.equal(Services.cookies.countCookiesFromHost(uri.host), expected);
|
|
}
|
|
|
|
// Set two cookies; via document.channel and via http request.
|
|
async function do_set_cookies(uri, channel, session, expected) {
|
|
let suffix = session ? "" : "; max-age=1000";
|
|
|
|
// via document.cookie
|
|
const thirdPartyUrl = "http://third.com/";
|
|
const contentPage = await CookieXPCShellUtils.loadContentPage(thirdPartyUrl);
|
|
await contentPage.spawn(
|
|
[
|
|
{
|
|
cookie: "can=has" + suffix,
|
|
url: uri.spec,
|
|
},
|
|
],
|
|
async function (obj) {
|
|
await new this.content.Promise(resolve => {
|
|
let doc = this.content.document;
|
|
let ifr = doc.createElement("iframe");
|
|
ifr.src = obj.url;
|
|
doc.body.appendChild(ifr);
|
|
ifr.addEventListener("load", async () => {
|
|
await this.SpecialPowers.spawn(ifr, [obj.cookie], cookie => {
|
|
this.content.document.cookie = cookie;
|
|
});
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
);
|
|
await contentPage.close();
|
|
|
|
Assert.equal(Services.cookies.countCookiesFromHost(uri.host), expected[0]);
|
|
|
|
// via http request
|
|
Services.cookies.setCookieStringFromHttp(uri, "hot=dog" + suffix, channel);
|
|
Assert.equal(Services.cookies.countCookiesFromHost(uri.host), expected[1]);
|
|
}
|
|
|
|
function do_count_cookies() {
|
|
return Services.cookies.cookies.length;
|
|
}
|
|
|
|
// Helper object to store cookie data.
|
|
function Cookie(
|
|
name,
|
|
value,
|
|
host,
|
|
path,
|
|
expiry,
|
|
lastAccessed,
|
|
creationTime,
|
|
isSession,
|
|
isSecure,
|
|
isHttpOnly,
|
|
inBrowserElement = false,
|
|
originAttributes = {},
|
|
sameSite = Ci.nsICookie.SAMESITE_UNSET,
|
|
schemeMap = Ci.nsICookie.SCHEME_UNSET,
|
|
isPartitioned = false
|
|
) {
|
|
this.name = name;
|
|
this.value = value;
|
|
this.host = host;
|
|
this.path = path;
|
|
this.expiry = expiry;
|
|
this.lastAccessed = lastAccessed;
|
|
this.creationTime = creationTime;
|
|
this.isSession = isSession;
|
|
this.isSecure = isSecure;
|
|
this.isHttpOnly = isHttpOnly;
|
|
this.inBrowserElement = inBrowserElement;
|
|
this.originAttributes = originAttributes;
|
|
this.sameSite = sameSite;
|
|
this.schemeMap = schemeMap;
|
|
this.isPartitioned = isPartitioned;
|
|
|
|
// For pre version 15 compatibility:
|
|
this.rawSameSite = sameSite;
|
|
|
|
let strippedHost = host.charAt(0) == "." ? host.slice(1) : host;
|
|
|
|
try {
|
|
this.baseDomain = Services.eTLD.getBaseDomainFromHost(strippedHost);
|
|
} catch (e) {
|
|
if (
|
|
e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS ||
|
|
e.result == Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS
|
|
) {
|
|
this.baseDomain = strippedHost;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Object representing a database connection and associated statements. The
|
|
// implementation varies depending on schema version.
|
|
function CookieDatabaseConnection(file, schema) {
|
|
// Manually generate a cookies.sqlite file with appropriate rows, columns,
|
|
// and schema version. If it already exists, just set up our statements.
|
|
let exists = file.exists();
|
|
|
|
this.db = Services.storage.openDatabase(file);
|
|
this.schema = schema;
|
|
if (!exists) {
|
|
this.db.schemaVersion = schema;
|
|
}
|
|
|
|
switch (schema) {
|
|
case 1: {
|
|
if (!exists) {
|
|
this.db.executeSimpleSQL(
|
|
"CREATE TABLE moz_cookies ( \
|
|
id INTEGER PRIMARY KEY, \
|
|
name TEXT, \
|
|
value TEXT, \
|
|
host TEXT, \
|
|
path TEXT, \
|
|
expiry INTEGER, \
|
|
isSecure INTEGER, \
|
|
isHttpOnly INTEGER)"
|
|
);
|
|
}
|
|
|
|
this.stmtInsert = this.db.createStatement(
|
|
"INSERT INTO moz_cookies ( \
|
|
id, \
|
|
name, \
|
|
value, \
|
|
host, \
|
|
path, \
|
|
expiry, \
|
|
isSecure, \
|
|
isHttpOnly) \
|
|
VALUES ( \
|
|
:id, \
|
|
:name, \
|
|
:value, \
|
|
:host, \
|
|
:path, \
|
|
:expiry, \
|
|
:isSecure, \
|
|
:isHttpOnly)"
|
|
);
|
|
|
|
this.stmtDelete = this.db.createStatement(
|
|
"DELETE FROM moz_cookies WHERE id = :id"
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
case 2: {
|
|
if (!exists) {
|
|
this.db.executeSimpleSQL(
|
|
"CREATE TABLE moz_cookies ( \
|
|
id INTEGER PRIMARY KEY, \
|
|
name TEXT, \
|
|
value TEXT, \
|
|
host TEXT, \
|
|
path TEXT, \
|
|
expiry INTEGER, \
|
|
lastAccessed INTEGER, \
|
|
isSecure INTEGER, \
|
|
isHttpOnly INTEGER)"
|
|
);
|
|
}
|
|
|
|
this.stmtInsert = this.db.createStatement(
|
|
"INSERT OR REPLACE INTO moz_cookies ( \
|
|
id, \
|
|
name, \
|
|
value, \
|
|
host, \
|
|
path, \
|
|
expiry, \
|
|
lastAccessed, \
|
|
isSecure, \
|
|
isHttpOnly) \
|
|
VALUES ( \
|
|
:id, \
|
|
:name, \
|
|
:value, \
|
|
:host, \
|
|
:path, \
|
|
:expiry, \
|
|
:lastAccessed, \
|
|
:isSecure, \
|
|
:isHttpOnly)"
|
|
);
|
|
|
|
this.stmtDelete = this.db.createStatement(
|
|
"DELETE FROM moz_cookies WHERE id = :id"
|
|
);
|
|
|
|
this.stmtUpdate = this.db.createStatement(
|
|
"UPDATE moz_cookies SET lastAccessed = :lastAccessed WHERE id = :id"
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
case 3: {
|
|
if (!exists) {
|
|
this.db.executeSimpleSQL(
|
|
"CREATE TABLE moz_cookies ( \
|
|
id INTEGER PRIMARY KEY, \
|
|
baseDomain TEXT, \
|
|
name TEXT, \
|
|
value TEXT, \
|
|
host TEXT, \
|
|
path TEXT, \
|
|
expiry INTEGER, \
|
|
lastAccessed INTEGER, \
|
|
isSecure INTEGER, \
|
|
isHttpOnly INTEGER)"
|
|
);
|
|
|
|
this.db.executeSimpleSQL(
|
|
"CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)"
|
|
);
|
|
}
|
|
|
|
this.stmtInsert = this.db.createStatement(
|
|
"INSERT INTO moz_cookies ( \
|
|
id, \
|
|
baseDomain, \
|
|
name, \
|
|
value, \
|
|
host, \
|
|
path, \
|
|
expiry, \
|
|
lastAccessed, \
|
|
isSecure, \
|
|
isHttpOnly) \
|
|
VALUES ( \
|
|
:id, \
|
|
:baseDomain, \
|
|
:name, \
|
|
:value, \
|
|
:host, \
|
|
:path, \
|
|
:expiry, \
|
|
:lastAccessed, \
|
|
:isSecure, \
|
|
:isHttpOnly)"
|
|
);
|
|
|
|
this.stmtDelete = this.db.createStatement(
|
|
"DELETE FROM moz_cookies WHERE id = :id"
|
|
);
|
|
|
|
this.stmtUpdate = this.db.createStatement(
|
|
"UPDATE moz_cookies SET lastAccessed = :lastAccessed WHERE id = :id"
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
case 4: {
|
|
if (!exists) {
|
|
this.db.executeSimpleSQL(
|
|
"CREATE TABLE moz_cookies ( \
|
|
id INTEGER PRIMARY KEY, \
|
|
baseDomain TEXT, \
|
|
name TEXT, \
|
|
value TEXT, \
|
|
host TEXT, \
|
|
path TEXT, \
|
|
expiry INTEGER, \
|
|
lastAccessed INTEGER, \
|
|
creationTime INTEGER, \
|
|
isSecure INTEGER, \
|
|
isHttpOnly INTEGER \
|
|
CONSTRAINT moz_uniqueid UNIQUE (name, host, path))"
|
|
);
|
|
|
|
this.db.executeSimpleSQL(
|
|
"CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)"
|
|
);
|
|
|
|
this.db.executeSimpleSQL("PRAGMA journal_mode = WAL");
|
|
}
|
|
|
|
this.stmtInsert = this.db.createStatement(
|
|
"INSERT INTO moz_cookies ( \
|
|
baseDomain, \
|
|
name, \
|
|
value, \
|
|
host, \
|
|
path, \
|
|
expiry, \
|
|
lastAccessed, \
|
|
creationTime, \
|
|
isSecure, \
|
|
isHttpOnly) \
|
|
VALUES ( \
|
|
:baseDomain, \
|
|
:name, \
|
|
:value, \
|
|
:host, \
|
|
:path, \
|
|
:expiry, \
|
|
:lastAccessed, \
|
|
:creationTime, \
|
|
:isSecure, \
|
|
:isHttpOnly)"
|
|
);
|
|
|
|
this.stmtDelete = this.db.createStatement(
|
|
"DELETE FROM moz_cookies \
|
|
WHERE name = :name AND host = :host AND path = :path"
|
|
);
|
|
|
|
this.stmtUpdate = this.db.createStatement(
|
|
"UPDATE moz_cookies SET lastAccessed = :lastAccessed \
|
|
WHERE name = :name AND host = :host AND path = :path"
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
case 10: {
|
|
if (!exists) {
|
|
this.db.executeSimpleSQL(
|
|
"CREATE TABLE moz_cookies ( \
|
|
id INTEGER PRIMARY KEY, \
|
|
baseDomain TEXT, \
|
|
originAttributes TEXT NOT NULL DEFAULT '', \
|
|
name TEXT, \
|
|
value TEXT, \
|
|
host TEXT, \
|
|
path TEXT, \
|
|
expiry INTEGER, \
|
|
lastAccessed INTEGER, \
|
|
creationTime INTEGER, \
|
|
isSecure INTEGER, \
|
|
isHttpOnly INTEGER, \
|
|
inBrowserElement INTEGER DEFAULT 0, \
|
|
sameSite INTEGER DEFAULT 0, \
|
|
rawSameSite INTEGER DEFAULT 0, \
|
|
CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))"
|
|
);
|
|
|
|
this.db.executeSimpleSQL(
|
|
"CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)"
|
|
);
|
|
|
|
this.db.executeSimpleSQL("PRAGMA journal_mode = WAL");
|
|
this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16");
|
|
}
|
|
|
|
this.stmtInsert = this.db.createStatement(
|
|
"INSERT INTO moz_cookies ( \
|
|
name, \
|
|
value, \
|
|
host, \
|
|
baseDomain, \
|
|
path, \
|
|
expiry, \
|
|
lastAccessed, \
|
|
creationTime, \
|
|
isSecure, \
|
|
isHttpOnly, \
|
|
inBrowserElement, \
|
|
originAttributes, \
|
|
sameSite, \
|
|
rawSameSite \
|
|
) VALUES ( \
|
|
:name, \
|
|
:value, \
|
|
:host, \
|
|
:baseDomain, \
|
|
:path, \
|
|
:expiry, \
|
|
:lastAccessed, \
|
|
:creationTime, \
|
|
:isSecure, \
|
|
:isHttpOnly, \
|
|
:inBrowserElement, \
|
|
:originAttributes, \
|
|
:sameSite, \
|
|
:rawSameSite)"
|
|
);
|
|
|
|
this.stmtDelete = this.db.createStatement(
|
|
"DELETE FROM moz_cookies \
|
|
WHERE name = :name AND host = :host AND path = :path AND \
|
|
originAttributes = :originAttributes"
|
|
);
|
|
|
|
this.stmtUpdate = this.db.createStatement(
|
|
"UPDATE moz_cookies SET lastAccessed = :lastAccessed \
|
|
WHERE name = :name AND host = :host AND path = :path AND \
|
|
originAttributes = :originAttributes"
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
case 11: {
|
|
if (!exists) {
|
|
this.db.executeSimpleSQL(
|
|
"CREATE TABLE moz_cookies ( \
|
|
id INTEGER PRIMARY KEY, \
|
|
originAttributes TEXT NOT NULL DEFAULT '', \
|
|
name TEXT, \
|
|
value TEXT, \
|
|
host TEXT, \
|
|
path TEXT, \
|
|
expiry INTEGER, \
|
|
lastAccessed INTEGER, \
|
|
creationTime INTEGER, \
|
|
isSecure INTEGER, \
|
|
isHttpOnly INTEGER, \
|
|
inBrowserElement INTEGER DEFAULT 0, \
|
|
sameSite INTEGER DEFAULT 0, \
|
|
rawSameSite INTEGER DEFAULT 0, \
|
|
CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))"
|
|
);
|
|
|
|
this.db.executeSimpleSQL("PRAGMA journal_mode = WAL");
|
|
this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16");
|
|
}
|
|
|
|
this.stmtInsert = this.db.createStatement(
|
|
"INSERT INTO moz_cookies ( \
|
|
name, \
|
|
value, \
|
|
host, \
|
|
path, \
|
|
expiry, \
|
|
lastAccessed, \
|
|
creationTime, \
|
|
isSecure, \
|
|
isHttpOnly, \
|
|
inBrowserElement, \
|
|
originAttributes, \
|
|
sameSite, \
|
|
rawSameSite \
|
|
) VALUES ( \
|
|
:name, \
|
|
:value, \
|
|
:host, \
|
|
:path, \
|
|
:expiry, \
|
|
:lastAccessed, \
|
|
:creationTime, \
|
|
:isSecure, \
|
|
:isHttpOnly, \
|
|
:inBrowserElement, \
|
|
:originAttributes, \
|
|
:sameSite, \
|
|
:rawSameSite)"
|
|
);
|
|
|
|
this.stmtDelete = this.db.createStatement(
|
|
"DELETE FROM moz_cookies \
|
|
WHERE name = :name AND host = :host AND path = :path AND \
|
|
originAttributes = :originAttributes"
|
|
);
|
|
|
|
this.stmtUpdate = this.db.createStatement(
|
|
"UPDATE moz_cookies SET lastAccessed = :lastAccessed \
|
|
WHERE name = :name AND host = :host AND path = :path AND \
|
|
originAttributes = :originAttributes"
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
case 12: {
|
|
if (!exists) {
|
|
this.db.executeSimpleSQL(
|
|
"CREATE TABLE moz_cookies ( \
|
|
id INTEGER PRIMARY KEY, \
|
|
originAttributes TEXT NOT NULL DEFAULT '', \
|
|
name TEXT, \
|
|
value TEXT, \
|
|
host TEXT, \
|
|
path TEXT, \
|
|
expiry INTEGER, \
|
|
lastAccessed INTEGER, \
|
|
creationTime INTEGER, \
|
|
isSecure INTEGER, \
|
|
isHttpOnly INTEGER, \
|
|
inBrowserElement INTEGER DEFAULT 0, \
|
|
sameSite INTEGER DEFAULT 0, \
|
|
rawSameSite INTEGER DEFAULT 0, \
|
|
schemeMap INTEGER DEFAULT 0, \
|
|
CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))"
|
|
);
|
|
|
|
this.db.executeSimpleSQL("PRAGMA journal_mode = WAL");
|
|
this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16");
|
|
}
|
|
|
|
this.stmtInsert = this.db.createStatement(
|
|
"INSERT INTO moz_cookies ( \
|
|
name, \
|
|
value, \
|
|
host, \
|
|
path, \
|
|
expiry, \
|
|
lastAccessed, \
|
|
creationTime, \
|
|
isSecure, \
|
|
isHttpOnly, \
|
|
inBrowserElement, \
|
|
originAttributes, \
|
|
sameSite, \
|
|
rawSameSite, \
|
|
schemeMap \
|
|
) VALUES ( \
|
|
:name, \
|
|
:value, \
|
|
:host, \
|
|
:path, \
|
|
:expiry, \
|
|
:lastAccessed, \
|
|
:creationTime, \
|
|
:isSecure, \
|
|
:isHttpOnly, \
|
|
:inBrowserElement, \
|
|
:originAttributes, \
|
|
:sameSite, \
|
|
:rawSameSite, \
|
|
:schemeMap)"
|
|
);
|
|
|
|
this.stmtDelete = this.db.createStatement(
|
|
"DELETE FROM moz_cookies \
|
|
WHERE name = :name AND host = :host AND path = :path AND \
|
|
originAttributes = :originAttributes"
|
|
);
|
|
|
|
this.stmtUpdate = this.db.createStatement(
|
|
"UPDATE moz_cookies SET lastAccessed = :lastAccessed \
|
|
WHERE name = :name AND host = :host AND path = :path AND \
|
|
originAttributes = :originAttributes"
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
case 13:
|
|
case 14: {
|
|
if (!exists) {
|
|
this.db.executeSimpleSQL(
|
|
"CREATE TABLE moz_cookies ( \
|
|
id INTEGER PRIMARY KEY, \
|
|
originAttributes TEXT NOT NULL DEFAULT '', \
|
|
name TEXT, \
|
|
value TEXT, \
|
|
host TEXT, \
|
|
path TEXT, \
|
|
expiry INTEGER, \
|
|
lastAccessed INTEGER, \
|
|
creationTime INTEGER, \
|
|
isSecure INTEGER, \
|
|
isHttpOnly INTEGER, \
|
|
inBrowserElement INTEGER DEFAULT 0, \
|
|
sameSite INTEGER DEFAULT 0, \
|
|
rawSameSite INTEGER DEFAULT 0, \
|
|
schemeMap INTEGER DEFAULT 0, \
|
|
isPartitionedAttributeSet INTEGER DEFAULT 0, \
|
|
CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))"
|
|
);
|
|
|
|
this.db.executeSimpleSQL("PRAGMA journal_mode = WAL");
|
|
this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16");
|
|
}
|
|
|
|
this.stmtInsert = this.db.createStatement(
|
|
"INSERT INTO moz_cookies ( \
|
|
name, \
|
|
value, \
|
|
host, \
|
|
path, \
|
|
expiry, \
|
|
lastAccessed, \
|
|
creationTime, \
|
|
isSecure, \
|
|
isHttpOnly, \
|
|
inBrowserElement, \
|
|
originAttributes, \
|
|
sameSite, \
|
|
rawSameSite, \
|
|
schemeMap, \
|
|
isPartitionedAttributeSet \
|
|
) VALUES ( \
|
|
:name, \
|
|
:value, \
|
|
:host, \
|
|
:path, \
|
|
:expiry, \
|
|
:lastAccessed, \
|
|
:creationTime, \
|
|
:isSecure, \
|
|
:isHttpOnly, \
|
|
:inBrowserElement, \
|
|
:originAttributes, \
|
|
:sameSite, \
|
|
:rawSameSite, \
|
|
:schemeMap, \
|
|
:isPartitionedAttributeSet)"
|
|
);
|
|
|
|
this.stmtDelete = this.db.createStatement(
|
|
"DELETE FROM moz_cookies \
|
|
WHERE name = :name AND host = :host AND path = :path AND \
|
|
originAttributes = :originAttributes"
|
|
);
|
|
|
|
this.stmtUpdate = this.db.createStatement(
|
|
"UPDATE moz_cookies SET lastAccessed = :lastAccessed \
|
|
WHERE name = :name AND host = :host AND path = :path AND \
|
|
originAttributes = :originAttributes"
|
|
);
|
|
|
|
break;
|
|
}
|
|
case 15: {
|
|
if (!exists) {
|
|
this.db.executeSimpleSQL(
|
|
"CREATE TABLE moz_cookies ( \
|
|
id INTEGER PRIMARY KEY, \
|
|
originAttributes TEXT NOT NULL DEFAULT '', \
|
|
name TEXT, \
|
|
value TEXT, \
|
|
host TEXT, \
|
|
path TEXT, \
|
|
expiry INTEGER, \
|
|
lastAccessed INTEGER, \
|
|
creationTime INTEGER, \
|
|
isSecure INTEGER, \
|
|
isHttpOnly INTEGER, \
|
|
inBrowserElement INTEGER DEFAULT 0, \
|
|
sameSite INTEGER DEFAULT 0, \
|
|
schemeMap INTEGER DEFAULT 0, \
|
|
isPartitionedAttributeSet INTEGER DEFAULT 0, \
|
|
CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))"
|
|
);
|
|
|
|
this.db.executeSimpleSQL("PRAGMA journal_mode = WAL");
|
|
this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16");
|
|
}
|
|
|
|
this.stmtInsert = this.db.createStatement(
|
|
"INSERT INTO moz_cookies ( \
|
|
name, \
|
|
value, \
|
|
host, \
|
|
path, \
|
|
expiry, \
|
|
lastAccessed, \
|
|
creationTime, \
|
|
isSecure, \
|
|
isHttpOnly, \
|
|
inBrowserElement, \
|
|
originAttributes, \
|
|
sameSite, \
|
|
schemeMap, \
|
|
isPartitionedAttributeSet \
|
|
) VALUES ( \
|
|
:name, \
|
|
:value, \
|
|
:host, \
|
|
:path, \
|
|
:expiry, \
|
|
:lastAccessed, \
|
|
:creationTime, \
|
|
:isSecure, \
|
|
:isHttpOnly, \
|
|
:inBrowserElement, \
|
|
:originAttributes, \
|
|
:sameSite, \
|
|
:schemeMap, \
|
|
:isPartitionedAttributeSet)"
|
|
);
|
|
|
|
this.stmtDelete = this.db.createStatement(
|
|
"DELETE FROM moz_cookies \
|
|
WHERE name = :name AND host = :host AND path = :path AND \
|
|
originAttributes = :originAttributes"
|
|
);
|
|
|
|
this.stmtUpdate = this.db.createStatement(
|
|
"UPDATE moz_cookies SET lastAccessed = :lastAccessed \
|
|
WHERE name = :name AND host = :host AND path = :path AND \
|
|
originAttributes = :originAttributes"
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
do_throw("unrecognized schemaVersion!");
|
|
}
|
|
}
|
|
|
|
CookieDatabaseConnection.prototype = {
|
|
insertCookie(cookie) {
|
|
if (!(cookie instanceof Cookie)) {
|
|
do_throw("not a cookie");
|
|
}
|
|
|
|
switch (this.schema) {
|
|
case 1:
|
|
this.stmtInsert.bindByName("id", cookie.creationTime);
|
|
this.stmtInsert.bindByName("name", cookie.name);
|
|
this.stmtInsert.bindByName("value", cookie.value);
|
|
this.stmtInsert.bindByName("host", cookie.host);
|
|
this.stmtInsert.bindByName("path", cookie.path);
|
|
this.stmtInsert.bindByName("expiry", cookie.expiry);
|
|
this.stmtInsert.bindByName("isSecure", cookie.isSecure);
|
|
this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
|
|
break;
|
|
|
|
case 2:
|
|
this.stmtInsert.bindByName("id", cookie.creationTime);
|
|
this.stmtInsert.bindByName("name", cookie.name);
|
|
this.stmtInsert.bindByName("value", cookie.value);
|
|
this.stmtInsert.bindByName("host", cookie.host);
|
|
this.stmtInsert.bindByName("path", cookie.path);
|
|
this.stmtInsert.bindByName("expiry", cookie.expiry);
|
|
this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
|
|
this.stmtInsert.bindByName("isSecure", cookie.isSecure);
|
|
this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
|
|
break;
|
|
|
|
case 3:
|
|
this.stmtInsert.bindByName("id", cookie.creationTime);
|
|
this.stmtInsert.bindByName("baseDomain", cookie.baseDomain);
|
|
this.stmtInsert.bindByName("name", cookie.name);
|
|
this.stmtInsert.bindByName("value", cookie.value);
|
|
this.stmtInsert.bindByName("host", cookie.host);
|
|
this.stmtInsert.bindByName("path", cookie.path);
|
|
this.stmtInsert.bindByName("expiry", cookie.expiry);
|
|
this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
|
|
this.stmtInsert.bindByName("isSecure", cookie.isSecure);
|
|
this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
|
|
break;
|
|
|
|
case 4:
|
|
this.stmtInsert.bindByName("baseDomain", cookie.baseDomain);
|
|
this.stmtInsert.bindByName("name", cookie.name);
|
|
this.stmtInsert.bindByName("value", cookie.value);
|
|
this.stmtInsert.bindByName("host", cookie.host);
|
|
this.stmtInsert.bindByName("path", cookie.path);
|
|
this.stmtInsert.bindByName("expiry", cookie.expiry);
|
|
this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
|
|
this.stmtInsert.bindByName("creationTime", cookie.creationTime);
|
|
this.stmtInsert.bindByName("isSecure", cookie.isSecure);
|
|
this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
|
|
break;
|
|
|
|
case 10:
|
|
this.stmtInsert.bindByName("name", cookie.name);
|
|
this.stmtInsert.bindByName("value", cookie.value);
|
|
this.stmtInsert.bindByName("host", cookie.host);
|
|
this.stmtInsert.bindByName("baseDomain", cookie.baseDomain);
|
|
this.stmtInsert.bindByName("path", cookie.path);
|
|
this.stmtInsert.bindByName("expiry", cookie.expiry);
|
|
this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
|
|
this.stmtInsert.bindByName("creationTime", cookie.creationTime);
|
|
this.stmtInsert.bindByName("isSecure", cookie.isSecure);
|
|
this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
|
|
this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement);
|
|
this.stmtInsert.bindByName(
|
|
"originAttributes",
|
|
ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
|
|
);
|
|
this.stmtInsert.bindByName("sameSite", cookie.sameSite);
|
|
this.stmtInsert.bindByName("rawSameSite", cookie.rawSameSite);
|
|
break;
|
|
|
|
case 11:
|
|
this.stmtInsert.bindByName("name", cookie.name);
|
|
this.stmtInsert.bindByName("value", cookie.value);
|
|
this.stmtInsert.bindByName("host", cookie.host);
|
|
this.stmtInsert.bindByName("path", cookie.path);
|
|
this.stmtInsert.bindByName("expiry", cookie.expiry);
|
|
this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
|
|
this.stmtInsert.bindByName("creationTime", cookie.creationTime);
|
|
this.stmtInsert.bindByName("isSecure", cookie.isSecure);
|
|
this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
|
|
this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement);
|
|
this.stmtInsert.bindByName(
|
|
"originAttributes",
|
|
ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
|
|
);
|
|
this.stmtInsert.bindByName("sameSite", cookie.sameSite);
|
|
this.stmtInsert.bindByName("rawSameSite", cookie.rawSameSite);
|
|
break;
|
|
|
|
case 12:
|
|
this.stmtInsert.bindByName("name", cookie.name);
|
|
this.stmtInsert.bindByName("value", cookie.value);
|
|
this.stmtInsert.bindByName("host", cookie.host);
|
|
this.stmtInsert.bindByName("path", cookie.path);
|
|
this.stmtInsert.bindByName("expiry", cookie.expiry);
|
|
this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
|
|
this.stmtInsert.bindByName("creationTime", cookie.creationTime);
|
|
this.stmtInsert.bindByName("isSecure", cookie.isSecure);
|
|
this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
|
|
this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement);
|
|
this.stmtInsert.bindByName(
|
|
"originAttributes",
|
|
ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
|
|
);
|
|
this.stmtInsert.bindByName("sameSite", cookie.sameSite);
|
|
this.stmtInsert.bindByName("rawSameSite", cookie.rawSameSite);
|
|
this.stmtInsert.bindByName("schemeMap", cookie.schemeMap);
|
|
break;
|
|
|
|
case 13:
|
|
case 14:
|
|
this.stmtInsert.bindByName("name", cookie.name);
|
|
this.stmtInsert.bindByName("value", cookie.value);
|
|
this.stmtInsert.bindByName("host", cookie.host);
|
|
this.stmtInsert.bindByName("path", cookie.path);
|
|
this.stmtInsert.bindByName("expiry", cookie.expiry);
|
|
this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
|
|
this.stmtInsert.bindByName("creationTime", cookie.creationTime);
|
|
this.stmtInsert.bindByName("isSecure", cookie.isSecure);
|
|
this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
|
|
this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement);
|
|
this.stmtInsert.bindByName(
|
|
"originAttributes",
|
|
ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
|
|
);
|
|
this.stmtInsert.bindByName("sameSite", cookie.sameSite);
|
|
this.stmtInsert.bindByName("rawSameSite", cookie.rawSameSite);
|
|
this.stmtInsert.bindByName("schemeMap", cookie.schemeMap);
|
|
this.stmtInsert.bindByName(
|
|
"isPartitionedAttributeSet",
|
|
cookie.isPartitioned
|
|
);
|
|
break;
|
|
|
|
case 15:
|
|
this.stmtInsert.bindByName("name", cookie.name);
|
|
this.stmtInsert.bindByName("value", cookie.value);
|
|
this.stmtInsert.bindByName("host", cookie.host);
|
|
this.stmtInsert.bindByName("path", cookie.path);
|
|
this.stmtInsert.bindByName("expiry", cookie.expiry);
|
|
this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
|
|
this.stmtInsert.bindByName("creationTime", cookie.creationTime);
|
|
this.stmtInsert.bindByName("isSecure", cookie.isSecure);
|
|
this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
|
|
this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement);
|
|
this.stmtInsert.bindByName(
|
|
"originAttributes",
|
|
ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
|
|
);
|
|
this.stmtInsert.bindByName("sameSite", cookie.sameSite);
|
|
this.stmtInsert.bindByName("schemeMap", cookie.schemeMap);
|
|
this.stmtInsert.bindByName(
|
|
"isPartitionedAttributeSet",
|
|
cookie.isPartitioned
|
|
);
|
|
break;
|
|
|
|
default:
|
|
do_throw("unrecognized schemaVersion!");
|
|
}
|
|
|
|
do_execute_stmt(this.stmtInsert);
|
|
},
|
|
|
|
deleteCookie(cookie) {
|
|
if (!(cookie instanceof Cookie)) {
|
|
do_throw("not a cookie");
|
|
}
|
|
|
|
switch (this.db.schemaVersion) {
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
this.stmtDelete.bindByName("id", cookie.creationTime);
|
|
break;
|
|
|
|
case 4:
|
|
this.stmtDelete.bindByName("name", cookie.name);
|
|
this.stmtDelete.bindByName("host", cookie.host);
|
|
this.stmtDelete.bindByName("path", cookie.path);
|
|
break;
|
|
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
case 14:
|
|
this.stmtDelete.bindByName("name", cookie.name);
|
|
this.stmtDelete.bindByName("host", cookie.host);
|
|
this.stmtDelete.bindByName("path", cookie.path);
|
|
this.stmtDelete.bindByName(
|
|
"originAttributes",
|
|
ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
|
|
);
|
|
break;
|
|
|
|
default:
|
|
do_throw("unrecognized schemaVersion!");
|
|
}
|
|
|
|
do_execute_stmt(this.stmtDelete);
|
|
},
|
|
|
|
updateCookie(cookie) {
|
|
if (!(cookie instanceof Cookie)) {
|
|
do_throw("not a cookie");
|
|
}
|
|
|
|
switch (this.db.schemaVersion) {
|
|
case 1:
|
|
do_throw("can't update a schema 1 cookie!");
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
this.stmtUpdate.bindByName("id", cookie.creationTime);
|
|
this.stmtUpdate.bindByName("lastAccessed", cookie.lastAccessed);
|
|
break;
|
|
|
|
case 4:
|
|
this.stmtDelete.bindByName("name", cookie.name);
|
|
this.stmtDelete.bindByName("host", cookie.host);
|
|
this.stmtDelete.bindByName("path", cookie.path);
|
|
this.stmtUpdate.bindByName("name", cookie.name);
|
|
this.stmtUpdate.bindByName("host", cookie.host);
|
|
this.stmtUpdate.bindByName("path", cookie.path);
|
|
this.stmtUpdate.bindByName("lastAccessed", cookie.lastAccessed);
|
|
break;
|
|
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
case 14:
|
|
this.stmtDelete.bindByName("name", cookie.name);
|
|
this.stmtDelete.bindByName("host", cookie.host);
|
|
this.stmtDelete.bindByName("path", cookie.path);
|
|
this.stmtDelete.bindByName(
|
|
"originAttributes",
|
|
ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
|
|
);
|
|
this.stmtUpdate.bindByName("name", cookie.name);
|
|
this.stmtUpdate.bindByName("host", cookie.host);
|
|
this.stmtUpdate.bindByName("path", cookie.path);
|
|
this.stmtUpdate.bindByName(
|
|
"originAttributes",
|
|
ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
|
|
);
|
|
this.stmtUpdate.bindByName("lastAccessed", cookie.lastAccessed);
|
|
break;
|
|
|
|
default:
|
|
do_throw("unrecognized schemaVersion!");
|
|
}
|
|
|
|
do_execute_stmt(this.stmtUpdate);
|
|
},
|
|
|
|
close() {
|
|
this.stmtInsert.finalize();
|
|
this.stmtDelete.finalize();
|
|
if (this.stmtUpdate) {
|
|
this.stmtUpdate.finalize();
|
|
}
|
|
this.db.close();
|
|
|
|
this.stmtInsert = null;
|
|
this.stmtDelete = null;
|
|
this.stmtUpdate = null;
|
|
this.db = null;
|
|
},
|
|
};
|
|
|
|
function do_get_cookie_file(profile) {
|
|
let file = profile.clone();
|
|
file.append("cookies.sqlite");
|
|
return file;
|
|
}
|
|
|
|
// Count the cookies from 'host' in a database. If 'host' is null, count all
|
|
// cookies.
|
|
function do_count_cookies_in_db(connection, host) {
|
|
let select = null;
|
|
if (host) {
|
|
select = connection.createStatement(
|
|
"SELECT COUNT(1) FROM moz_cookies WHERE host = :host"
|
|
);
|
|
select.bindByName("host", host);
|
|
} else {
|
|
select = connection.createStatement("SELECT COUNT(1) FROM moz_cookies");
|
|
}
|
|
|
|
select.executeStep();
|
|
let result = select.getInt32(0);
|
|
select.reset();
|
|
select.finalize();
|
|
return result;
|
|
}
|
|
|
|
// Execute 'stmt', ensuring that we reset it if it throws.
|
|
function do_execute_stmt(stmt) {
|
|
try {
|
|
stmt.executeStep();
|
|
stmt.reset();
|
|
} catch (e) {
|
|
stmt.reset();
|
|
throw e;
|
|
}
|
|
}
|