MSMigrationUtils.sys.mjs (24019B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 import { ctypes } from "resource://gre/modules/ctypes.sys.mjs"; 6 import { MigrationUtils } from "resource:///modules/MigrationUtils.sys.mjs"; 7 8 const lazy = {}; 9 10 ChromeUtils.defineESModuleGetters(lazy, { 11 PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs", 12 WindowsRegistry: "resource://gre/modules/WindowsRegistry.sys.mjs", 13 }); 14 15 const EDGE_FAVORITES = "AC\\MicrosoftEdge\\User\\Default\\Favorites"; 16 const FREE_CLOSE_FAILED = 0; 17 const INTERNET_EXPLORER_EDGE_GUID = [ 18 0x3ccd5499, 0x4b1087a8, 0x886015a2, 0x553bdd88, 19 ]; 20 const RESULT_SUCCESS = 0; 21 const VAULT_ENUMERATE_ALL_ITEMS = 512; 22 const WEB_CREDENTIALS_VAULT_ID = [ 23 0x4bf4c442, 0x41a09b8a, 0x4add80b3, 0x28db4d70, 24 ]; 25 26 const wintypes = { 27 BOOL: ctypes.int, 28 DWORD: ctypes.uint32_t, 29 DWORDLONG: ctypes.uint64_t, 30 CHAR: ctypes.char, 31 PCHAR: ctypes.char.ptr, 32 LPCWSTR: ctypes.char16_t.ptr, 33 PDWORD: ctypes.uint32_t.ptr, 34 VOIDP: ctypes.voidptr_t, 35 WORD: ctypes.uint16_t, 36 }; 37 38 // TODO: Bug 1202978 - Refactor MSMigrationUtils ctypes helpers 39 function CtypesKernelHelpers() { 40 this._structs = {}; 41 this._functions = {}; 42 this._libs = {}; 43 44 this._structs.SYSTEMTIME = new ctypes.StructType("SYSTEMTIME", [ 45 { wYear: wintypes.WORD }, 46 { wMonth: wintypes.WORD }, 47 { wDayOfWeek: wintypes.WORD }, 48 { wDay: wintypes.WORD }, 49 { wHour: wintypes.WORD }, 50 { wMinute: wintypes.WORD }, 51 { wSecond: wintypes.WORD }, 52 { wMilliseconds: wintypes.WORD }, 53 ]); 54 55 this._structs.FILETIME = new ctypes.StructType("FILETIME", [ 56 { dwLowDateTime: wintypes.DWORD }, 57 { dwHighDateTime: wintypes.DWORD }, 58 ]); 59 60 try { 61 this._libs.kernel32 = ctypes.open("Kernel32"); 62 63 this._functions.FileTimeToSystemTime = this._libs.kernel32.declare( 64 "FileTimeToSystemTime", 65 ctypes.winapi_abi, 66 wintypes.BOOL, 67 this._structs.FILETIME.ptr, 68 this._structs.SYSTEMTIME.ptr 69 ); 70 } catch (ex) { 71 this.finalize(); 72 } 73 } 74 75 CtypesKernelHelpers.prototype = { 76 /** 77 * Must be invoked once after last use of any of the provided helpers. 78 */ 79 finalize() { 80 this._structs = {}; 81 this._functions = {}; 82 for (let key in this._libs) { 83 let lib = this._libs[key]; 84 try { 85 lib.close(); 86 } catch (ex) {} 87 } 88 this._libs = {}; 89 }, 90 91 /** 92 * Converts a FILETIME struct (2 DWORDS), to a SYSTEMTIME struct, 93 * and then deduces the number of seconds since the epoch (which 94 * is the data we want for the cookie expiry date). 95 * 96 * @param {number} aTimeHi 97 * Least significant DWORD. 98 * @param {number} aTimeLo 99 * Most significant DWORD. 100 * @returns {number} the number of seconds since the epoch 101 */ 102 fileTimeToSecondsSinceEpoch(aTimeHi, aTimeLo) { 103 let fileTime = this._structs.FILETIME(); 104 fileTime.dwLowDateTime = aTimeLo; 105 fileTime.dwHighDateTime = aTimeHi; 106 let systemTime = this._structs.SYSTEMTIME(); 107 let result = this._functions.FileTimeToSystemTime( 108 fileTime.address(), 109 systemTime.address() 110 ); 111 if (result == 0) { 112 throw new Error(ctypes.winLastError); 113 } 114 115 // System time is in UTC, so we use Date.UTC to get milliseconds from epoch, 116 // then divide by 1000 to get seconds, and round down: 117 return Math.floor( 118 Date.UTC( 119 systemTime.wYear, 120 systemTime.wMonth - 1, 121 systemTime.wDay, 122 systemTime.wHour, 123 systemTime.wMinute, 124 systemTime.wSecond, 125 systemTime.wMilliseconds 126 ) / 1000 127 ); 128 }, 129 }; 130 131 function CtypesVaultHelpers() { 132 this._structs = {}; 133 this._functions = {}; 134 135 this._structs.GUID = new ctypes.StructType("GUID", [ 136 { id: wintypes.DWORD.array(4) }, 137 ]); 138 139 this._structs.VAULT_ITEM_ELEMENT = new ctypes.StructType( 140 "VAULT_ITEM_ELEMENT", 141 [ 142 // not documented 143 { schemaElementId: wintypes.DWORD }, 144 // not documented 145 { unknown1: wintypes.DWORD }, 146 // vault type 147 { type: wintypes.DWORD }, 148 // not documented 149 { unknown2: wintypes.DWORD }, 150 // value of the item 151 { itemValue: wintypes.LPCWSTR }, 152 // not documented 153 { unknown3: wintypes.CHAR.array(12) }, 154 ] 155 ); 156 157 this._structs.VAULT_ELEMENT = new ctypes.StructType("VAULT_ELEMENT", [ 158 // vault item schemaId 159 { schemaId: this._structs.GUID }, 160 // a pointer to the name of the browser VAULT_ITEM_ELEMENT 161 { pszCredentialFriendlyName: wintypes.LPCWSTR }, 162 // a pointer to the url VAULT_ITEM_ELEMENT 163 { pResourceElement: this._structs.VAULT_ITEM_ELEMENT.ptr }, 164 // a pointer to the username VAULT_ITEM_ELEMENT 165 { pIdentityElement: this._structs.VAULT_ITEM_ELEMENT.ptr }, 166 // not documented 167 { pAuthenticatorElement: this._structs.VAULT_ITEM_ELEMENT.ptr }, 168 // not documented 169 { pPackageSid: this._structs.VAULT_ITEM_ELEMENT.ptr }, 170 // time stamp in local format 171 { lowLastModified: wintypes.DWORD }, 172 { highLastModified: wintypes.DWORD }, 173 // not documented 174 { flags: wintypes.DWORD }, 175 // not documented 176 { dwPropertiesCount: wintypes.DWORD }, 177 // not documented 178 { pPropertyElements: this._structs.VAULT_ITEM_ELEMENT.ptr }, 179 ]); 180 181 try { 182 this._vaultcliLib = ctypes.open("vaultcli.dll"); 183 184 this._functions.VaultOpenVault = this._vaultcliLib.declare( 185 "VaultOpenVault", 186 ctypes.winapi_abi, 187 wintypes.DWORD, 188 // GUID 189 this._structs.GUID.ptr, 190 // Flags 191 wintypes.DWORD, 192 // Vault Handle 193 wintypes.VOIDP.ptr 194 ); 195 this._functions.VaultEnumerateItems = this._vaultcliLib.declare( 196 "VaultEnumerateItems", 197 ctypes.winapi_abi, 198 wintypes.DWORD, 199 // Vault Handle 200 wintypes.VOIDP, 201 // Flags 202 wintypes.DWORD, 203 // Items Count 204 wintypes.PDWORD, 205 // Items 206 ctypes.voidptr_t 207 ); 208 this._functions.VaultCloseVault = this._vaultcliLib.declare( 209 "VaultCloseVault", 210 ctypes.winapi_abi, 211 wintypes.DWORD, 212 // Vault Handle 213 wintypes.VOIDP 214 ); 215 this._functions.VaultGetItem = this._vaultcliLib.declare( 216 "VaultGetItem", 217 ctypes.winapi_abi, 218 wintypes.DWORD, 219 // Vault Handle 220 wintypes.VOIDP, 221 // Schema Id 222 this._structs.GUID.ptr, 223 // Resource 224 this._structs.VAULT_ITEM_ELEMENT.ptr, 225 // Identity 226 this._structs.VAULT_ITEM_ELEMENT.ptr, 227 // Package Sid 228 this._structs.VAULT_ITEM_ELEMENT.ptr, 229 // HWND Owner 230 wintypes.DWORD, 231 // Flags 232 wintypes.DWORD, 233 // Items 234 this._structs.VAULT_ELEMENT.ptr.ptr 235 ); 236 this._functions.VaultFree = this._vaultcliLib.declare( 237 "VaultFree", 238 ctypes.winapi_abi, 239 wintypes.DWORD, 240 // Memory 241 this._structs.VAULT_ELEMENT.ptr 242 ); 243 } catch (ex) { 244 this.finalize(); 245 } 246 } 247 248 CtypesVaultHelpers.prototype = { 249 /** 250 * Must be invoked once after last use of any of the provided helpers. 251 */ 252 finalize() { 253 this._structs = {}; 254 this._functions = {}; 255 try { 256 this._vaultcliLib.close(); 257 } catch (ex) {} 258 this._vaultcliLib = null; 259 }, 260 }; 261 262 var gEdgeDir; 263 function getEdgeLocalDataFolder() { 264 if (gEdgeDir) { 265 return gEdgeDir.clone(); 266 } 267 let packages = Services.dirsvc.get("LocalAppData", Ci.nsIFile); 268 packages.append("Packages"); 269 let edgeDir = packages.clone(); 270 edgeDir.append("Microsoft.MicrosoftEdge_8wekyb3d8bbwe"); 271 try { 272 if (edgeDir.exists() && edgeDir.isReadable() && edgeDir.isDirectory()) { 273 gEdgeDir = edgeDir; 274 return edgeDir.clone(); 275 } 276 277 // Let's try the long way: 278 let dirEntries = packages.directoryEntries; 279 while (dirEntries.hasMoreElements()) { 280 let subDir = dirEntries.nextFile; 281 if ( 282 subDir.leafName.startsWith("Microsoft.MicrosoftEdge") && 283 subDir.isReadable() && 284 subDir.isDirectory() 285 ) { 286 gEdgeDir = subDir; 287 return subDir.clone(); 288 } 289 } 290 } catch (ex) { 291 console.error( 292 "Exception trying to find the Edge favorites directory: ", 293 ex 294 ); 295 } 296 return null; 297 } 298 299 function Bookmarks(migrationType) { 300 this._migrationType = migrationType; 301 } 302 303 Bookmarks.prototype = { 304 type: MigrationUtils.resourceTypes.BOOKMARKS, 305 306 get exists() { 307 return !!this._favoritesFolder; 308 }, 309 310 get importedAppLabel() { 311 return this._migrationType == MSMigrationUtils.MIGRATION_TYPE_IE 312 ? "IE" 313 : "Edge"; 314 }, 315 316 __favoritesFolder: null, 317 get _favoritesFolder() { 318 if (!this.__favoritesFolder) { 319 if (this._migrationType == MSMigrationUtils.MIGRATION_TYPE_IE) { 320 let favoritesFolder = Services.dirsvc.get("Favs", Ci.nsIFile); 321 if (favoritesFolder.exists() && favoritesFolder.isReadable()) { 322 this.__favoritesFolder = favoritesFolder; 323 } 324 } else if (this._migrationType == MSMigrationUtils.MIGRATION_TYPE_EDGE) { 325 let edgeDir = getEdgeLocalDataFolder(); 326 if (edgeDir) { 327 edgeDir.appendRelativePath(EDGE_FAVORITES); 328 if ( 329 edgeDir.exists() && 330 edgeDir.isReadable() && 331 edgeDir.isDirectory() 332 ) { 333 this.__favoritesFolder = edgeDir; 334 } 335 } 336 } 337 } 338 return this.__favoritesFolder; 339 }, 340 341 __toolbarFolderName: null, 342 get _toolbarFolderName() { 343 if (!this.__toolbarFolderName) { 344 if (this._migrationType == MSMigrationUtils.MIGRATION_TYPE_IE) { 345 // Retrieve the name of IE's favorites subfolder that holds the bookmarks 346 // in the toolbar. This was previously stored in the registry and changed 347 // in IE7 to always be called "Links". 348 let folderName = lazy.WindowsRegistry.readRegKey( 349 Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, 350 "Software\\Microsoft\\Internet Explorer\\Toolbar", 351 "LinksFolderName" 352 ); 353 this.__toolbarFolderName = folderName || "Links"; 354 } else { 355 this.__toolbarFolderName = "Links"; 356 } 357 } 358 return this.__toolbarFolderName; 359 }, 360 361 migrate: function B_migrate(aCallback) { 362 return (async () => { 363 // Import to the bookmarks menu. 364 let folderGuid = lazy.PlacesUtils.bookmarks.menuGuid; 365 await this._migrateFolder(this._favoritesFolder, folderGuid); 366 })().then( 367 () => aCallback(true), 368 e => { 369 console.error(e); 370 aCallback(false); 371 } 372 ); 373 }, 374 375 async _migrateFolder(aSourceFolder, aDestFolderGuid) { 376 let { bookmarks, favicons } = 377 await this._getBookmarksInFolder(aSourceFolder); 378 if (!bookmarks.length) { 379 return; 380 } 381 382 await MigrationUtils.insertManyBookmarksWrapper(bookmarks, aDestFolderGuid); 383 MigrationUtils.insertManyFavicons(favicons).catch(console.error); 384 }, 385 386 /** 387 * Iterates through a bookmark folder to obtain whatever information from each bookmark is needed elsewhere. This function also recurses into child folders. 388 * 389 * @param {nsIFile} aSourceFolder the folder to search for bookmarks and subfolders. 390 * @returns {Promise<object>} An object with the following properties: 391 * {Object[]} bookmarks: 392 * An array of Objects with these properties: 393 * {number} type: A type mapping to one of the types in nsINavBookmarksService 394 * {string} title: The title of the bookmark 395 * {Object[]} children: An array of objects with the same structure as this one. 396 * 397 * {Object[]} favicons 398 * An array of Objects with these properties: 399 * {Uint8Array} faviconData: The binary data of a favicon 400 * {nsIURI} uri: The URI of the associated bookmark 401 */ 402 async _getBookmarksInFolder(aSourceFolder) { 403 // TODO (bug 741993): the favorites order is stored in the Registry, at 404 // HCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Favorites 405 // for IE, and in a similar location for Edge. 406 // Until we support it, bookmarks are imported in alphabetical order. 407 let entries = aSourceFolder.directoryEntries; 408 let rv = []; 409 let favicons = []; 410 while (entries.hasMoreElements()) { 411 let entry = entries.nextFile; 412 try { 413 // Make sure that entry.path == entry.target to not follow .lnk folder 414 // shortcuts which could lead to infinite cycles. 415 // Don't use isSymlink(), since it would throw for invalid 416 // lnk files pointing to URLs or to unresolvable paths. 417 if (entry.path == entry.target && entry.isDirectory()) { 418 let isBookmarksFolder = 419 entry.leafName == this._toolbarFolderName && 420 entry.parent.equals(this._favoritesFolder); 421 if (isBookmarksFolder && entry.isReadable()) { 422 // Import to the bookmarks toolbar. 423 let folderGuid = lazy.PlacesUtils.bookmarks.toolbarGuid; 424 await this._migrateFolder(entry, folderGuid); 425 } else if (entry.isReadable()) { 426 let { bookmarks: childBookmarks, favicons: childFavicons } = 427 await this._getBookmarksInFolder(entry); 428 favicons = favicons.concat(childFavicons); 429 rv.push({ 430 type: lazy.PlacesUtils.bookmarks.TYPE_FOLDER, 431 title: entry.leafName, 432 children: childBookmarks, 433 }); 434 } 435 } else { 436 // Strip the .url extension, to both check this is a valid link file, 437 // and get the associated title. 438 let matches = entry.leafName.match(/(.+)\.url$/i); 439 if (matches) { 440 let fileHandler = Cc[ 441 "@mozilla.org/network/protocol;1?name=file" 442 ].getService(Ci.nsIFileProtocolHandler); 443 let uri = fileHandler.readURLFile(entry); 444 // Silently failing in the event that the alternative data stream for the favicon doesn't exist 445 try { 446 let faviconData = await IOUtils.read(entry.path + ":favicon"); 447 favicons.push({ faviconData, uri }); 448 } catch {} 449 450 rv.push({ url: uri, title: matches[1] }); 451 } 452 } 453 } catch (ex) { 454 console.error( 455 "Unable to import ", 456 this.importedAppLabel, 457 " favorite (", 458 entry.leafName, 459 "): ", 460 ex 461 ); 462 } 463 } 464 return { bookmarks: rv, favicons }; 465 }, 466 }; 467 468 function getTypedURLs(registryKeyPath) { 469 // The list of typed URLs is a sort of annotation stored in the registry. 470 // The number of entries stored is not UI-configurable, but has changed 471 // between different Windows versions. We just keep reading up to the first 472 // non-existing entry to support different limits / states of the registry. 473 let typedURLs = new Map(); 474 let typedURLKey = Cc["@mozilla.org/windows-registry-key;1"].createInstance( 475 Ci.nsIWindowsRegKey 476 ); 477 let typedURLTimeKey = Cc[ 478 "@mozilla.org/windows-registry-key;1" 479 ].createInstance(Ci.nsIWindowsRegKey); 480 let cTypes = new CtypesKernelHelpers(); 481 try { 482 try { 483 typedURLKey.open( 484 Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, 485 registryKeyPath + "\\TypedURLs", 486 Ci.nsIWindowsRegKey.ACCESS_READ 487 ); 488 } catch (ex) { 489 // Ignore errors opening this registry key - if it doesn't work, there's 490 // no way we can get useful info here. 491 return typedURLs; 492 } 493 try { 494 typedURLTimeKey.open( 495 Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, 496 registryKeyPath + "\\TypedURLsTime", 497 Ci.nsIWindowsRegKey.ACCESS_READ 498 ); 499 } catch (ex) { 500 typedURLTimeKey = null; 501 } 502 let entryName; 503 for ( 504 let entry = 1; 505 typedURLKey.hasValue((entryName = "url" + entry)); 506 entry++ 507 ) { 508 let url = typedURLKey.readStringValue(entryName); 509 // If we can't get a date for whatever reason, default to 6 months ago 510 let timeTyped = Date.now() - 31536000 / 2; 511 if (typedURLTimeKey && typedURLTimeKey.hasValue(entryName)) { 512 let urlTime = ""; 513 try { 514 urlTime = typedURLTimeKey.readBinaryValue(entryName); 515 } catch (ex) { 516 console.error("Couldn't read url time for ", entryName); 517 } 518 if (urlTime.length == 8) { 519 let urlTimeHex = []; 520 for (let i = 0; i < 8; i++) { 521 let c = urlTime.charCodeAt(i).toString(16); 522 if (c.length == 1) { 523 c = "0" + c; 524 } 525 urlTimeHex.unshift(c); 526 } 527 try { 528 let hi = parseInt(urlTimeHex.slice(0, 4).join(""), 16); 529 let lo = parseInt(urlTimeHex.slice(4, 8).join(""), 16); 530 // Convert to seconds since epoch: 531 let secondsSinceEpoch = cTypes.fileTimeToSecondsSinceEpoch(hi, lo); 532 533 // If the date is very far in the past, just use the default 534 if (secondsSinceEpoch > Date.now() / 1000000) { 535 // Callers expect PRTime, which is microseconds since epoch: 536 timeTyped = secondsSinceEpoch * 1000; 537 } 538 } catch (ex) { 539 // Ignore conversion exceptions. Callers will have to deal 540 // with the fallback value. 541 } 542 } 543 } 544 typedURLs.set(url, timeTyped * 1000); 545 } 546 } catch (ex) { 547 console.error("Error reading typed URL history: ", ex); 548 } finally { 549 if (typedURLKey) { 550 typedURLKey.close(); 551 } 552 if (typedURLTimeKey) { 553 typedURLTimeKey.close(); 554 } 555 cTypes.finalize(); 556 } 557 return typedURLs; 558 } 559 560 // Migrator for form passwords 561 function WindowsVaultFormPasswords() {} 562 563 WindowsVaultFormPasswords.prototype = { 564 type: MigrationUtils.resourceTypes.PASSWORDS, 565 566 get exists() { 567 // check if there are passwords available for migration. 568 return this.migrate(() => {}, true); 569 }, 570 571 /** 572 * If aOnlyCheckExists is false, import the form passwords from the vault 573 * and then call the aCallback. 574 * Otherwise, check if there are passwords in the vault. 575 * 576 * @param {Function} aCallback - a callback called when the migration is done. 577 * @param {boolean} [aOnlyCheckExists=false] - if aOnlyCheckExists is true, just check if there are some 578 * passwords to migrate. Import the passwords from the vault and call aCallback otherwise. 579 * @returns {boolean} true if there are passwords in the vault and aOnlyCheckExists is set to true, 580 * false if there is no password in the vault and aOnlyCheckExists is set to true, undefined if 581 * aOnlyCheckExists is set to false. 582 */ 583 async migrate(aCallback, aOnlyCheckExists = false) { 584 // check if the vault item is an IE/Edge one 585 function _isIEOrEdgePassword(id) { 586 return ( 587 id[0] == INTERNET_EXPLORER_EDGE_GUID[0] && 588 id[1] == INTERNET_EXPLORER_EDGE_GUID[1] && 589 id[2] == INTERNET_EXPLORER_EDGE_GUID[2] && 590 id[3] == INTERNET_EXPLORER_EDGE_GUID[3] 591 ); 592 } 593 594 let ctypesVaultHelpers = new CtypesVaultHelpers(); 595 let ctypesKernelHelpers = new CtypesKernelHelpers(); 596 let migrationSucceeded = true; 597 let successfulVaultOpen = false; 598 let error, vault; 599 try { 600 // web credentials vault id 601 let vaultGuid = new ctypesVaultHelpers._structs.GUID( 602 WEB_CREDENTIALS_VAULT_ID 603 ); 604 error = new wintypes.DWORD(); 605 // web credentials vault 606 vault = new wintypes.VOIDP(); 607 // open the current vault using the vaultGuid 608 error = ctypesVaultHelpers._functions.VaultOpenVault( 609 vaultGuid.address(), 610 0, 611 vault.address() 612 ); 613 if (error != RESULT_SUCCESS) { 614 throw new Error("Unable to open Vault: " + error); 615 } 616 successfulVaultOpen = true; 617 618 let item = new ctypesVaultHelpers._structs.VAULT_ELEMENT.ptr(); 619 let itemCount = new wintypes.DWORD(); 620 // enumerate all the available items. This api is going to return a table of all the 621 // available items and item is going to point to the first element of this table. 622 error = ctypesVaultHelpers._functions.VaultEnumerateItems( 623 vault, 624 VAULT_ENUMERATE_ALL_ITEMS, 625 itemCount.address(), 626 item.address() 627 ); 628 if (error != RESULT_SUCCESS) { 629 throw new Error("Unable to enumerate Vault items: " + error); 630 } 631 632 let logins = []; 633 for (let j = 0; j < itemCount.value; j++) { 634 try { 635 // if it's not an ie/edge password, skip it 636 if (!_isIEOrEdgePassword(item.contents.schemaId.id)) { 637 continue; 638 } 639 let url = 640 item.contents.pResourceElement.contents.itemValue.readString(); 641 let realURL = URL.parse(url); 642 if ( 643 !realURL || 644 !["http:", "https:", "ftp:"].includes(realURL.protocol) 645 ) { 646 // Ignore items for non-URLs or URLs that aren't HTTP(S)/FTP 647 continue; 648 } 649 650 // if aOnlyCheckExists is set to true, the purpose of the call is to return true if there is at 651 // least a password which is true in this case because a password was by now already found 652 if (aOnlyCheckExists) { 653 return true; 654 } 655 let username = 656 item.contents.pIdentityElement.contents.itemValue.readString(); 657 // the current login credential object 658 let credential = new ctypesVaultHelpers._structs.VAULT_ELEMENT.ptr(); 659 error = ctypesVaultHelpers._functions.VaultGetItem( 660 vault, 661 item.contents.schemaId.address(), 662 item.contents.pResourceElement, 663 item.contents.pIdentityElement, 664 null, 665 0, 666 0, 667 credential.address() 668 ); 669 if (error != RESULT_SUCCESS) { 670 throw new Error("Unable to get item: " + error); 671 } 672 673 let password = 674 credential.contents.pAuthenticatorElement.contents.itemValue.readString(); 675 let creation = Date.now(); 676 try { 677 // login manager wants time in milliseconds since epoch, so convert 678 // to seconds since epoch and multiply to get milliseconds: 679 creation = 680 ctypesKernelHelpers.fileTimeToSecondsSinceEpoch( 681 item.contents.highLastModified, 682 item.contents.lowLastModified 683 ) * 1000; 684 } catch (ex) { 685 // Ignore exceptions in the dates and just create the login for right now. 686 } 687 // create a new login 688 logins.push({ 689 username, 690 password, 691 origin: realURL.URI.prePath, 692 timeCreated: creation, 693 }); 694 695 // close current item 696 error = ctypesVaultHelpers._functions.VaultFree(credential); 697 if (error == FREE_CLOSE_FAILED) { 698 throw new Error("Unable to free item: " + error); 699 } 700 } catch (e) { 701 migrationSucceeded = false; 702 console.error(e); 703 } finally { 704 // move to next item in the table returned by VaultEnumerateItems 705 item = item.increment(); 706 } 707 } 708 709 if (logins.length) { 710 await MigrationUtils.insertLoginsWrapper(logins); 711 } 712 } catch (e) { 713 console.error(e); 714 migrationSucceeded = false; 715 } finally { 716 if (successfulVaultOpen) { 717 // close current vault 718 error = ctypesVaultHelpers._functions.VaultCloseVault(vault); 719 if (error == FREE_CLOSE_FAILED) { 720 console.error("Unable to close vault: ", error); 721 } 722 } 723 ctypesKernelHelpers.finalize(); 724 ctypesVaultHelpers.finalize(); 725 aCallback(migrationSucceeded); 726 } 727 if (aOnlyCheckExists) { 728 return false; 729 } 730 return undefined; 731 }, 732 }; 733 734 export var MSMigrationUtils = { 735 MIGRATION_TYPE_IE: 1, 736 MIGRATION_TYPE_EDGE: 2, 737 CtypesKernelHelpers, 738 getBookmarksMigrator(migrationType = this.MIGRATION_TYPE_IE) { 739 return new Bookmarks(migrationType); 740 }, 741 getWindowsVaultFormPasswordsMigrator() { 742 return new WindowsVaultFormPasswords(); 743 }, 744 getTypedURLs, 745 getEdgeLocalDataFolder, 746 };