зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1596660 - Replace pwmgr storage-mozStorage with a stub storage-geckoview. r=sfoster
* storage-mozStorage was used by Fenenc but that is no longer built from m-c. * Existing Android tests need to be disabled since they rely on being able to manipulate storage but this commit only stubs searching for logins. * A later commit will actually filter the logins returned by a GV delegate. Differential Revision: https://phabricator.services.mozilla.com/D54139 --HG-- rename : toolkit/components/passwordmgr/storage-json.js => toolkit/components/passwordmgr/storage-geckoview.js extra : moz-landing-system : lando
This commit is contained in:
Родитель
a2a7b27d8d
Коммит
60e3f6a6e1
|
@ -347,8 +347,11 @@ const PasswordsCleaner = {
|
|||
} catch (ex) {
|
||||
// XXXehsan: is there a better way to do this rather than this
|
||||
// hacky comparison?
|
||||
if (!ex.message.includes("User canceled Master Password entry")) {
|
||||
throw new Error("Exception occured in clearing passwords :" + ex);
|
||||
if (
|
||||
!ex.message.includes("User canceled Master Password entry") &&
|
||||
ex.result != Cr.NS_ERROR_NOT_IMPLEMENTED
|
||||
) {
|
||||
throw new Error("Exception occured in clearing passwords: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,13 +46,13 @@ Classes = [
|
|||
if buildconfig.substs['OS_TARGET'] == 'Android':
|
||||
Classes += [
|
||||
{
|
||||
'cid': '{8c2023b9-175c-477e-9761-44ae7b549756}',
|
||||
'cid': '{337f317f-f713-452a-962d-db831c785fec}',
|
||||
'contract_ids': [
|
||||
'@mozilla.org/login-manager/storage/mozStorage;1',
|
||||
'@mozilla.org/login-manager/storage/geckoview;1',
|
||||
'@mozilla.org/login-manager/storage/default;1',
|
||||
],
|
||||
'jsm': 'resource://gre/modules/storage-mozStorage.js',
|
||||
'constructor': 'LoginManagerStorage_mozStorage',
|
||||
'jsm': 'resource://gre/modules/storage-geckoview.js',
|
||||
'constructor': 'LoginManagerStorage_geckoview',
|
||||
},
|
||||
]
|
||||
else:
|
||||
|
|
|
@ -42,18 +42,18 @@ EXTRA_JS_MODULES += [
|
|||
'LoginManagerPrompter.jsm',
|
||||
'LoginRecipes.jsm',
|
||||
'OSCrypto.jsm',
|
||||
'storage-json.js',
|
||||
]
|
||||
|
||||
if CONFIG['OS_TARGET'] == 'Android':
|
||||
EXTRA_JS_MODULES += [
|
||||
'storage-mozStorage.js',
|
||||
'storage-geckoview.js',
|
||||
]
|
||||
else:
|
||||
EXTRA_JS_MODULES += [
|
||||
'LoginImport.jsm',
|
||||
'LoginStore.jsm',
|
||||
'PasswordGenerator.jsm',
|
||||
'storage-json.js',
|
||||
]
|
||||
|
||||
if CONFIG['OS_TARGET'] == 'WINNT':
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* nsILoginManagerStorage implementation for GeckoView
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { LoginManagerStorage_json } = ChromeUtils.import(
|
||||
"resource://gre/modules/storage-json.js"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"LoginHelper",
|
||||
"resource://gre/modules/LoginHelper.jsm"
|
||||
);
|
||||
|
||||
class LoginManagerStorage_geckoview extends LoginManagerStorage_json {
|
||||
get classID() {
|
||||
return Components.ID("{337f317f-f713-452a-962d-db831c785fec}");
|
||||
}
|
||||
get QueryInterface() {
|
||||
return ChromeUtils.generateQI([Ci.nsILoginManagerStorage]);
|
||||
}
|
||||
|
||||
get _xpcom_factory() {
|
||||
return XPCOMUtils.generateSingletonFactory(
|
||||
this.LoginManagerStorage_geckoview
|
||||
);
|
||||
}
|
||||
|
||||
get _crypto() {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
initialize() {
|
||||
try {
|
||||
return Promise.resolve();
|
||||
} catch (e) {
|
||||
this.log("Initialization failed:", e);
|
||||
throw new Error("Initialization failed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method used by regression tests only. It is called before
|
||||
* replacing this storage module with a new instance.
|
||||
*/
|
||||
terminate() {}
|
||||
|
||||
addLogin(
|
||||
login,
|
||||
preEncrypted = false,
|
||||
plaintextUsername = null,
|
||||
plaintextPassword = null
|
||||
) {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
removeLogin(login) {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
modifyLogin(oldLogin, newLoginData) {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
getAllLogins() {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all saved logins that can be decrypted.
|
||||
*
|
||||
* @resolve {nsILoginInfo[]}
|
||||
*/
|
||||
async getAllLoginsAsync() {
|
||||
let [logins, ids] = this._searchLogins({});
|
||||
if (!logins.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
async searchLoginsAsync(matchData) {
|
||||
this.log("searchLoginsAsync:", matchData);
|
||||
|
||||
await Promise.resolve();
|
||||
|
||||
let realMatchData = {};
|
||||
let options = {};
|
||||
for (let [name, value] of Object.entries(matchData)) {
|
||||
switch (name) {
|
||||
// Some property names aren't field names but are special options to affect the search.
|
||||
case "acceptDifferentSubdomains":
|
||||
case "schemeUpgrades": {
|
||||
options[name] = value;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
realMatchData[name] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: get from GV
|
||||
let candidateLogins = [];
|
||||
let [logins, ids] = this._searchLogins(
|
||||
realMatchData,
|
||||
options,
|
||||
candidateLogins
|
||||
);
|
||||
return logins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use `searchLoginsAsync` instead.
|
||||
*/
|
||||
searchLogins(matchData) {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all logins from storage.
|
||||
*/
|
||||
removeAllLogins() {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
get uiBusy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get isLoggedIn() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* GeckoView will encrypt the login itself.
|
||||
*/
|
||||
_encryptLogin(login) {
|
||||
return login;
|
||||
}
|
||||
|
||||
/**
|
||||
* GeckoView logins are already decrypted before this component receives them
|
||||
* so this method is a no-op for this backend.
|
||||
*/
|
||||
_decryptLogins(logins) {
|
||||
return logins;
|
||||
}
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyGetter(
|
||||
LoginManagerStorage_geckoview.prototype,
|
||||
"log",
|
||||
() => {
|
||||
let logger = LoginHelper.createLogger("Login storage");
|
||||
return logger.log.bind(logger);
|
||||
}
|
||||
);
|
||||
|
||||
const EXPORTED_SYMBOLS = ["LoginManagerStorage_geckoview"];
|
|
@ -329,6 +329,8 @@ class LoginManagerStorage_json {
|
|||
* @return {nsILoginInfo[]}
|
||||
*/
|
||||
getAllLogins() {
|
||||
this._store.ensureDataReady();
|
||||
|
||||
let [logins, ids] = this._searchLogins({});
|
||||
|
||||
// decrypt entries for caller.
|
||||
|
@ -346,6 +348,8 @@ class LoginManagerStorage_json {
|
|||
* @resolve {nsILoginInfo[]}
|
||||
*/
|
||||
async getAllLoginsAsync() {
|
||||
this._store.ensureDataReady();
|
||||
|
||||
let [logins, ids] = this._searchLogins({});
|
||||
if (!logins.length) {
|
||||
return [];
|
||||
|
@ -404,6 +408,8 @@ class LoginManagerStorage_json {
|
|||
* @return {nsILoginInfo[]} which are decrypted.
|
||||
*/
|
||||
searchLogins(matchData) {
|
||||
this._store.ensureDataReady();
|
||||
|
||||
let realMatchData = {};
|
||||
let options = {};
|
||||
// Convert nsIPropertyBag to normal JS object
|
||||
|
@ -443,10 +449,9 @@ class LoginManagerStorage_json {
|
|||
aOptions = {
|
||||
schemeUpgrades: false,
|
||||
acceptDifferentSubdomains: false,
|
||||
}
|
||||
},
|
||||
candidateLogins = this._store.data.logins
|
||||
) {
|
||||
this._store.ensureDataReady();
|
||||
|
||||
if (
|
||||
"formActionOrigin" in matchData &&
|
||||
matchData.formActionOrigin === "" &&
|
||||
|
@ -539,7 +544,7 @@ class LoginManagerStorage_json {
|
|||
|
||||
let foundLogins = [],
|
||||
foundIds = [];
|
||||
for (let loginItem of this._store.data.logins) {
|
||||
for (let loginItem of candidateLogins) {
|
||||
if (match(loginItem)) {
|
||||
// Create the new nsLoginInfo object, push to array
|
||||
let login = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(
|
||||
|
@ -594,6 +599,8 @@ class LoginManagerStorage_json {
|
|||
}
|
||||
|
||||
findLogins(origin, formActionOrigin, httpRealm) {
|
||||
this._store.ensureDataReady();
|
||||
|
||||
let loginData = {
|
||||
origin,
|
||||
formActionOrigin,
|
||||
|
@ -615,6 +622,8 @@ class LoginManagerStorage_json {
|
|||
}
|
||||
|
||||
countLogins(origin, formActionOrigin, httpRealm) {
|
||||
this._store.ensureDataReady();
|
||||
|
||||
let loginData = {
|
||||
origin,
|
||||
formActionOrigin,
|
||||
|
@ -677,6 +686,8 @@ class LoginManagerStorage_json {
|
|||
* stored login (useful for looking at the actual nsILoginMetaInfo values).
|
||||
*/
|
||||
_getIdForLogin(login) {
|
||||
this._store.ensureDataReady();
|
||||
|
||||
let matchData = {};
|
||||
for (let field of ["origin", "formActionOrigin", "httpRealm"]) {
|
||||
if (login[field] != "") {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -89,12 +89,6 @@ add_task(async function test_common_initialize() {
|
|||
|
||||
// Ensure that the service and the storage module are initialized.
|
||||
await Services.logins.initializationPromise;
|
||||
|
||||
// Ensure that every test file starts with an empty database.
|
||||
LoginTestUtils.clearData();
|
||||
|
||||
// Clean up after every test.
|
||||
registerCleanupFunction(() => LoginTestUtils.clearData());
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,614 +0,0 @@
|
|||
/**
|
||||
* This test interfaces directly with the mozStorage password storage module,
|
||||
* bypassing the normal password manager usage.
|
||||
*/
|
||||
|
||||
/* eslint-disable no-var */
|
||||
|
||||
const { PermissionTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/PermissionTestUtils.jsm"
|
||||
);
|
||||
|
||||
const ENCTYPE_BASE64 = 0;
|
||||
const ENCTYPE_SDR = 1;
|
||||
const PERMISSION_SAVE_LOGINS = "login-saving";
|
||||
|
||||
// Current schema version used by storage-mozStorage.js. This will need to be
|
||||
// kept in sync with the version there (or else the tests fail).
|
||||
const CURRENT_SCHEMA = 6;
|
||||
|
||||
async function copyFile(aLeafName) {
|
||||
await OS.File.copy(
|
||||
OS.Path.join(do_get_file("data").path, aLeafName),
|
||||
OS.Path.join(OS.Constants.Path.profileDir, aLeafName)
|
||||
);
|
||||
}
|
||||
|
||||
function openDB(aLeafName) {
|
||||
let dbFile = new FileUtils.File(OS.Constants.Path.profileDir);
|
||||
dbFile.append(aLeafName);
|
||||
|
||||
return Services.storage.openDatabase(dbFile);
|
||||
}
|
||||
|
||||
function deleteFile(pathname, filename) {
|
||||
let file = new FileUtils.File(pathname);
|
||||
file.append(filename);
|
||||
|
||||
// Suppress failures, this happens in the mozstorage tests on Windows
|
||||
// because the module may still be holding onto the DB. (We don't
|
||||
// have a way to explicitly shutdown/GC the module).
|
||||
try {
|
||||
if (file.exists()) {
|
||||
file.remove(false);
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function reloadStorage(aInputPathName, aInputFileName) {
|
||||
let inputFile = null;
|
||||
if (aInputFileName) {
|
||||
inputFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
inputFile.initWithPath(aInputPathName);
|
||||
inputFile.append(aInputFileName);
|
||||
}
|
||||
|
||||
let storage = Cc[
|
||||
"@mozilla.org/login-manager/storage/mozStorage;1"
|
||||
].createInstance(Ci.nsILoginManagerStorage);
|
||||
storage
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIVariant)
|
||||
.initWithFile(inputFile);
|
||||
|
||||
return storage;
|
||||
}
|
||||
|
||||
function checkStorageData(storage, ref_disabledHosts, ref_logins) {
|
||||
LoginTestUtils.assertLoginListsEqual(storage.getAllLogins(), ref_logins);
|
||||
LoginTestUtils.assertDisabledHostsEqual(
|
||||
getAllDisabledHostsFromPermissionManager(),
|
||||
ref_disabledHosts
|
||||
);
|
||||
}
|
||||
|
||||
function getAllDisabledHostsFromPermissionManager() {
|
||||
let disabledHosts = [];
|
||||
for (let perm of Services.perms.all) {
|
||||
if (
|
||||
perm.type == PERMISSION_SAVE_LOGINS &&
|
||||
perm.capability == Services.perms.DENY_ACTION
|
||||
) {
|
||||
disabledHosts.push(perm.principal.URI.prePath);
|
||||
}
|
||||
}
|
||||
|
||||
return disabledHosts;
|
||||
}
|
||||
|
||||
function setLoginSavingEnabled(origin, enabled) {
|
||||
if (enabled) {
|
||||
PermissionTestUtils.remove(origin, PERMISSION_SAVE_LOGINS);
|
||||
} else {
|
||||
PermissionTestUtils.add(
|
||||
origin,
|
||||
PERMISSION_SAVE_LOGINS,
|
||||
Services.perms.DENY_ACTION
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
add_task(async function test_execute() {
|
||||
const OUTDIR = OS.Constants.Path.profileDir;
|
||||
let testnum = 0;
|
||||
let testdesc = "Setup of nsLoginInfo test-users";
|
||||
|
||||
try {
|
||||
var isGUID = /^\{[0-9a-f\d]{8}-[0-9a-f\d]{4}-[0-9a-f\d]{4}-[0-9a-f\d]{4}-[0-9a-f\d]{12}\}$/;
|
||||
function getGUIDforID(conn, id) {
|
||||
let stmt = conn.createStatement(
|
||||
"SELECT guid from moz_logins WHERE id = " + id
|
||||
);
|
||||
stmt.executeStep();
|
||||
let guid = stmt.getString(0);
|
||||
stmt.finalize();
|
||||
return guid;
|
||||
}
|
||||
|
||||
function getEncTypeForID(conn, id) {
|
||||
let stmt = conn.createStatement(
|
||||
"SELECT encType from moz_logins WHERE id = " + id
|
||||
);
|
||||
stmt.executeStep();
|
||||
let encType = stmt.row.encType;
|
||||
stmt.finalize();
|
||||
return encType;
|
||||
}
|
||||
|
||||
function getAllDisabledHostsFromMozStorage(conn) {
|
||||
let disabledHosts = [];
|
||||
let stmt = conn.createStatement("SELECT hostname from moz_disabledHosts");
|
||||
|
||||
while (stmt.executeStep()) {
|
||||
disabledHosts.push(stmt.row.hostname);
|
||||
}
|
||||
|
||||
return disabledHosts;
|
||||
}
|
||||
|
||||
var storage;
|
||||
var dbConnection;
|
||||
var nsLoginInfo = new Components.Constructor(
|
||||
"@mozilla.org/login-manager/loginInfo;1",
|
||||
Ci.nsILoginInfo
|
||||
);
|
||||
Assert.ok(nsLoginInfo != null);
|
||||
|
||||
var testuser1 = new nsLoginInfo();
|
||||
testuser1.init(
|
||||
"http://test.com",
|
||||
"http://test.com",
|
||||
null,
|
||||
"testuser1",
|
||||
"testpass1",
|
||||
"u1",
|
||||
"p1"
|
||||
);
|
||||
var testuser1B = new nsLoginInfo();
|
||||
testuser1B.init(
|
||||
"http://test.com",
|
||||
"http://test.com",
|
||||
null,
|
||||
"testuser1B",
|
||||
"testpass1B",
|
||||
"u1",
|
||||
"p1"
|
||||
);
|
||||
var testuser2 = new nsLoginInfo();
|
||||
testuser2.init(
|
||||
"http://test.org",
|
||||
"http://test.org",
|
||||
null,
|
||||
"testuser2",
|
||||
"testpass2",
|
||||
"u2",
|
||||
"p2"
|
||||
);
|
||||
var testuser3 = new nsLoginInfo();
|
||||
testuser3.init(
|
||||
"http://test.gov",
|
||||
"http://test.gov",
|
||||
null,
|
||||
"testuser3",
|
||||
"testpass3",
|
||||
"u3",
|
||||
"p3"
|
||||
);
|
||||
var testuser4 = new nsLoginInfo();
|
||||
testuser4.init(
|
||||
"http://test.gov",
|
||||
"http://test.gov",
|
||||
null,
|
||||
"testuser1",
|
||||
"testpass2",
|
||||
"u4",
|
||||
"p4"
|
||||
);
|
||||
var testuser5 = new nsLoginInfo();
|
||||
testuser5.init(
|
||||
"http://test.gov",
|
||||
"http://test.gov",
|
||||
null,
|
||||
"testuser2",
|
||||
"testpass1",
|
||||
"u5",
|
||||
"p5"
|
||||
);
|
||||
|
||||
/* ========== 1 ========== */
|
||||
testnum++;
|
||||
testdesc = "Test downgrade from v999 storage";
|
||||
|
||||
await copyFile("signons-v999.sqlite");
|
||||
// Verify the schema version in the test file.
|
||||
dbConnection = openDB("signons-v999.sqlite");
|
||||
Assert.equal(999, dbConnection.schemaVersion);
|
||||
dbConnection.close();
|
||||
|
||||
storage = reloadStorage(OUTDIR, "signons-v999.sqlite");
|
||||
setLoginSavingEnabled("https://disabled.net", false);
|
||||
checkStorageData(storage, ["https://disabled.net"], [testuser1]);
|
||||
|
||||
// Check to make sure we downgraded the schema version.
|
||||
dbConnection = openDB("signons-v999.sqlite");
|
||||
Assert.equal(CURRENT_SCHEMA, dbConnection.schemaVersion);
|
||||
dbConnection.close();
|
||||
|
||||
deleteFile(OUTDIR, "signons-v999.sqlite");
|
||||
|
||||
/* ========== 2 ========== */
|
||||
testnum++;
|
||||
testdesc = "Test downgrade from incompat v999 storage";
|
||||
// This file has a testuser999/testpass999, but is missing an expected column
|
||||
|
||||
var origFile = OS.Path.join(OUTDIR, "signons-v999-2.sqlite");
|
||||
var failFile = OS.Path.join(OUTDIR, "signons-v999-2.sqlite.corrupt");
|
||||
|
||||
// Make sure we always start clean in a clean state.
|
||||
await copyFile("signons-v999-2.sqlite");
|
||||
await OS.File.remove(failFile);
|
||||
|
||||
Assert.throws(
|
||||
() => reloadStorage(OUTDIR, "signons-v999-2.sqlite"),
|
||||
/Initialization failed/
|
||||
);
|
||||
|
||||
// Check to ensure the DB file was renamed to .corrupt.
|
||||
Assert.equal(false, await OS.File.exists(origFile));
|
||||
Assert.ok(await OS.File.exists(failFile));
|
||||
|
||||
await OS.File.remove(failFile);
|
||||
|
||||
/* ========== 3 ========== */
|
||||
testnum++;
|
||||
testdesc = "Test upgrade from v1->v2 storage";
|
||||
|
||||
await copyFile("signons-v1.sqlite");
|
||||
// Sanity check the test file.
|
||||
dbConnection = openDB("signons-v1.sqlite");
|
||||
Assert.equal(1, dbConnection.schemaVersion);
|
||||
dbConnection.close();
|
||||
|
||||
storage = reloadStorage(OUTDIR, "signons-v1.sqlite");
|
||||
checkStorageData(storage, ["https://disabled.net"], [testuser1, testuser2]);
|
||||
|
||||
// Check to see that we added a GUIDs to the logins.
|
||||
dbConnection = openDB("signons-v1.sqlite");
|
||||
Assert.equal(CURRENT_SCHEMA, dbConnection.schemaVersion);
|
||||
var guid = getGUIDforID(dbConnection, 1);
|
||||
Assert.ok(isGUID.test(guid));
|
||||
guid = getGUIDforID(dbConnection, 2);
|
||||
Assert.ok(isGUID.test(guid));
|
||||
dbConnection.close();
|
||||
|
||||
deleteFile(OUTDIR, "signons-v1.sqlite");
|
||||
|
||||
/* ========== 4 ========== */
|
||||
testnum++;
|
||||
testdesc = "Test upgrade v2->v1 storage";
|
||||
// This is the case where a v2 DB has been accessed with v1 code, and now we
|
||||
// are upgrading it again. Any logins added by the v1 code must be properly
|
||||
// upgraded.
|
||||
|
||||
await copyFile("signons-v1v2.sqlite");
|
||||
// Sanity check the test file.
|
||||
dbConnection = openDB("signons-v1v2.sqlite");
|
||||
Assert.equal(1, dbConnection.schemaVersion);
|
||||
dbConnection.close();
|
||||
|
||||
storage = reloadStorage(OUTDIR, "signons-v1v2.sqlite");
|
||||
checkStorageData(
|
||||
storage,
|
||||
["https://disabled.net"],
|
||||
[testuser1, testuser2, testuser3]
|
||||
);
|
||||
|
||||
// While we're here, try modifying a login, to ensure that doing so doesn't
|
||||
// change the existing GUID.
|
||||
storage.modifyLogin(testuser1, testuser1B);
|
||||
checkStorageData(
|
||||
storage,
|
||||
["https://disabled.net"],
|
||||
[testuser1B, testuser2, testuser3]
|
||||
);
|
||||
|
||||
// Check the GUIDs. Logins 1 and 2 should retain their original GUID, login 3
|
||||
// should have one created (because it didn't have one previously).
|
||||
dbConnection = openDB("signons-v1v2.sqlite");
|
||||
Assert.equal(CURRENT_SCHEMA, dbConnection.schemaVersion);
|
||||
guid = getGUIDforID(dbConnection, 1);
|
||||
Assert.equal("{655c7358-f1d6-6446-adab-53f98ac5d80f}", guid);
|
||||
guid = getGUIDforID(dbConnection, 2);
|
||||
Assert.equal("{13d9bfdc-572a-4d4e-9436-68e9803e84c1}", guid);
|
||||
guid = getGUIDforID(dbConnection, 3);
|
||||
Assert.ok(isGUID.test(guid));
|
||||
dbConnection.close();
|
||||
|
||||
deleteFile(OUTDIR, "signons-v1v2.sqlite");
|
||||
|
||||
/* ========== 5 ========== */
|
||||
testnum++;
|
||||
testdesc = "Test upgrade from v2->v3 storage";
|
||||
|
||||
await copyFile("signons-v2.sqlite");
|
||||
// Sanity check the test file.
|
||||
dbConnection = openDB("signons-v2.sqlite");
|
||||
Assert.equal(2, dbConnection.schemaVersion);
|
||||
|
||||
storage = reloadStorage(OUTDIR, "signons-v2.sqlite");
|
||||
|
||||
// Check to see that we added the correct encType to the logins.
|
||||
Assert.equal(CURRENT_SCHEMA, dbConnection.schemaVersion);
|
||||
var encTypes = [
|
||||
ENCTYPE_BASE64,
|
||||
ENCTYPE_SDR,
|
||||
ENCTYPE_BASE64,
|
||||
ENCTYPE_BASE64,
|
||||
];
|
||||
for (let i = 0; i < encTypes.length; i++) {
|
||||
Assert.equal(encTypes[i], getEncTypeForID(dbConnection, i + 1));
|
||||
}
|
||||
dbConnection.close();
|
||||
|
||||
// There are 4 logins, but 3 will be invalid because we can no longer decrypt
|
||||
// base64-encoded items. (testuser1/4/5)
|
||||
checkStorageData(storage, ["https://disabled.net"], [testuser2]);
|
||||
|
||||
deleteFile(OUTDIR, "signons-v2.sqlite");
|
||||
|
||||
/* ========== 6 ========== */
|
||||
testnum++;
|
||||
testdesc = "Test upgrade v3->v2 storage";
|
||||
// This is the case where a v3 DB has been accessed with v2 code, and now we
|
||||
// are upgrading it again. Any logins added by the v2 code must be properly
|
||||
// upgraded.
|
||||
|
||||
await copyFile("signons-v2v3.sqlite");
|
||||
// Sanity check the test file.
|
||||
dbConnection = openDB("signons-v2v3.sqlite");
|
||||
Assert.equal(2, dbConnection.schemaVersion);
|
||||
encTypes = [
|
||||
ENCTYPE_BASE64,
|
||||
ENCTYPE_SDR,
|
||||
ENCTYPE_BASE64,
|
||||
ENCTYPE_BASE64,
|
||||
null,
|
||||
];
|
||||
for (let i = 0; i < encTypes.length; i++) {
|
||||
Assert.equal(encTypes[i], getEncTypeForID(dbConnection, i + 1));
|
||||
}
|
||||
|
||||
// Reload storage, check that the new login now has encType=1, others untouched
|
||||
storage = reloadStorage(OUTDIR, "signons-v2v3.sqlite");
|
||||
Assert.equal(CURRENT_SCHEMA, dbConnection.schemaVersion);
|
||||
|
||||
encTypes = [
|
||||
ENCTYPE_BASE64,
|
||||
ENCTYPE_SDR,
|
||||
ENCTYPE_BASE64,
|
||||
ENCTYPE_BASE64,
|
||||
ENCTYPE_SDR,
|
||||
];
|
||||
for (let i = 0; i < encTypes.length; i++) {
|
||||
Assert.equal(encTypes[i], getEncTypeForID(dbConnection, i + 1));
|
||||
}
|
||||
|
||||
// Sanity check that the data gets migrated
|
||||
// There are 5 logins, but 3 will be invalid because we can no longer decrypt
|
||||
// base64-encoded items. (testuser1/4/5). We no longer reencrypt with SDR.
|
||||
checkStorageData(storage, ["https://disabled.net"], [testuser2, testuser3]);
|
||||
encTypes = [
|
||||
ENCTYPE_BASE64,
|
||||
ENCTYPE_SDR,
|
||||
ENCTYPE_BASE64,
|
||||
ENCTYPE_BASE64,
|
||||
ENCTYPE_SDR,
|
||||
];
|
||||
for (let i = 0; i < encTypes.length; i++) {
|
||||
Assert.equal(encTypes[i], getEncTypeForID(dbConnection, i + 1));
|
||||
}
|
||||
dbConnection.close();
|
||||
|
||||
deleteFile(OUTDIR, "signons-v2v3.sqlite");
|
||||
|
||||
/* ========== 7 ========== */
|
||||
testnum++;
|
||||
testdesc = "Test upgrade from v3->v4 storage";
|
||||
|
||||
await copyFile("signons-v3.sqlite");
|
||||
// Sanity check the test file.
|
||||
dbConnection = openDB("signons-v3.sqlite");
|
||||
Assert.equal(3, dbConnection.schemaVersion);
|
||||
|
||||
storage = reloadStorage(OUTDIR, "signons-v3.sqlite");
|
||||
Assert.equal(CURRENT_SCHEMA, dbConnection.schemaVersion);
|
||||
|
||||
// Remove old entry from permission manager.
|
||||
setLoginSavingEnabled("https://disabled.net", true);
|
||||
|
||||
// Check that timestamps and counts were initialized correctly
|
||||
checkStorageData(storage, [], [testuser1, testuser2]);
|
||||
|
||||
var logins = storage.getAllLogins();
|
||||
for (var i = 0; i < 2; i++) {
|
||||
Assert.ok(logins[i] instanceof Ci.nsILoginMetaInfo);
|
||||
Assert.equal(1, logins[i].timesUsed);
|
||||
LoginTestUtils.assertTimeIsAboutNow(logins[i].timeCreated);
|
||||
LoginTestUtils.assertTimeIsAboutNow(logins[i].timeLastUsed);
|
||||
LoginTestUtils.assertTimeIsAboutNow(logins[i].timePasswordChanged);
|
||||
}
|
||||
|
||||
/* ========== 8 ========== */
|
||||
testnum++;
|
||||
testdesc = "Test upgrade from v3->v4->v3 storage";
|
||||
|
||||
await copyFile("signons-v3v4.sqlite");
|
||||
// Sanity check the test file.
|
||||
dbConnection = openDB("signons-v3v4.sqlite");
|
||||
Assert.equal(3, dbConnection.schemaVersion);
|
||||
|
||||
storage = reloadStorage(OUTDIR, "signons-v3v4.sqlite");
|
||||
Assert.equal(CURRENT_SCHEMA, dbConnection.schemaVersion);
|
||||
|
||||
// testuser1 already has timestamps, testuser2 does not.
|
||||
checkStorageData(storage, [], [testuser1, testuser2]);
|
||||
|
||||
logins = storage.getAllLogins();
|
||||
|
||||
var t1, t2;
|
||||
if (logins[0].username == "testuser1") {
|
||||
t1 = logins[0];
|
||||
t2 = logins[1];
|
||||
} else {
|
||||
t1 = logins[1];
|
||||
t2 = logins[0];
|
||||
}
|
||||
|
||||
Assert.ok(t1 instanceof Ci.nsILoginMetaInfo);
|
||||
Assert.ok(t2 instanceof Ci.nsILoginMetaInfo);
|
||||
|
||||
Assert.equal(9, t1.timesUsed);
|
||||
Assert.equal(1262049951275, t1.timeCreated);
|
||||
Assert.equal(1262049951275, t1.timeLastUsed);
|
||||
Assert.equal(1262049951275, t1.timePasswordChanged);
|
||||
|
||||
Assert.equal(1, t2.timesUsed);
|
||||
LoginTestUtils.assertTimeIsAboutNow(t2.timeCreated);
|
||||
LoginTestUtils.assertTimeIsAboutNow(t2.timeLastUsed);
|
||||
LoginTestUtils.assertTimeIsAboutNow(t2.timePasswordChanged);
|
||||
|
||||
/* ========== 9 ========== */
|
||||
testnum++;
|
||||
testdesc = "Test upgrade from v4 storage";
|
||||
|
||||
await copyFile("signons-v4.sqlite");
|
||||
// Sanity check the test file.
|
||||
dbConnection = openDB("signons-v4.sqlite");
|
||||
Assert.equal(4, dbConnection.schemaVersion);
|
||||
Assert.ok(!dbConnection.tableExists("moz_deleted_logins"));
|
||||
|
||||
storage = reloadStorage(OUTDIR, "signons-v4.sqlite");
|
||||
Assert.equal(CURRENT_SCHEMA, dbConnection.schemaVersion);
|
||||
Assert.ok(dbConnection.tableExists("moz_deleted_logins"));
|
||||
|
||||
/* ========== 10 ========== */
|
||||
testnum++;
|
||||
testdesc = "Test upgrade from v4->v5->v4 storage";
|
||||
|
||||
await copyFile("signons-v4v5.sqlite");
|
||||
// Sanity check the test file.
|
||||
dbConnection = openDB("signons-v4v5.sqlite");
|
||||
Assert.equal(4, dbConnection.schemaVersion);
|
||||
Assert.ok(dbConnection.tableExists("moz_deleted_logins"));
|
||||
|
||||
storage = reloadStorage(OUTDIR, "signons-v4v5.sqlite");
|
||||
Assert.equal(CURRENT_SCHEMA, dbConnection.schemaVersion);
|
||||
Assert.ok(dbConnection.tableExists("moz_deleted_logins"));
|
||||
|
||||
/* ========== 11 ========== */
|
||||
testnum++;
|
||||
testdesc = "Test upgrade from v5->v6 storage";
|
||||
|
||||
await copyFile("signons-v5v6.sqlite");
|
||||
|
||||
// Sanity check the test file.
|
||||
dbConnection = openDB("signons-v5v6.sqlite");
|
||||
Assert.equal(5, dbConnection.schemaVersion);
|
||||
Assert.ok(dbConnection.tableExists("moz_disabledHosts"));
|
||||
|
||||
// Initial disabled hosts inside signons-v5v6.sqlite
|
||||
var disabledHosts = [
|
||||
"http://disabled1.example.com",
|
||||
"http://大.net",
|
||||
"http://xn--19g.com",
|
||||
];
|
||||
|
||||
LoginTestUtils.assertDisabledHostsEqual(
|
||||
disabledHosts,
|
||||
getAllDisabledHostsFromMozStorage(dbConnection)
|
||||
);
|
||||
|
||||
// Reload storage
|
||||
storage = reloadStorage(OUTDIR, "signons-v5v6.sqlite");
|
||||
Assert.equal(CURRENT_SCHEMA, dbConnection.schemaVersion);
|
||||
|
||||
// moz_disabledHosts should now be empty after migration.
|
||||
LoginTestUtils.assertDisabledHostsEqual(
|
||||
[],
|
||||
getAllDisabledHostsFromMozStorage(dbConnection)
|
||||
);
|
||||
|
||||
// Get all the other hosts currently saved in the permission manager.
|
||||
let hostsInPermissionManager = getAllDisabledHostsFromPermissionManager();
|
||||
|
||||
// Converted to punycode
|
||||
disabledHosts = [
|
||||
"http://disabled1.example.com",
|
||||
"http://xn--pss.net",
|
||||
"http://xn--19g.com",
|
||||
];
|
||||
|
||||
// All disabledHosts should have migrated to the permission manager
|
||||
LoginTestUtils.assertDisabledHostsEqual(
|
||||
disabledHosts,
|
||||
hostsInPermissionManager
|
||||
);
|
||||
|
||||
// Remove all disabled hosts from the permission manager before test ends
|
||||
for (let host of disabledHosts) {
|
||||
setLoginSavingEnabled(host, true);
|
||||
}
|
||||
|
||||
/* ========== 12 ========== */
|
||||
testnum++;
|
||||
testdesc = "Create nsILoginInfo instances for testing with";
|
||||
|
||||
testuser1 = new nsLoginInfo();
|
||||
testuser1.init(
|
||||
"http://dummyhost.mozilla.org",
|
||||
"",
|
||||
null,
|
||||
"dummydude",
|
||||
"itsasecret",
|
||||
"put_user_here",
|
||||
"put_pw_here"
|
||||
);
|
||||
|
||||
/*
|
||||
* ---------------------- DB Corruption ----------------------
|
||||
* Try to initialize with a corrupt database file. This should create a backup
|
||||
* file, then upon next use create a new database file.
|
||||
*/
|
||||
|
||||
/* ========== 13 ========== */
|
||||
testnum++;
|
||||
testdesc = "Corrupt database and backup";
|
||||
|
||||
const filename = "signons-c.sqlite";
|
||||
const filepath = OS.Path.join(OS.Constants.Path.profileDir, filename);
|
||||
|
||||
await OS.File.copy(do_get_file("data/corruptDB.sqlite").path, filepath);
|
||||
|
||||
// will init mozStorage module with corrupt database, init should fail
|
||||
Assert.throws(
|
||||
() => reloadStorage(OS.Constants.Path.profileDir, filename),
|
||||
/Initialization failed/
|
||||
);
|
||||
|
||||
// check that the backup file exists
|
||||
Assert.ok(await OS.File.exists(filepath + ".corrupt"));
|
||||
|
||||
// check that the original corrupt file has been deleted
|
||||
Assert.equal(false, await OS.File.exists(filepath));
|
||||
|
||||
// initialize the storage module again
|
||||
storage = reloadStorage(OS.Constants.Path.profileDir, filename);
|
||||
|
||||
// use the storage module again, should work now
|
||||
storage.addLogin(testuser1);
|
||||
checkStorageData(storage, [], [testuser1]);
|
||||
|
||||
// check the file exists
|
||||
var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.initWithPath(OS.Constants.Path.profileDir);
|
||||
file.append(filename);
|
||||
Assert.ok(file.exists());
|
||||
|
||||
deleteFile(OS.Constants.Path.profileDir, filename + ".corrupt");
|
||||
deleteFile(OS.Constants.Path.profileDir, filename);
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
"FAILED in test #" + testnum + " -- " + testdesc + ": " + e
|
||||
);
|
||||
}
|
||||
});
|
|
@ -1,5 +1,6 @@
|
|||
[DEFAULT]
|
||||
head = head.js
|
||||
skip-if = os == "android" # Not supported on GV because we can't add/remove from storage.
|
||||
support-files = data/**
|
||||
|
||||
# Test JSON file access and import from SQLite, not applicable to Android.
|
||||
|
@ -8,11 +9,7 @@ skip-if = os == "android"
|
|||
[test_module_LoginStore.js]
|
||||
skip-if = os == "android"
|
||||
|
||||
# Test SQLite database backup and migration, applicable to Android only.
|
||||
[test_storage_mozStorage.js]
|
||||
skip-if = os != "android"
|
||||
|
||||
# The following tests apply to any storage back-end.
|
||||
# The following tests apply to any storage back-end that supports add/modify/remove.
|
||||
[test_context_menu.js]
|
||||
skip-if = os == "android" # The context menu isn't used on Android.
|
||||
# LoginManagerContextMenu is only included for MOZ_BUILD_APP == 'browser'.
|
||||
|
|
Загрузка…
Ссылка в новой задаче