ProfileDataUpgrader.sys.mjs (45311B)
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 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; 6 7 const lazy = {}; 8 9 ChromeUtils.defineESModuleGetters(lazy, { 10 AddonManager: "resource://gre/modules/AddonManager.sys.mjs", 11 FormAutofillUtils: "resource://gre/modules/shared/FormAutofillUtils.sys.mjs", 12 FirefoxBridgeExtensionUtils: 13 "resource:///modules/FirefoxBridgeExtensionUtils.sys.mjs", 14 LoginHelper: "resource://gre/modules/LoginHelper.sys.mjs", 15 PlacesUIUtils: "moz-src:///browser/components/places/PlacesUIUtils.sys.mjs", 16 UsageReporting: "resource://gre/modules/UsageReporting.sys.mjs", 17 }); 18 19 export let ProfileDataUpgrader = { 20 _migrateXULStoreForDocument(fromURL, toURL) { 21 Array.from(Services.xulStore.getIDsEnumerator(fromURL)).forEach(id => { 22 Array.from(Services.xulStore.getAttributeEnumerator(fromURL, id)).forEach( 23 attr => { 24 let value = Services.xulStore.getValue(fromURL, id, attr); 25 Services.xulStore.setValue(toURL, id, attr, value); 26 } 27 ); 28 }); 29 }, 30 31 _migrateHashedKeysForXULStoreForDocument(docUrl) { 32 Array.from(Services.xulStore.getIDsEnumerator(docUrl)) 33 .filter(id => id.startsWith("place:")) 34 .forEach(id => { 35 Services.xulStore.removeValue(docUrl, id, "open"); 36 let hashedId = lazy.PlacesUIUtils.obfuscateUrlForXulStore(id); 37 Services.xulStore.setValue(docUrl, hashedId, "open", "true"); 38 }); 39 }, 40 41 /** 42 * This method transforms data in the profile directory so that it can be 43 * used in the current version of Firefox. It is organized similar to 44 * typical database version upgrades: we are invoked with the version of the 45 * profile data on disk (`existingDataVersion`) and the version we expect/need 46 * (`newVersion`), and execute any necessary migrations. 47 * 48 * In practice, most of the migrations move user choices from one preference 49 * to another, or ensure that other mechanical file moves (e.g. of document 50 * URLs like browser.xhtml). 51 * 52 * If you're adding a new migration, you will need to increment 53 * APP_DATA_VERSION in BrowserGlue.sys.mjs' _migrateUI. That version is not 54 * in this module so that we can avoid loading this module entirely in common 55 * cases (Firefox startups where a profile is not upgraded). 56 * 57 * Note that this is invoked very early on startup and should try to avoid 58 * doing very expensive things immediately unless absolutely necessary. Some 59 * of the migrations will therefore set a pref or otherwise flag that their 60 * component needs to do more work later, perhaps during idle tasks or 61 * similar, to avoid front-loading the component initialization into this 62 * early part of startup. Of course, some of these migrations (e.g. to ensure 63 * that browser windows remember their sizes if the URL to browser.xhtml has 64 * changed) _need_ to run very early, and that is OK. 65 * 66 * @param {integer} existingDataVersion 67 * The version of the data in the profile. 68 * @param {integer} newVersion 69 * The version that the application expects/needs. 70 */ 71 // eslint-disable-next-line complexity 72 upgrade(existingDataVersion, newVersion) { 73 const BROWSER_DOCURL = AppConstants.BROWSER_CHROME_URL; 74 75 let xulStore = Services.xulStore; 76 77 if (existingDataVersion < 90) { 78 this._migrateXULStoreForDocument( 79 "chrome://browser/content/places/historySidebar.xul", 80 "chrome://browser/content/places/historySidebar.xhtml" 81 ); 82 this._migrateXULStoreForDocument( 83 "chrome://browser/content/places/places.xul", 84 "chrome://browser/content/places/places.xhtml" 85 ); 86 this._migrateXULStoreForDocument( 87 "chrome://browser/content/places/bookmarksSidebar.xul", 88 "chrome://browser/content/places/bookmarksSidebar.xhtml" 89 ); 90 } 91 92 // Clear socks proxy values if they were shared from http, to prevent 93 // websocket breakage after bug 1577862 (see bug 969282). 94 if ( 95 existingDataVersion < 91 && 96 Services.prefs.getBoolPref("network.proxy.share_proxy_settings", false) && 97 Services.prefs.getIntPref("network.proxy.type", 0) == 1 98 ) { 99 let httpProxy = Services.prefs.getCharPref("network.proxy.http", ""); 100 let httpPort = Services.prefs.getIntPref("network.proxy.http_port", 0); 101 let socksProxy = Services.prefs.getCharPref("network.proxy.socks", ""); 102 let socksPort = Services.prefs.getIntPref("network.proxy.socks_port", 0); 103 if (httpProxy && httpProxy == socksProxy && httpPort == socksPort) { 104 Services.prefs.setCharPref( 105 "network.proxy.socks", 106 Services.prefs.getCharPref("network.proxy.backup.socks", "") 107 ); 108 Services.prefs.setIntPref( 109 "network.proxy.socks_port", 110 Services.prefs.getIntPref("network.proxy.backup.socks_port", 0) 111 ); 112 } 113 } 114 115 if (existingDataVersion < 92) { 116 // privacy.userContext.longPressBehavior pref was renamed and changed to a boolean 117 let longpress = Services.prefs.getIntPref( 118 "privacy.userContext.longPressBehavior", 119 0 120 ); 121 if (longpress == 1) { 122 Services.prefs.setBoolPref( 123 "privacy.userContext.newTabContainerOnLeftClick.enabled", 124 true 125 ); 126 } 127 } 128 129 if (existingDataVersion < 93) { 130 // The Gecko Profiler Addon is now an internal component. Remove the old 131 // addon, and enable the new UI. 132 133 function enableProfilerButton(wasAddonActive) { 134 // Enable the feature pref. This will add it to the customization palette, 135 // but not to the the navbar. 136 Services.prefs.setBoolPref( 137 "devtools.performance.popup.feature-flag", 138 true 139 ); 140 141 if (wasAddonActive) { 142 const { ProfilerMenuButton } = ChromeUtils.importESModule( 143 "resource://devtools/client/performance-new/popup/menu-button.sys.mjs" 144 ); 145 if (!ProfilerMenuButton.isInNavbar()) { 146 ProfilerMenuButton.addToNavbar(); 147 } 148 } 149 } 150 151 let addonPromise; 152 try { 153 addonPromise = lazy.AddonManager.getAddonByID( 154 "geckoprofiler@mozilla.com" 155 ); 156 } catch (error) { 157 console.error( 158 "Could not access the AddonManager to upgrade the profile. This is most " + 159 "likely because the upgrader is being run from an xpcshell test where " + 160 "the AddonManager is not initialized." 161 ); 162 } 163 Promise.resolve(addonPromise).then(addon => { 164 if (!addon) { 165 // Either the addon wasn't installed, or the call to getAddonByID failed. 166 return; 167 } 168 // Remove the old addon. 169 const wasAddonActive = addon.isActive; 170 addon 171 .uninstall() 172 .catch(console.error) 173 .then(() => enableProfilerButton(wasAddonActive)) 174 .catch(console.error); 175 }, console.error); 176 } 177 178 // Clear unused socks proxy backup values - see bug 1625773. 179 if (existingDataVersion < 94) { 180 let backup = Services.prefs.getCharPref("network.proxy.backup.socks", ""); 181 let backupPort = Services.prefs.getIntPref( 182 "network.proxy.backup.socks_port", 183 0 184 ); 185 let socksProxy = Services.prefs.getCharPref("network.proxy.socks", ""); 186 let socksPort = Services.prefs.getIntPref("network.proxy.socks_port", 0); 187 if (backup == socksProxy) { 188 Services.prefs.clearUserPref("network.proxy.backup.socks"); 189 } 190 if (backupPort == socksPort) { 191 Services.prefs.clearUserPref("network.proxy.backup.socks_port"); 192 } 193 } 194 195 if (existingDataVersion < 95) { 196 const oldPrefName = "media.autoplay.enabled.user-gestures-needed"; 197 const oldPrefValue = Services.prefs.getBoolPref(oldPrefName, true); 198 const newPrefValue = oldPrefValue ? 0 : 1; 199 Services.prefs.setIntPref("media.autoplay.blocking_policy", newPrefValue); 200 Services.prefs.clearUserPref(oldPrefName); 201 } 202 203 if (existingDataVersion < 96) { 204 const oldPrefName = "browser.urlbar.openViewOnFocus"; 205 const oldPrefValue = Services.prefs.getBoolPref(oldPrefName, true); 206 Services.prefs.setBoolPref( 207 "browser.urlbar.suggest.topsites", 208 oldPrefValue 209 ); 210 Services.prefs.clearUserPref(oldPrefName); 211 } 212 213 if (existingDataVersion < 97) { 214 let userCustomizedWheelMax = Services.prefs.prefHasUserValue( 215 "general.smoothScroll.mouseWheel.durationMaxMS" 216 ); 217 let userCustomizedWheelMin = Services.prefs.prefHasUserValue( 218 "general.smoothScroll.mouseWheel.durationMinMS" 219 ); 220 221 if (!userCustomizedWheelMin && !userCustomizedWheelMax) { 222 // If the user has an existing profile but hasn't customized the wheel 223 // animation duration, they will now get the new default values. This 224 // condition used to set a migrationPercent pref to 0, so that users 225 // upgrading an older profile would gradually have their wheel animation 226 // speed migrated to the new values. However, that "gradual migration" 227 // was phased out by FF 86, so we don't need to set that pref anymore. 228 } else if (userCustomizedWheelMin && !userCustomizedWheelMax) { 229 // If they customized just one of the two, save the old value for the 230 // other one as well, because the two values go hand-in-hand and we 231 // don't want to move just one to a new value and leave the other one 232 // at a customized value. In both of these cases, we leave the "migration 233 // complete" percentage at 100, because they have customized this and 234 // don't need any further migration. 235 Services.prefs.setIntPref( 236 "general.smoothScroll.mouseWheel.durationMaxMS", 237 400 238 ); 239 } else if (!userCustomizedWheelMin && userCustomizedWheelMax) { 240 // Same as above case, but for the other pref. 241 Services.prefs.setIntPref( 242 "general.smoothScroll.mouseWheel.durationMinMS", 243 200 244 ); 245 } else { 246 // The last remaining case is if they customized both values, in which 247 // case also don't need to do anything; the user's customized values 248 // will be retained and respected. 249 } 250 } 251 252 if (existingDataVersion < 98) { 253 Services.prefs.clearUserPref("browser.search.cohort"); 254 } 255 256 if (existingDataVersion < 99) { 257 Services.prefs.clearUserPref("security.tls.version.enable-deprecated"); 258 } 259 260 if (existingDataVersion < 102) { 261 // In Firefox 83, we moved to a dynamic button, so it needs to be removed 262 // from default placement. This is done early enough that it doesn't 263 // impact adding new managed bookmarks. 264 const { CustomizableUI } = ChromeUtils.importESModule( 265 "moz-src:///browser/components/customizableui/CustomizableUI.sys.mjs" 266 ); 267 CustomizableUI.removeWidgetFromArea("managed-bookmarks"); 268 } 269 270 // We have to rerun these because we had to use 102 on beta. 271 // They were 101 and 102 before. 272 if (existingDataVersion < 103) { 273 // Set a pref if the bookmarks toolbar was already visible, 274 // so we can keep it visible when navigating away from newtab 275 let bookmarksToolbarWasVisible = 276 Services.xulStore.getValue( 277 BROWSER_DOCURL, 278 "PersonalToolbar", 279 "collapsed" 280 ) == "false"; 281 if (bookmarksToolbarWasVisible) { 282 // Migrate the user to the "always visible" value. See firefox.js for 283 // the other possible states. 284 Services.prefs.setCharPref( 285 "browser.toolbars.bookmarks.visibility", 286 "always" 287 ); 288 } 289 Services.xulStore.removeValue( 290 BROWSER_DOCURL, 291 "PersonalToolbar", 292 "collapsed" 293 ); 294 295 Services.prefs.clearUserPref( 296 "browser.livebookmarks.migrationAttemptsLeft" 297 ); 298 } 299 300 // For existing profiles, continue putting bookmarks in the 301 // "other bookmarks" folder. 302 if (existingDataVersion < 104) { 303 Services.prefs.setCharPref( 304 "browser.bookmarks.defaultLocation", 305 "unfiled" 306 ); 307 } 308 309 // Renamed and flipped the logic of a pref to make its purpose more clear. 310 if (existingDataVersion < 105) { 311 const oldPrefName = "browser.urlbar.imeCompositionClosesPanel"; 312 const oldPrefValue = Services.prefs.getBoolPref(oldPrefName, true); 313 Services.prefs.setBoolPref( 314 "browser.urlbar.keepPanelOpenDuringImeComposition", 315 !oldPrefValue 316 ); 317 Services.prefs.clearUserPref(oldPrefName); 318 } 319 320 if (existingDataVersion < 107) { 321 // Migrate old http URIs for mailto handlers to their https equivalents. 322 // The handler service will do this. We need to wait with migrating 323 // until the handler service has started up, so just set a pref here. 324 const kPref = "browser.handlers.migrations"; 325 // We might have set up another migration further up. Create an array, 326 // and drop empty strings resulting from the `split`: 327 let migrations = Services.prefs 328 .getCharPref(kPref, "") 329 .split(",") 330 .filter(x => !!x); 331 migrations.push("secure-mail"); 332 Services.prefs.setCharPref(kPref, migrations.join(",")); 333 } 334 335 if (existingDataVersion < 108) { 336 // Migrate old ctrlTab pref to new ctrlTab pref 337 let defaultValue = false; 338 let oldPrefName = "browser.ctrlTab.recentlyUsedOrder"; 339 let oldPrefDefault = true; 340 // Use old pref value if the user used Ctrl+Tab before, elsewise use new default value 341 if (Services.prefs.getBoolPref("browser.engagement.ctrlTab.has-used")) { 342 let newPrefValue = Services.prefs.getBoolPref( 343 oldPrefName, 344 oldPrefDefault 345 ); 346 Services.prefs.setBoolPref( 347 "browser.ctrlTab.sortByRecentlyUsed", 348 newPrefValue 349 ); 350 } else { 351 Services.prefs.setBoolPref( 352 "browser.ctrlTab.sortByRecentlyUsed", 353 defaultValue 354 ); 355 } 356 } 357 358 if (existingDataVersion < 109) { 359 // Migrate old pref to new pref 360 if ( 361 Services.prefs.prefHasUserValue("signon.recipes.remoteRecipesEnabled") 362 ) { 363 // Fetch the previous value of signon.recipes.remoteRecipesEnabled and assign it to signon.recipes.remoteRecipes.enabled. 364 Services.prefs.setBoolPref( 365 "signon.recipes.remoteRecipes.enabled", 366 Services.prefs.getBoolPref( 367 "signon.recipes.remoteRecipesEnabled", 368 true 369 ) 370 ); 371 //Then clear user pref 372 Services.prefs.clearUserPref("signon.recipes.remoteRecipesEnabled"); 373 } 374 } 375 376 if (existingDataVersion < 120) { 377 // Migrate old titlebar bool pref to new int-based one. 378 const oldPref = "browser.tabs.drawInTitlebar"; 379 const newPref = "browser.tabs.inTitlebar"; 380 if (Services.prefs.prefHasUserValue(oldPref)) { 381 // We may have int prefs for builds between bug 1736518 and bug 1739539. 382 const oldPrefType = Services.prefs.getPrefType(oldPref); 383 if (oldPrefType == Services.prefs.PREF_BOOL) { 384 Services.prefs.setIntPref( 385 newPref, 386 Services.prefs.getBoolPref(oldPref) ? 1 : 0 387 ); 388 } else { 389 Services.prefs.setIntPref( 390 newPref, 391 Services.prefs.getIntPref(oldPref) 392 ); 393 } 394 Services.prefs.clearUserPref(oldPref); 395 } 396 } 397 398 if (existingDataVersion < 121) { 399 // Migrate stored uris and convert them to use hashed keys 400 this._migrateHashedKeysForXULStoreForDocument(BROWSER_DOCURL); 401 this._migrateHashedKeysForXULStoreForDocument( 402 "chrome://browser/content/places/bookmarksSidebar.xhtml" 403 ); 404 this._migrateHashedKeysForXULStoreForDocument( 405 "chrome://browser/content/places/historySidebar.xhtml" 406 ); 407 } 408 409 if (existingDataVersion < 122) { 410 // Migrate xdg-desktop-portal pref from old to new prefs. 411 try { 412 const oldPref = "widget.use-xdg-desktop-portal"; 413 if (Services.prefs.getBoolPref(oldPref)) { 414 Services.prefs.setIntPref( 415 "widget.use-xdg-desktop-portal.file-picker", 416 1 417 ); 418 Services.prefs.setIntPref( 419 "widget.use-xdg-desktop-portal.mime-handler", 420 1 421 ); 422 } 423 Services.prefs.clearUserPref(oldPref); 424 } catch (ex) {} 425 } 426 427 // Bug 1745248: Due to multiple backouts, do not use UI Version 123 428 // as this version is most likely set for the Nightly channel 429 430 if (existingDataVersion < 124) { 431 // Migrate "extensions.formautofill.available" and 432 // "extensions.formautofill.creditCards.available" from old to new prefs 433 const oldFormAutofillModule = "extensions.formautofill.available"; 434 const oldCreditCardsAvailable = 435 "extensions.formautofill.creditCards.available"; 436 const newCreditCardsAvailable = 437 "extensions.formautofill.creditCards.supported"; 438 const newAddressesAvailable = 439 "extensions.formautofill.addresses.supported"; 440 if (Services.prefs.prefHasUserValue(oldFormAutofillModule)) { 441 let moduleAvailability = Services.prefs.getCharPref( 442 oldFormAutofillModule 443 ); 444 if (moduleAvailability == "on") { 445 Services.prefs.setCharPref(newAddressesAvailable, moduleAvailability); 446 Services.prefs.setCharPref( 447 newCreditCardsAvailable, 448 Services.prefs.getBoolPref(oldCreditCardsAvailable) ? "on" : "off" 449 ); 450 } 451 452 if (moduleAvailability == "off") { 453 Services.prefs.setCharPref( 454 newCreditCardsAvailable, 455 moduleAvailability 456 ); 457 Services.prefs.setCharPref(newAddressesAvailable, moduleAvailability); 458 } 459 } 460 461 // after migrating, clear old prefs so we can remove them later. 462 Services.prefs.clearUserPref(oldFormAutofillModule); 463 Services.prefs.clearUserPref(oldCreditCardsAvailable); 464 } 465 466 if (existingDataVersion < 125) { 467 // Bug 1756243 - Clear PiP cached coordinates since we changed their 468 // coordinate space. 469 const PIP_PLAYER_URI = 470 "chrome://global/content/pictureinpicture/player.xhtml"; 471 try { 472 for (let value of ["left", "top", "width", "height"]) { 473 Services.xulStore.removeValue( 474 PIP_PLAYER_URI, 475 "picture-in-picture", 476 value 477 ); 478 } 479 } catch (ex) { 480 console.error("Failed to clear XULStore PiP values: ", ex); 481 } 482 } 483 484 function migrateXULAttributeToStyle(url, id, attr) { 485 try { 486 let value = Services.xulStore.getValue(url, id, attr); 487 if (value) { 488 Services.xulStore.setValue(url, id, "style", `${attr}: ${value}px;`); 489 } 490 } catch (ex) { 491 console.error(`Error migrating ${id}'s ${attr} value: `, ex); 492 } 493 } 494 495 // Bug 1792748 used version 129 with a buggy variant of the sidebar width 496 // migration. This version is already in use in the nightly channel, so it 497 // shouldn't be used. 498 499 // Bug 1793366: migrate sidebar persisted attribute from width to style. 500 if (existingDataVersion < 130) { 501 migrateXULAttributeToStyle(BROWSER_DOCURL, "sidebar-box", "width"); 502 } 503 504 // Migration 131 was moved to 133 to allow for an uplift. 505 506 if (existingDataVersion < 132) { 507 // These attributes are no longer persisted, thus remove them from xulstore. 508 for (let url of [ 509 "chrome://browser/content/places/bookmarkProperties.xhtml", 510 "chrome://browser/content/places/bookmarkProperties2.xhtml", 511 ]) { 512 for (let attr of ["width", "screenX", "screenY"]) { 513 xulStore.removeValue(url, "bookmarkproperties", attr); 514 } 515 } 516 } 517 518 if (existingDataVersion < 133) { 519 xulStore.removeValue(BROWSER_DOCURL, "urlbar-container", "width"); 520 } 521 522 // Migration 134 was removed because it was no longer necessary. 523 524 if (existingDataVersion < 135 && AppConstants.platform == "linux") { 525 // Avoid changing titlebar setting for users that used to had it off. 526 try { 527 if (!Services.prefs.prefHasUserValue("browser.tabs.inTitlebar")) { 528 let de = Services.appinfo.desktopEnvironment; 529 let oldDefault = de.includes("gnome") || de.includes("pantheon"); 530 if (!oldDefault) { 531 Services.prefs.setIntPref("browser.tabs.inTitlebar", 0); 532 } 533 } 534 } catch (e) { 535 console.error("Error migrating tabsInTitlebar setting", e); 536 } 537 } 538 539 if (existingDataVersion < 136) { 540 migrateXULAttributeToStyle( 541 "chrome://browser/content/places/places.xhtml", 542 "placesList", 543 "width" 544 ); 545 } 546 547 if (existingDataVersion < 137) { 548 // The default value for enabling smooth scrolls is now false if the 549 // user prefers reduced motion. If the value was previously set, do 550 // not reset it, but if it was not explicitly set preserve the old 551 // default value. 552 if ( 553 !Services.prefs.prefHasUserValue("general.smoothScroll") && 554 Services.appinfo.prefersReducedMotion 555 ) { 556 Services.prefs.setBoolPref("general.smoothScroll", true); 557 } 558 } 559 560 if (existingDataVersion < 138) { 561 // Bug 1757297: Change scheme of all existing 'https-only-load-insecure' 562 // permissions with https scheme to http scheme. 563 try { 564 Services.perms 565 .getAllByTypes(["https-only-load-insecure"]) 566 .filter(permission => permission.principal.schemeIs("https")) 567 .forEach(permission => { 568 const capability = permission.capability; 569 const uri = permission.principal.URI.mutate() 570 .setScheme("http") 571 .finalize(); 572 const principal = 573 Services.scriptSecurityManager.createContentPrincipal(uri, {}); 574 Services.perms.removePermission(permission); 575 Services.perms.addFromPrincipal( 576 principal, 577 "https-only-load-insecure", 578 capability 579 ); 580 }); 581 } catch (e) { 582 console.error("Error migrating https-only-load-insecure permission", e); 583 } 584 } 585 586 if (existingDataVersion < 139) { 587 // Reset the default permissions to ALLOW_ACTION to rollback issues for 588 // affected users, see Bug 1579517 589 // originInfo in the format [origin, type] 590 [ 591 ["https://www.mozilla.org", "uitour"], 592 ["https://support.mozilla.org", "uitour"], 593 ["about:home", "uitour"], 594 ["about:newtab", "uitour"], 595 ["https://addons.mozilla.org", "install"], 596 ["https://support.mozilla.org", "remote-troubleshooting"], 597 ["about:welcome", "autoplay-media"], 598 ].forEach(originInfo => { 599 // Reset permission on the condition that it is set to 600 // UNKNOWN_ACTION, we want to prevent resetting user 601 // manipulated permissions 602 if ( 603 Services.perms.UNKNOWN_ACTION == 604 Services.perms.testPermissionFromPrincipal( 605 Services.scriptSecurityManager.createContentPrincipalFromOrigin( 606 originInfo[0] 607 ), 608 originInfo[1] 609 ) 610 ) { 611 // Adding permissions which have default values does not create 612 // new permissions, but rather remove the UNKNOWN_ACTION permission 613 // overrides. User's not affected by Bug 1579517 will not be affected by this addition. 614 Services.perms.addFromPrincipal( 615 Services.scriptSecurityManager.createContentPrincipalFromOrigin( 616 originInfo[0] 617 ), 618 originInfo[1], 619 Services.perms.ALLOW_ACTION 620 ); 621 } 622 }); 623 } 624 625 if (existingDataVersion < 140) { 626 // Remove browser.fixup.alternate.enabled pref in Bug 1850902. 627 Services.prefs.clearUserPref("browser.fixup.alternate.enabled"); 628 } 629 630 if (existingDataVersion < 141) { 631 for (const filename of ["signons.sqlite", "signons.sqlite.corrupt"]) { 632 const filePath = PathUtils.join(PathUtils.profileDir, filename); 633 IOUtils.remove(filePath, { ignoreAbsent: true }).catch(console.error); 634 } 635 } 636 637 if (existingDataVersion < 142) { 638 // Bug 1860392 - Remove incorrectly persisted theming values from sidebar style. 639 try { 640 let value = xulStore.getValue(BROWSER_DOCURL, "sidebar-box", "style"); 641 if (value) { 642 // Remove custom properties. 643 value = value 644 .split(";") 645 .filter(v => !v.trim().startsWith("--")) 646 .join(";"); 647 xulStore.setValue(BROWSER_DOCURL, "sidebar-box", "style", value); 648 } 649 } catch (ex) { 650 console.error(ex); 651 } 652 } 653 654 if (existingDataVersion < 143) { 655 // Version 143 has been superseded by version 145 below. 656 } 657 658 if (existingDataVersion < 144) { 659 // TerminatorTelemetry was removed in bug 1879136. Before it was removed, 660 // the ShutdownDuration.json file would be written to disk at shutdown 661 // so that the next launch of the browser could read it in and send 662 // shutdown performance measurements. 663 // 664 // Unfortunately, this mechanism and its measurements were fairly 665 // unreliable, so they were removed. 666 for (const filename of [ 667 "ShutdownDuration.json", 668 "ShutdownDuration.json.tmp", 669 ]) { 670 const filePath = PathUtils.join(PathUtils.profileDir, filename); 671 IOUtils.remove(filePath, { ignoreAbsent: true }).catch(console.error); 672 } 673 } 674 675 if (existingDataVersion < 145) { 676 if (AppConstants.platform == "win") { 677 // In Firefox 122, we enabled the firefox and firefox-private protocols. 678 // We switched over to using firefox-bridge and firefox-private-bridge, 679 // but we want to clean up the use of the other protocols. 680 lazy.FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries( 681 lazy.FirefoxBridgeExtensionUtils.OLD_PUBLIC_PROTOCOL, 682 lazy.FirefoxBridgeExtensionUtils.OLD_PRIVATE_PROTOCOL 683 ); 684 685 // Clean up the old user prefs from FX 122 686 Services.prefs.clearUserPref( 687 "network.protocol-handler.external.firefox" 688 ); 689 Services.prefs.clearUserPref( 690 "network.protocol-handler.external.firefox-private" 691 ); 692 693 // In Firefox 126, we switched over to using native messaging so the 694 // protocols are no longer necessary even in firefox-bridge and 695 // firefox-private-bridge form 696 lazy.FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries( 697 lazy.FirefoxBridgeExtensionUtils.PUBLIC_PROTOCOL, 698 lazy.FirefoxBridgeExtensionUtils.PRIVATE_PROTOCOL 699 ); 700 Services.prefs.clearUserPref( 701 "network.protocol-handler.external.firefox-bridge" 702 ); 703 Services.prefs.clearUserPref( 704 "network.protocol-handler.external.firefox-private-bridge" 705 ); 706 Services.prefs.clearUserPref("browser.shell.customProtocolsRegistered"); 707 } 708 } 709 710 let hasRun146Migration = false; 711 if (existingDataVersion < 147) { 712 // Directly copy old os auth pref values prior to 147 to the new boolean 713 // pref for OS auth (UI migration 156). Previously, this migration version 714 // migrated the old OS auth pref values to an encrypted string pref. 715 const prevOsAuthForCc = !Services.prefs.getBoolPref( 716 "signon.management.page.os-auth.enabled", 717 false 718 ); 719 const newOSAuthNameForCc = 720 "extensions.formautofill.creditCards.os-auth.locked.enabled"; 721 Services.prefs.setBoolPref(newOSAuthNameForCc, prevOsAuthForCc); 722 Services.prefs.lockPref(newOSAuthNameForCc); 723 724 const prevOsAuthForPw = !Services.prefs.getBoolPref( 725 "extensions.formautofill.reauth.enabled", 726 false 727 ); 728 const newOSAuthNameForPw = 729 "signon.management.page.os-auth.locked.enabled"; 730 Services.prefs.setBoolPref(newOSAuthNameForPw, prevOsAuthForPw); 731 Services.prefs.lockPref(newOSAuthNameForPw); 732 733 hasRun146Migration = true; 734 Services.prefs.clearUserPref("extensions.formautofill.reauth.enabled"); 735 Services.prefs.clearUserPref("signon.management.page.os-auth.enabled"); 736 } 737 738 if (existingDataVersion < 148) { 739 // The Firefox Translations addon is now a built-in Firefox feature. 740 let addonPromise; 741 try { 742 addonPromise = lazy.AddonManager.getAddonByID( 743 "firefox-translations-addon@mozilla.org" 744 ); 745 } catch (error) { 746 // This always throws in xpcshell as the AddonManager is not initialized. 747 if (!Services.env.exists("XPCSHELL_TEST_PROFILE_DIR")) { 748 console.error( 749 "Could not access the AddonManager to upgrade the profile." 750 ); 751 } 752 } 753 addonPromise?.then(addon => addon?.uninstall()).catch(console.error); 754 } 755 756 if (existingDataVersion < 149) { 757 // remove permissions used by deleted nsContentManager 758 [ 759 "other", 760 "script", 761 "image", 762 "stylesheet", 763 "object", 764 "document", 765 "subdocument", 766 "refresh", 767 "xbl", 768 "ping", 769 "xmlhttprequest", 770 "objectsubrequest", 771 "dtd", 772 "font", 773 "websocket", 774 "csp_report", 775 "xslt", 776 "beacon", 777 "fetch", 778 "manifest", 779 "speculative", 780 ].forEach(type => { 781 Services.perms.removeByType(type); 782 }); 783 } 784 785 if (existingDataVersion < 150) { 786 Services.prefs.clearUserPref("toolkit.telemetry.pioneerId"); 787 } 788 789 if (existingDataVersion < 151) { 790 // Existing Firefox users should have the usage reporting upload 791 // preference "inherit" the general data reporting preference. 792 lazy.UsageReporting.adoptDataReportingPreference(); 793 } 794 795 if ( 796 existingDataVersion < 152 && 797 Services.prefs.getBoolPref("sidebar.revamp") && 798 !Services.prefs.getBoolPref("browser.ml.chat.enabled") 799 ) { 800 let tools = Services.prefs.getCharPref("sidebar.main.tools"); 801 if (tools?.includes("aichat")) { 802 let updatedTools = tools 803 .split(",") 804 .filter(t => t != "aichat") 805 .join(","); 806 Services.prefs.setCharPref("sidebar.main.tools", updatedTools); 807 } 808 } 809 810 if ( 811 existingDataVersion < 153 && 812 Services.prefs.getBoolPref("sidebar.revamp") && 813 !Services.prefs.prefHasUserValue("sidebar.main.tools") 814 ) { 815 // This pref will now be a user set branch but we want to preserve the previous 816 // default value for existing sidebar.revamp users who hadn't changed it. 817 Services.prefs.setCharPref( 818 "sidebar.main.tools", 819 "aichat,syncedtabs,history" 820 ); 821 } 822 823 if (existingDataVersion < 154) { 824 // Remove mibbit handler. 825 // The handler service will do this. We need to wait with migrating 826 // until the handler service has started up, so just set a pref here. 827 const kPref = "browser.handlers.migrations"; 828 // We might have set up another migration further up. Create an array, 829 // and drop empty strings resulting from the `split`: 830 let migrations = Services.prefs 831 .getCharPref(kPref, "") 832 .split(",") 833 .filter(x => !!x); 834 migrations.push("mibbit"); 835 Services.prefs.setCharPref(kPref, migrations.join(",")); 836 } 837 838 if (existingDataVersion < 155) { 839 // Remove outdated sidebar info from XULStore. 840 for (const attr of [ 841 "checked", 842 "positionend", 843 "sidebarcommand", 844 "style", 845 ]) { 846 Services.xulStore.removeValue(BROWSER_DOCURL, "sidebar-box", attr); 847 } 848 } 849 850 if (existingDataVersion < 156) { 851 const customBlockListEnabled = Services.prefs.getBoolPref( 852 "browser.contentblocking.customBlockList.preferences.ui.enabled", 853 false 854 ); 855 if (customBlockListEnabled) { 856 Services.prefs.clearUserPref( 857 "browser.contentblocking.customBlockList.preferences.ui.enabled" 858 ); 859 Services.prefs.clearUserPref("urlclassifier.trackingTable"); 860 } 861 } 862 863 if (existingDataVersion < 157) { 864 // We've changed the 147 migration to copy the old OS auth pref values of 865 // that version to the new locked boolean prefs instead, so no need to 866 // perform a migration if it's already been done. 867 if (!hasRun146Migration) { 868 // We're moving away from string encrypted prefs for OS Authentication and 869 // using locked boolean prefs instead. 870 // To determine the state of the old OS Auth value, manually read these prefs. 871 // This treats any non-empty-string value as "turned off", irrespective of 872 // whether it correctly decrypts to the correct value, because we cannot do 873 // the decryption if the primary password has not yet been provided. 874 const prevOsAuthForCc = !Services.prefs.getStringPref( 875 "extensions.formautofill.creditCards.reauth.optout", 876 "" 877 ); 878 const prevOsAuthForPw = !Services.prefs.getStringPref( 879 "signon.management.page.os-auth.optout", 880 "" 881 ); 882 883 lazy.LoginHelper.setOSAuthEnabled(prevOsAuthForPw); 884 lazy.FormAutofillUtils.setOSAuthEnabled(prevOsAuthForCc); 885 886 Services.prefs.clearUserPref( 887 "extensions.formautofill.creditCards.reauth.optout" 888 ); 889 Services.prefs.clearUserPref("signon.management.page.os-auth.optout"); 890 } 891 } 892 893 // Nightly users who have run the migration for 157 will have had OS auth 894 // set to true for everyone who has migrated and there's no way to retrieve 895 // the old OS auth pref value because it was cleared in the previous 896 // migration. So we force the pref to false. See bug 1974217. 897 if (AppConstants.NIGHTLY_BUILD && existingDataVersion === 158) { 898 lazy.LoginHelper.setOSAuthEnabled(false); 899 lazy.FormAutofillUtils.setOSAuthEnabled(false); 900 } 901 902 if (existingDataVersion < 159) { 903 // Bug 1979014 / bug 1980398 - autohide attribute becomes a real boolean attribute. 904 let menubarWasEnabled = 905 Services.xulStore.getValue( 906 BROWSER_DOCURL, 907 "toolbar-menubar", 908 "autohide" 909 ) == "false"; 910 if (menubarWasEnabled) { 911 Services.xulStore.setValue( 912 BROWSER_DOCURL, 913 "toolbar-menubar", 914 "autohide", 915 "-moz-missing\n" 916 ); 917 } 918 } 919 920 if (existingDataVersion < 160) { 921 // Force all logins to be re-encrypted to make use of more modern crypto. 922 // This pref is checked in the initialization of the LoginManagerStorage. 923 Services.prefs.setBoolPref("signon.reencryptionNeeded", true); 924 } 925 926 // Updating from 161 to 163 to trigger re-migrations of the Rusts store. 927 if (existingDataVersion < 163) { 928 // Force all logins to be re-migrated to the rust store. 929 Services.prefs.setBoolPref("signon.rustMirror.migrationNeeded", true); 930 } 931 932 // Update the migration version. 933 Services.prefs.setIntPref("browser.migration.version", newVersion); 934 }, 935 936 upgradeBB(isNewProfile) { 937 // Version 1: 13.0a3. Reset layout.css.prefers-color-scheme.content-override 938 // for tor-browser#41739. 939 // Version 2: 14.0a5: Reset the privacy tracking headers preferences since 940 // the UI is hidden. tor-browser#42777. 941 // Also, do not set 942 // dom.security.https_only_mode_send_http_background_request in 943 // the security level anymore (tor-browser#42149). 944 // Also, reset security.xfocsp.errorReporting.automatic since we 945 // hid its neterror checkbox. tor-browser#42653. 946 // Version 3: 14.0a7: Reset general.smoothScroll. tor-browser#42070. 947 // Version 4: 15.0a2: Drop ML components. tor-browser#44045. 948 // Version 5: 15.0a3: Disable LaterRun using prefs. tor-browser#42630. 949 // Version 6: 15.0a4: Reset browser colors. tor-browser#43850. 950 const MIGRATION_VERSION = 6; 951 const MIGRATION_PREF = "basebrowser.migration.version"; 952 953 if (isNewProfile) { 954 // Do not migrate fresh profiles 955 Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); 956 return; 957 } else if (isNewProfile === undefined) { 958 // If this happens, check if upstream updated their function and do not 959 // set this member anymore! 960 console.error("upgradeBB: isNewProfile is undefined."); 961 } 962 963 const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); 964 if (currentVersion < 1) { 965 Services.prefs.clearUserPref( 966 "layout.css.prefers-color-scheme.content-override" 967 ); 968 } 969 if (currentVersion < 2) { 970 for (const prefName of [ 971 "privacy.globalprivacycontrol.enabled", 972 "privacy.donottrackheader.enabled", 973 // Telemetry preference for if the user changed the value. 974 "privacy.globalprivacycontrol.was_ever_enabled", 975 // The next two preferences have no corresponding UI, but are related. 976 "privacy.globalprivacycontrol.functionality.enabled", 977 "privacy.globalprivacycontrol.pbmode.enabled", 978 "dom.security.https_only_mode_send_http_background_request", 979 "security.xfocsp.errorReporting.automatic", 980 ]) { 981 Services.prefs.clearUserPref(prefName); 982 } 983 } 984 if (currentVersion < 3) { 985 Services.prefs.clearUserPref("general.smoothScroll"); 986 } 987 if (currentVersion < 4) { 988 for (const prefName of [ 989 "browser.translations.enable", 990 "browser.ml.enable", 991 "browser.ml.chat.enabled", 992 "browser.ml.linkPreview.enabled", 993 "browser.tabs.groups.smart.enabled", 994 "browser.tabs.groups.smart.userEnabled", 995 "extensions.ml.enabled", 996 "pdfjs.enableAltText", 997 "pdfjs.enableAltTextForEnglish", 998 "pdfjs.enableGuessAltText", 999 "pdfjs.enableAltTextModelDownload", 1000 "browser.urlbar.quicksuggest.mlEnabled", 1001 "places.semanticHistory.featureGate", 1002 ]) { 1003 // Preferences are locked. Do not want user values to linger in the 1004 // user's profile and become active if these preferences become unlocked 1005 // in the future. 1006 Services.prefs.clearUserPref(prefName); 1007 } 1008 } 1009 if (currentVersion < 5) { 1010 for (const prefName of [ 1011 "browser.laterrun.bookkeeping.sessionCount", 1012 "browser.laterrun.bookkeeping.profileCreationTime", 1013 "browser.laterrun.bookkeeping.updateAppliedTime", 1014 ]) { 1015 Services.prefs.clearUserPref(prefName); 1016 } 1017 } 1018 if (currentVersion < 6) { 1019 // Clear the related preference that is no longer read by upstream's code. 1020 Services.prefs.clearUserPref("browser.display.use_system_colors"); 1021 if (Services.prefs.getBoolPref("privacy.resistFingerprinting", true)) { 1022 for (const prefName of [ 1023 // User has not switched off resist fingerprinting. We want to reset 1024 // any "0" (automatic, use system colours) and "2" (always use browser 1025 // colours) values. 1026 // The "0" value cannot be set by the user under RFP in 1027 // about:preferences. The "2" value can be set, but has a different 1028 // name and a warning about website detectability. tor-browser#43850. 1029 "browser.display.document_color_use", 1030 // Under RFP, the following colours are ignored. So we clear them. 1031 // NOTE: Only a subset of can be set via the colors.xhtml dialog in 1032 // about:preferences. 1033 "browser.anchor_color", 1034 "browser.anchor_color.dark", 1035 "browser.visited_color", 1036 "browser.visited_color.dark", 1037 "browser.display.foreground_color", 1038 "browser.display.foreground_color.dark", 1039 "browser.display.background_color", 1040 "browser.display.background_color.dark", 1041 "browser.active_color", 1042 "browser.active_color.dark", 1043 ]) { 1044 Services.prefs.clearUserPref(prefName); 1045 } 1046 } 1047 } 1048 Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); 1049 }, 1050 1051 async upgradeTB(isNewProfile) { 1052 // Version 1: Tor Browser 12.0. We use it to remove langpacks, after the 1053 // migration to packaged locales. 1054 // Version 2: Tor Browser 13.0/13.0a1: tor-browser#41845. Also, removed some 1055 // torbutton preferences that are not used anymore. 1056 // Version 3: Tor Browser 13.0.7/13.5a3: Remove blockchair 1057 // (tor-browser#42283). 1058 // Version 4: Tor Browser 14.0a4 (2024-09-02): Remove Twitter, Yahoo and 1059 // YouTube search engines (tor-browser#41835). 1060 // Version 5: Tor Browser 14.0a5: Clear user preference for CFR settings 1061 // since we hid the UI (tor-browser#43118). 1062 // Version 6: Tor Browser 14.5a3: Clear preference for TorSettings that is 1063 // no longer used (tor-browser#41921). 1064 // Drop unused TorConnect setting (tor-browser#43462). 1065 // Version 7: Tor Browser 14.5a6: Clear home page update url preference 1066 // (tor-browser#43567). 1067 // Version 8: Tor Browser 15.0a2: Remove legacy search addons 1068 // (tor-browser#43111). 1069 // Version 9: Tor Browser 15.0a3: Remove YEC 2024 preference. 1070 // (tor-browser#44180) 1071 const TBB_MIGRATION_VERSION = 9; 1072 const MIGRATION_PREF = "torbrowser.migration.version"; 1073 1074 // If we decide to force updating users to pass through any version 1075 // following 12.0, we can remove this check, and check only whether 1076 // MIGRATION_PREF has a user value, like Mozilla does. 1077 if (isNewProfile) { 1078 // Do not migrate fresh profiles 1079 Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION); 1080 return; 1081 } else if (isNewProfile === undefined) { 1082 // If this happens, check if upstream updated their function and do not 1083 // set this member anymore! 1084 console.error("upgradeTB: isNewProfile is undefined."); 1085 } 1086 1087 const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); 1088 const removeLangpacks = async () => { 1089 for (const addon of await AddonManager.getAddonsByTypes(["locale"])) { 1090 await addon.uninstall(); 1091 } 1092 }; 1093 if (currentVersion < 1) { 1094 try { 1095 await removeLangpacks(); 1096 } catch (err) { 1097 console.error("Could not remove langpacks", err); 1098 } 1099 } 1100 if (currentVersion < 2) { 1101 const prefToClear = [ 1102 // tor-browser#41845: We were forcing these value by check the value of 1103 // automatic PBM. We decided not to change 1104 "browser.cache.disk.enable", 1105 "places.history.enabled", 1106 "security.nocertdb", 1107 "permissions.memory_only", 1108 // Old torbutton preferences not used anymore. 1109 "extensions.torbutton.loglevel", 1110 "extensions.torbutton.logmethod", 1111 "extensions.torbutton.pref_fixup_version", 1112 "extensions.torbutton.resize_new_windows", 1113 "extensions.torbutton.startup", 1114 "extensions.torlauncher.prompt_for_locale", 1115 "extensions.torlauncher.loglevel", 1116 "extensions.torlauncher.logmethod", 1117 "extensions.torlauncher.torrc_fixup_version", 1118 ]; 1119 for (const pref of prefToClear) { 1120 if (Services.prefs.prefHasUserValue(pref)) { 1121 Services.prefs.clearUserPref(pref); 1122 } 1123 } 1124 } 1125 const dropAddons = async list => { 1126 for (const id of list) { 1127 try { 1128 const engine = await lazy.AddonManager.getAddonByID(id); 1129 await engine?.uninstall(); 1130 } catch {} 1131 } 1132 }; 1133 if (currentVersion < 3) { 1134 await dropAddons([ 1135 "blockchair@search.mozilla.org", 1136 "blockchair-onion@search.mozilla.org", 1137 ]); 1138 } 1139 if (currentVersion < 4) { 1140 await dropAddons([ 1141 "twitter@search.mozilla.org", 1142 "yahoo@search.mozilla.org", 1143 "youtube@search.mozilla.org", 1144 ]); 1145 } 1146 if (currentVersion < 5) { 1147 for (const pref of [ 1148 "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons", 1149 "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features", 1150 ]) { 1151 Services.prefs.clearUserPref(pref); 1152 } 1153 } 1154 if (currentVersion < 6) { 1155 Services.prefs.clearUserPref("torbrowser.settings.enabled"); 1156 Services.prefs.clearUserPref("torbrowser.bootstrap.allow_internet_test"); 1157 } 1158 if (currentVersion < 7) { 1159 Services.prefs.clearUserPref("torbrowser.post_update.url"); 1160 } 1161 if (currentVersion < 8) { 1162 await dropAddons([ 1163 "ddg@search.mozilla.org", 1164 "ddg-onion@search.mozilla.org", 1165 "google@search.mozilla.org", 1166 "startpage@search.mozilla.org", 1167 "startpage-onion@search.mozilla.org", 1168 "wikipedia@search.mozilla.org", 1169 ]); 1170 } 1171 if (currentVersion < 9) { 1172 Services.prefs.clearUserPref("torbrowser.homepage.yec2024.message"); 1173 } 1174 1175 Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION); 1176 }, 1177 };