test_password_tracker.js (7945B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 const { PasswordEngine, LoginRec } = ChromeUtils.importESModule( 5 "resource://services-sync/engines/passwords.sys.mjs" 6 ); 7 const { Service } = ChromeUtils.importESModule( 8 "resource://services-sync/service.sys.mjs" 9 ); 10 11 let engine; 12 let store; 13 let tracker; 14 15 add_task(async function setup() { 16 await Service.engineManager.register(PasswordEngine); 17 engine = Service.engineManager.get("passwords"); 18 store = engine._store; 19 tracker = engine._tracker; 20 }); 21 22 add_task(async function test_tracking() { 23 let recordNum = 0; 24 25 _("Verify we've got an empty tracker to work with."); 26 let changes = await engine.getChangedIDs(); 27 do_check_empty(changes); 28 29 let exceptionHappened = false; 30 try { 31 await tracker.getChangedIDs(); 32 } catch (ex) { 33 exceptionHappened = true; 34 } 35 ok(exceptionHappened, "tracker does not keep track of changes"); 36 37 async function createPassword() { 38 _("RECORD NUM: " + recordNum); 39 let record = new LoginRec("passwords", "GUID" + recordNum); 40 record.cleartext = { 41 id: "GUID" + recordNum, 42 hostname: "http://foo.bar.com", 43 formSubmitURL: "http://foo.bar.com", 44 username: "john" + recordNum, 45 password: "smith", 46 usernameField: "username", 47 passwordField: "password", 48 }; 49 recordNum++; 50 let login = store._nsLoginInfoFromRecord(record); 51 await Services.logins.addLoginAsync(login); 52 await tracker.asyncObserver.promiseObserversComplete(); 53 } 54 55 try { 56 tracker.start(); 57 await createPassword(); 58 changes = await engine.getChangedIDs(); 59 do_check_attribute_count(changes, 1); 60 Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE); 61 Assert.equal(changes.GUID0.counter, 1); 62 Assert.ok(typeof changes.GUID0.modified, "number"); 63 64 _("Starting twice won't do any harm."); 65 tracker.start(); 66 await createPassword(); 67 changes = await engine.getChangedIDs(); 68 do_check_attribute_count(changes, 2); 69 Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE * 2); 70 Assert.equal(changes.GUID0.counter, 1); 71 Assert.equal(changes.GUID1.counter, 1); 72 73 // The tracker doesn't keep track of changes, so 3 changes 74 // should still be returned, but the score is not updated. 75 _("Let's stop tracking again."); 76 tracker.resetScore(); 77 await tracker.stop(); 78 await createPassword(); 79 changes = await engine.getChangedIDs(); 80 do_check_attribute_count(changes, 3); 81 Assert.equal(tracker.score, 0); 82 Assert.equal(changes.GUID0.counter, 1); 83 Assert.equal(changes.GUID1.counter, 1); 84 Assert.equal(changes.GUID2.counter, 1); 85 86 _("Stopping twice won't do any harm."); 87 await tracker.stop(); 88 await createPassword(); 89 changes = await engine.getChangedIDs(); 90 do_check_attribute_count(changes, 4); 91 Assert.equal(tracker.score, 0); 92 } finally { 93 _("Clean up."); 94 await store.wipe(); 95 tracker.resetScore(); 96 await tracker.stop(); 97 } 98 }); 99 100 add_task(async function test_onWipe() { 101 _("Verify we've got an empty tracker to work with."); 102 const changes = await engine.getChangedIDs(); 103 do_check_empty(changes); 104 Assert.equal(tracker.score, 0); 105 106 try { 107 _("A store wipe should increment the score"); 108 tracker.start(); 109 await store.wipe(); 110 await tracker.asyncObserver.promiseObserversComplete(); 111 112 Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE); 113 } finally { 114 tracker.resetScore(); 115 await tracker.stop(); 116 } 117 }); 118 119 add_task(async function test_removeAllLogins() { 120 let recordNum = 0; 121 _("Verify that all tracked logins are removed."); 122 123 // Perform this test twice, the first time where a sync is not performed 124 // between adding and removing items and the second time where a sync is 125 // performed. In the former case, the logins will just be deleted because 126 // they have never been synced, so they won't be detected as changes. In 127 // the latter case, the logins have been synced so they will be marked for 128 // deletion. 129 for (let syncBeforeRemove of [false, true]) { 130 async function createPassword() { 131 _("RECORD NUM: " + recordNum); 132 let record = new LoginRec("passwords", "GUID" + recordNum); 133 record.cleartext = { 134 id: "GUID" + recordNum, 135 hostname: "http://foo.bar.com", 136 formSubmitURL: "http://foo.bar.com", 137 username: "john" + recordNum, 138 password: "smith", 139 usernameField: "username", 140 passwordField: "password", 141 }; 142 recordNum++; 143 let login = store._nsLoginInfoFromRecord(record); 144 await Services.logins.addLoginAsync(login); 145 146 await tracker.asyncObserver.promiseObserversComplete(); 147 } 148 try { 149 _("Tell tracker to start tracking changes"); 150 tracker.start(); 151 await createPassword(); 152 await createPassword(); 153 let changes = await engine.getChangedIDs(); 154 do_check_attribute_count(changes, 2); 155 Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE * 2); 156 157 if (syncBeforeRemove) { 158 let logins = await Services.logins.getAllLogins(); 159 for (let login of logins) { 160 engine.markSynced(login.guid); 161 } 162 } 163 164 _("Tell sync to remove all logins"); 165 Services.logins.removeAllUserFacingLogins(); 166 await tracker.asyncObserver.promiseObserversComplete(); 167 changes = await engine.getChangedIDs(); 168 do_check_attribute_count(changes, syncBeforeRemove ? 2 : 0); 169 Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE * 5); 170 171 let deletedGuids = await engine._store.getAllIDs(); 172 if (syncBeforeRemove) { 173 for (let guid in deletedGuids) { 174 let deletedLogin = await engine._store._getLoginFromGUID(guid); 175 176 Assert.equal(deletedLogin.hostname, null, "deleted login hostname"); 177 Assert.equal( 178 deletedLogin.formActionOrigin, 179 null, 180 "deleted login formActionOrigin" 181 ); 182 Assert.equal( 183 deletedLogin.formSubmitURL, 184 null, 185 "deleted login formSubmitURL" 186 ); 187 Assert.equal(deletedLogin.httpRealm, null, "deleted login httpRealm"); 188 Assert.equal(deletedLogin.username, null, "deleted login username"); 189 Assert.equal(deletedLogin.password, null, "deleted login password"); 190 Assert.equal( 191 deletedLogin.usernameField, 192 "", 193 "deleted login usernameField" 194 ); 195 Assert.equal( 196 deletedLogin.passwordField, 197 "", 198 "deleted login passwordField" 199 ); 200 Assert.equal( 201 deletedLogin.unknownFields, 202 null, 203 "deleted login unknownFields" 204 ); 205 Assert.equal( 206 deletedLogin.timeCreated, 207 0, 208 "deleted login timeCreated" 209 ); 210 Assert.equal( 211 deletedLogin.timeLastUsed, 212 0, 213 "deleted login timeLastUsed" 214 ); 215 Assert.equal(deletedLogin.timesUsed, 0, "deleted login timesUsed"); 216 217 // These fields are not reset when the login is removed. 218 Assert.ok(deletedLogin.guid.startsWith("GUID"), "deleted login guid"); 219 Assert.equal( 220 deletedLogin.everSynced, 221 true, 222 "deleted login everSynced" 223 ); 224 Assert.equal( 225 deletedLogin.syncCounter, 226 2, 227 "deleted login syncCounter" 228 ); 229 Assert.greater( 230 deletedLogin.timePasswordChanged, 231 0, 232 "deleted login timePasswordChanged" 233 ); 234 } 235 } else { 236 Assert.equal( 237 Object.keys(deletedGuids).length, 238 0, 239 "no logins remain after removeAllUserFacingLogins" 240 ); 241 } 242 } finally { 243 _("Clean up."); 244 await store.wipe(); 245 tracker.resetScore(); 246 await tracker.stop(); 247 } 248 } 249 });