Bug 1205053 - use registry typedURLs to import rudimentary history from MS Edge, r=dolske

--HG--
extra : commitid : 5c0aDxUWRp0
extra : rebase_source : 2762ed6466d7f0ab13e619c52f1cebdf6d3073b1
This commit is contained in:
Gijs Kruitbosch 2015-09-15 22:18:41 +01:00
parent b45c5702f2
commit 4e2577e37c
4 changed files with 152 additions and 31 deletions

View File

@ -5,9 +5,79 @@
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource:///modules/MigrationUtils.jsm");
Cu.import("resource:///modules/MSMigrationUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
const kEdgeRegistryRoot = "SOFTWARE\\Classes\\Local Settings\\Software\\" +
"Microsoft\\Windows\\CurrentVersion\\AppContainer\\Storage\\" +
"microsoft.microsoftedge_8wekyb3d8bbwe\\MicrosoftEdge";
function EdgeTypedURLMigrator() {
}
EdgeTypedURLMigrator.prototype = {
type: MigrationUtils.resourceTypes.HISTORY,
get _typedURLs() {
if (!this.__typedURLs) {
this.__typedURLs = MSMigrationUtils.getTypedURLs(kEdgeRegistryRoot);
}
return this.__typedURLs;
},
get exists() {
return this._typedURLs.size > 0;
},
migrate: function(aCallback) {
let rv = true;
let typedURLs = this._typedURLs;
let places = [];
for (let [urlString, time] of typedURLs) {
let uri;
try {
uri = Services.io.newURI(urlString, null, null);
if (["http", "https", "ftp"].indexOf(uri.scheme) == -1) {
continue;
}
} catch (ex) {
Cu.reportError(ex);
continue;
}
// Note that the time will be in microseconds (PRTime),
// and Date.now() returns milliseconds. Places expects PRTime,
// so we multiply the Date.now return value to make up the difference.
let visitDate = time || (Date.now() * 1000);
places.push({
uri,
visits: [{ transitionType: Ci.nsINavHistoryService.TRANSITION_TYPED,
visitDate}]
});
}
if (places.length == 0) {
aCallback(typedURLs.size == 0);
return;
}
PlacesUtils.asyncHistory.updatePlaces(places, {
_success: false,
handleResult: function() {
// Importing any entry is considered a successful import.
this._success = true;
},
handleError: function() {},
handleCompletion: function() {
aCallback(this._success);
}
});
},
}
function EdgeProfileMigrator() {
}
@ -18,6 +88,7 @@ EdgeProfileMigrator.prototype.getResources = function() {
let resources = [
MSMigrationUtils.getBookmarksMigrator(MSMigrationUtils.MIGRATION_TYPE_EDGE),
MSMigrationUtils.getCookiesMigrator(MSMigrationUtils.MIGRATION_TYPE_EDGE),
new EdgeTypedURLMigrator(),
];
let windowsVaultFormPasswordsMigrator =
MSMigrationUtils.getWindowsVaultFormPasswordsMigrator();

View File

@ -46,34 +46,9 @@ History.prototype = {
get exists() true,
__typedURLs: null,
get _typedURLs() {
if (!this.__typedURLs) {
// The list of typed URLs is a sort of annotation stored in the registry.
// Currently, IE stores 25 entries and this value is not configurable,
// but we just keep reading up to the first non-existing entry to support
// possible future bumps of this limit.
this.__typedURLs = {};
let registry = Cc["@mozilla.org/windows-registry-key;1"].
createInstance(Ci.nsIWindowsRegKey);
try {
registry.open(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
"Software\\Microsoft\\Internet Explorer\\TypedURLs",
Ci.nsIWindowsRegKey.ACCESS_READ);
for (let entry = 1; registry.hasValue("url" + entry); entry++) {
let url = registry.readStringValue("url" + entry);
this.__typedURLs[url] = true;
}
} catch (ex) {
} finally {
registry.close();
}
}
return this.__typedURLs;
},
migrate: function H_migrate(aCallback) {
let places = [];
let typedURLs = MSMigrationUtils.getTypedURLs("Software\\Microsoft\\Internet Explorer");
let historyEnumerator = Cc["@mozilla.org/profile/migrator/iehistoryenumerator;1"].
createInstance(Ci.nsISimpleEnumerator);
while (historyEnumerator.hasMoreElements()) {
@ -93,11 +68,14 @@ History.prototype = {
}
// The typed urls are already fixed-up, so we can use them for comparison.
let transitionType = this._typedURLs[uri.spec] ?
let transitionType = typedURLs.has(uri.spec) ?
Ci.nsINavHistoryService.TRANSITION_TYPED :
Ci.nsINavHistoryService.TRANSITION_LINK;
// use the current date if we have no visits for this entry
let lastVisitTime = entry.get("time") || Date.now();
// use the current date if we have no visits for this entry.
// Note that the entry will have a time in microseconds (PRTime),
// and Date.now() returns milliseconds. Places expects PRTime,
// so we multiply the Date.now return value to make up the difference.
let lastVisitTime = entry.get("time") || (Date.now() * 1000);
places.push(
{ uri: uri,

View File

@ -686,8 +686,15 @@ Cookies.prototype = {
host = "." + host;
}
let expireTime = this.ctypesKernelHelpers.fileTimeToSecondsSinceEpoch(Number(expireTimeHi),
// Fallback: expire in 1h
let expireTime = (Date.now() + 3600 * 1000) * 1000;
try {
expireTime = this.ctypesKernelHelpers.fileTimeToSecondsSinceEpoch(Number(expireTimeHi),
Number(expireTimeLo));
} catch (ex) {
Cu.reportError("Failed to get expiry time for cookie for " + host);
}
Services.cookies.add(host,
path,
name,
@ -700,6 +707,69 @@ Cookies.prototype = {
}
};
function getTypedURLs(registryKeyPath) {
// The list of typed URLs is a sort of annotation stored in the registry.
// The number of entries stored is not UI-configurable, but has changed
// between different Windows versions. We just keep reading up to the first
// non-existing entry to support different limits / states of the registry.
let typedURLs = new Map();
let typedURLKey = Cc["@mozilla.org/windows-registry-key;1"].
createInstance(Ci.nsIWindowsRegKey);
let typedURLTimeKey = Cc["@mozilla.org/windows-registry-key;1"].
createInstance(Ci.nsIWindowsRegKey);
let cTypes = new CtypesHelpers();
try {
typedURLKey.open(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
registryKeyPath + "\\TypedURLs",
Ci.nsIWindowsRegKey.ACCESS_READ);
try {
typedURLTimeKey.open(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
registryKeyPath + "\\TypedURLsTime",
Ci.nsIWindowsRegKey.ACCESS_READ);
} catch (ex) {
typedURLTimeKey = null;
}
let entryName;
for (let entry = 1; typedURLKey.hasValue((entryName = "url" + entry)); entry++) {
let url = typedURLKey.readStringValue(entryName);
let timeTyped = 0;
if (typedURLTimeKey && typedURLTimeKey.hasValue(entryName)) {
let urlTime = "";
try {
urlTime = typedURLTimeKey.readBinaryValue(entryName);
} catch (ex) {
Cu.reportError("Couldn't read url time for " + entryName);
}
if (urlTime.length == 8) {
let urlTimeHex = [];
for (let i = 0; i < 8; i++) {
let c = urlTime.charCodeAt(i).toString(16);
if (c.length == 1)
c = "0" + c;
urlTimeHex.unshift(c);
}
try {
let hi = parseInt(urlTimeHex.slice(0, 4).join(''), 16);
let lo = parseInt(urlTimeHex.slice(4, 8).join(''), 16);
timeTyped = cTypes.fileTimeToSecondsSinceEpoch(hi, lo);
// Callers expect PRTime, which is microseconds since epoch:
timeTyped *= 1000 * 1000;
} catch (ex) {}
}
}
typedURLs.set(url, timeTyped);
}
} catch (ex) {
Cu.reportError("Error reading typed URL history: " + ex);
} finally {
typedURLKey.close();
typedURLTimeKey.close();
cTypes.finalize();
}
return typedURLs;
}
// Migrator for form passwords on Windows 8 and higher.
function WindowsVaultFormPasswords () {
}
@ -850,4 +920,5 @@ var MSMigrationUtils = {
getWindowsVaultFormPasswordsMigrator() {
return new WindowsVaultFormPasswords();
},
getTypedURLs,
};

View File

@ -1,6 +1,7 @@
const EDGE_AVAILABLE_MIGRATIONS =
MigrationUtils.resourceTypes.COOKIES |
MigrationUtils.resourceTypes.BOOKMARKS |
MigrationUtils.resourceTypes.HISTORY |
MigrationUtils.resourceTypes.PASSWORDS;
add_task(function* () {