Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* Any copyright is dedicated to the Public Domain.
const { LoginRec } = ChromeUtils.importESModule(
);
const { Service } = ChromeUtils.importESModule(
);
const { SyncedRecordsTelemetry } = ChromeUtils.importESModule(
);
async function checkRecord(
name,
record,
expectedCount,
timeCreated,
expectedTimeCreated,
timePasswordChanged,
expectedTimePasswordChanged,
recordIsUpdated
) {
let engine = Service.engineManager.get("passwords");
let store = engine._store;
let logins = await Services.logins.searchLoginsAsync({
origin: record.hostname,
formActionOrigin: record.formSubmitURL,
});
_("Record" + name + ":" + JSON.stringify(logins));
_("Count" + name + ":" + logins.length);
Assert.equal(logins.length, expectedCount);
if (expectedCount > 0) {
Assert.ok(!!(await store.getAllIDs())[record.id]);
let stored_record = logins[0].QueryInterface(Ci.nsILoginMetaInfo);
if (timeCreated !== undefined) {
Assert.equal(stored_record.timeCreated, expectedTimeCreated);
}
if (timePasswordChanged !== undefined) {
if (recordIsUpdated) {
Assert.ok(
stored_record.timePasswordChanged >= expectedTimePasswordChanged
);
} else {
Assert.equal(
stored_record.timePasswordChanged,
expectedTimePasswordChanged
);
}
return stored_record.timePasswordChanged;
}
} else {
Assert.ok(!(await store.getAllIDs())[record.id]);
}
return undefined;
}
async function changePassword(
name,
hostname,
password,
expectedCount,
timeCreated,
expectedTimeCreated,
timePasswordChanged,
expectedTimePasswordChanged,
insert,
recordIsUpdated
) {
const BOGUS_GUID = "zzzzzz" + hostname;
let record = new LoginRec("passwords", BOGUS_GUID);
record.cleartext = {
id: BOGUS_GUID,
hostname,
formSubmitURL: hostname,
username: "john",
password,
usernameField: "username",
passwordField: "password",
};
if (timeCreated !== undefined) {
record.timeCreated = timeCreated;
}
if (timePasswordChanged !== undefined) {
record.timePasswordChanged = timePasswordChanged;
}
let engine = Service.engineManager.get("passwords");
let store = engine._store;
if (insert) {
let countTelemetry = new SyncedRecordsTelemetry();
Assert.equal(
(await store.applyIncomingBatch([record], countTelemetry)).length,
0
);
}
return checkRecord(
name,
record,
expectedCount,
timeCreated,
expectedTimeCreated,
timePasswordChanged,
expectedTimePasswordChanged,
recordIsUpdated
);
}
async function test_apply_records_with_times(
hostname,
timeCreated,
timePasswordChanged
) {
// The following record is going to be inserted in the store and it needs
// to be found there. Then its timestamps are going to be compared to
// the expected values.
await changePassword(
" ",
hostname,
"password",
1,
timeCreated,
timeCreated,
timePasswordChanged,
timePasswordChanged,
true
);
}
async function test_apply_multiple_records_with_times() {
// The following records are going to be inserted in the store and they need
// to be found there. Then their timestamps are going to be compared to
// the expected values.
await changePassword(
"A",
"password",
1,
undefined,
undefined,
undefined,
undefined,
true
);
await changePassword(
"B",
"password",
1,
1000,
1000,
undefined,
undefined,
true
);
await changePassword(
"C",
"password",
1,
undefined,
undefined,
1000,
1000,
true
);
await changePassword(
"D",
"password",
1,
1000,
1000,
1000,
1000,
true
);
// The following records are not going to be inserted in the store and they
// are not going to be found there.
await changePassword(
"NotInStoreA",
"password",
0,
undefined,
undefined,
undefined,
undefined,
false
);
await changePassword(
"NotInStoreB",
"password",
0,
1000,
1000,
undefined,
undefined,
false
);
await changePassword(
"NotInStoreC",
"password",
0,
undefined,
undefined,
1000,
1000,
false
);
await changePassword(
"NotInStoreD",
"password",
0,
1000,
1000,
1000,
1000,
false
);
}
async function test_apply_same_record_with_different_times() {
// The following record is going to be inserted multiple times in the store
// and it needs to be found there. Then its timestamps are going to be
// compared to the expected values.
/* eslint-disable no-unused-vars */
/* The eslint linter thinks that timePasswordChanged is unused, even though
it is passed as an argument to changePassword. */
var timePasswordChanged = 100;
timePasswordChanged = await changePassword(
"A",
"password",
1,
100,
100,
100,
timePasswordChanged,
true
);
timePasswordChanged = await changePassword(
"A",
"password",
1,
100,
100,
800,
timePasswordChanged,
true,
true
);
timePasswordChanged = await changePassword(
"A",
"password",
1,
500,
100,
800,
timePasswordChanged,
true,
true
);
timePasswordChanged = await changePassword(
"A",
"password2",
1,
500,
100,
1536213005222,
timePasswordChanged,
true,
true
);
timePasswordChanged = await changePassword(
"A",
"password2",
1,
500,
100,
800,
timePasswordChanged,
true,
true
);
/* eslint-enable no-unused-vars */
}
async function test_LoginRec_toString(store, recordData) {
let rec = await store.createRecord(recordData.id);
ok(rec);
ok(!rec.toString().includes(rec.password));
}
add_task(async function run_test() {
const BOGUS_GUID_A = "zzzzzzzzzzzz";
const BOGUS_GUID_B = "yyyyyyyyyyyy";
let recordA = new LoginRec("passwords", BOGUS_GUID_A);
let recordB = new LoginRec("passwords", BOGUS_GUID_B);
recordA.cleartext = {
id: BOGUS_GUID_A,
hostname: "http://foo.bar.com",
formSubmitURL: "http://foo.bar.com",
httpRealm: "secure",
username: "john",
password: "smith",
usernameField: "username",
passwordField: "password",
};
recordB.cleartext = {
id: BOGUS_GUID_B,
hostname: "http://foo.baz.com",
formSubmitURL: "http://foo.baz.com",
username: "john",
password: "smith",
usernameField: "username",
passwordField: "password",
unknownStr: "an unknown string from another field",
};
let engine = Service.engineManager.get("passwords");
let store = engine._store;
try {
let countTelemetry = new SyncedRecordsTelemetry();
Assert.equal(
(await store.applyIncomingBatch([recordA, recordB], countTelemetry))
.length,
0
);
// Only the good record makes it to Services.logins.
let badLogins = await Services.logins.searchLoginsAsync({
origin: recordA.hostname,
formActionOrigin: recordA.formSubmitURL,
httpRealm: recordA.httpRealm,
});
let goodLogins = await Services.logins.searchLoginsAsync({
origin: recordB.hostname,
formActionOrigin: recordB.formSubmitURL,
});
_("Bad: " + JSON.stringify(badLogins));
_("Good: " + JSON.stringify(goodLogins));
_("Count: " + badLogins.length + ", " + goodLogins.length);
Assert.equal(goodLogins.length, 1);
Assert.equal(badLogins.length, 0);
// applyIncoming should've put any unknown fields from the server
// into a catch-all unknownFields field
Assert.equal(
goodLogins[0].unknownFields,
JSON.stringify({
unknownStr: "an unknown string from another field",
})
);
Assert.ok(!!(await store.getAllIDs())[BOGUS_GUID_B]);
Assert.ok(!(await store.getAllIDs())[BOGUS_GUID_A]);
await test_LoginRec_toString(store, recordB);
await test_apply_records_with_times(
undefined,
undefined
);
await test_apply_records_with_times("http://bfoo.baz.com", 1000, undefined);
await test_apply_records_with_times("http://cfoo.baz.com", undefined, 2000);
await test_apply_records_with_times("http://dfoo.baz.com", 1000, 2000);
await test_apply_multiple_records_with_times();
await test_apply_same_record_with_different_times();
} finally {
await store.wipe();
}
});