forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			360 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			360 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| const lazy = {};
 | |
| import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
 | |
| 
 | |
| ChromeUtils.defineESModuleGetters(lazy, {
 | |
|   BookmarkHTMLUtils: "resource://gre/modules/BookmarkHTMLUtils.sys.mjs",
 | |
|   BookmarkJSONUtils: "resource://gre/modules/BookmarkJSONUtils.sys.mjs",
 | |
|   LoginCSVImport: "resource://gre/modules/LoginCSVImport.sys.mjs",
 | |
|   MigrationWizardConstants:
 | |
|     "chrome://browser/content/migration/migration-wizard-constants.mjs",
 | |
| });
 | |
| 
 | |
| XPCOMUtils.defineLazyGetter(lazy, "gFluentStrings", function () {
 | |
|   return new Localization([
 | |
|     "branding/brand.ftl",
 | |
|     "browser/migrationWizard.ftl",
 | |
|   ]);
 | |
| });
 | |
| 
 | |
| /**
 | |
|  * Base class for a migration that involves reading a single file off of
 | |
|  * the disk that the user picks using a file picker. The file might be
 | |
|  * generated by another browser or some other application.
 | |
|  */
 | |
| export class FileMigratorBase {
 | |
|   /**
 | |
|    * This must be overridden to return a simple string identifier for the
 | |
|    * migrator, for example "password-csv". This key is what
 | |
|    * is used as an identifier when calling MigrationUtils.getFileMigrator.
 | |
|    *
 | |
|    * @type {string}
 | |
|    */
 | |
|   static get key() {
 | |
|     throw new Error("FileMigrator.key must be overridden.");
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This must be overridden to return a Fluent string ID mapping to the display
 | |
|    * name for this migrator. These strings should be defined in migrationWizard.ftl.
 | |
|    *
 | |
|    * @type {string}
 | |
|    */
 | |
|   static get displayNameL10nID() {
 | |
|     throw new Error("FileMigrator.displayNameL10nID must be overridden.");
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This getter should get overridden to return an icon url to represent the
 | |
|    * file to be imported from. By default, this will just use the default Favicon
 | |
|    * image.
 | |
|    *
 | |
|    * @type {string}
 | |
|    */
 | |
|   static get brandImage() {
 | |
|     return "chrome://global/skin/icons/defaultFavicon.svg";
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns true if the migrator is configured to be enabled.
 | |
|    *
 | |
|    * @type {boolean}
 | |
|    *   true if the migrator should be shown in the migration wizard.
 | |
|    */
 | |
|   get enabled() {
 | |
|     throw new Error("FileMigrator.enabled must be overridden.");
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This getter should be overridden to return a Fluent string ID for what
 | |
|    * the migration wizard header should be while the file migration is
 | |
|    * underway.
 | |
|    *
 | |
|    * @type {string}
 | |
|    */
 | |
|   get progressHeaderL10nID() {
 | |
|     throw new Error("FileMigrator.progressHeaderL10nID must be overridden.");
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This getter should be overridden to return a Fluent string ID for what
 | |
|    * the migration wizard header should be while the file migration is
 | |
|    * done.
 | |
|    *
 | |
|    * @type {string}
 | |
|    */
 | |
|   get successHeaderL10nID() {
 | |
|     throw new Error("FileMigrator.progressHeaderL10nID must be overridden.");
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @typedef {object} FilePickerConfiguration
 | |
|    * @property {string} title
 | |
|    *   The title that should be assigned to the native file picker window.
 | |
|    * @property {FilePickerConfigurationFilter[]} filters
 | |
|    *   One or more extension filters that should be applied to the native
 | |
|    *   file picker window to make selection easier.
 | |
|    */
 | |
| 
 | |
|   /**
 | |
|    * @typedef {object} FilePickerConfigurationFilter
 | |
|    * @property {string} title
 | |
|    *   The title for the filter. Example: "CSV Files"
 | |
|    * @property {string} extensionPattern
 | |
|    *   A matching pattern for the filter. Example: "*.csv"
 | |
|    */
 | |
| 
 | |
|   /**
 | |
|    * A subclass of FileMigratorBase will eventually open a native file picker
 | |
|    * for the user to select the file from their file system.
 | |
|    *
 | |
|    * Subclasses need to override this method in order to configure the
 | |
|    * native file picker.
 | |
|    *
 | |
|    * @returns {Promise<FilePickerConfiguration>}
 | |
|    */
 | |
|   async getFilePickerConfig() {
 | |
|     throw new Error("FileMigrator.getFilePickerConfig must be overridden.");
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns a list of one or more resource types that should appear to be
 | |
|    * in progress of migrating while the file migration occurs. Notably,
 | |
|    * this does not need to match the resource types that are returned by
 | |
|    * `FileMigratorBase.migrate`.
 | |
|    *
 | |
|    * @type {string[]}
 | |
|    *   An array of resource types from the
 | |
|    *   MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES set.
 | |
|    */
 | |
|   get displayedResourceTypes() {
 | |
|     throw new Error("FileMigrator.displayedResourceTypes must be overridden");
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Called to perform the file migration once the user makes a selection
 | |
|    * from the native file picker. This will not be called if the user
 | |
|    * chooses to cancel the native file picker.
 | |
|    *
 | |
|    * @param {string} filePath
 | |
|    *   The path that the user selected from the native file picker.
 | |
|    */
 | |
|   // eslint-disable-next-line no-unused-vars
 | |
|   async migrate(filePath) {
 | |
|     throw new Error("FileMigrator.migrate must be overridden.");
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * A file migrator for importing passwords from CSV or TSV files. CSV
 | |
|  * files are more common, so this is what we show as the file type for
 | |
|  * the display name, but this FileMigrator accepts both.
 | |
|  */
 | |
| export class PasswordFileMigrator extends FileMigratorBase {
 | |
|   static get key() {
 | |
|     return "file-password-csv";
 | |
|   }
 | |
| 
 | |
|   static get displayNameL10nID() {
 | |
|     return "migration-wizard-migrator-display-name-file-password-csv";
 | |
|   }
 | |
| 
 | |
|   static get brandImage() {
 | |
|     return "chrome://branding/content/document.ico";
 | |
|   }
 | |
| 
 | |
|   get enabled() {
 | |
|     return Services.prefs.getBoolPref(
 | |
|       "signon.management.page.fileImport.enabled",
 | |
|       false
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   get displayedResourceTypes() {
 | |
|     return [
 | |
|       lazy.MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES
 | |
|         .PASSWORDS_FROM_FILE,
 | |
|     ];
 | |
|   }
 | |
| 
 | |
|   get progressHeaderL10nID() {
 | |
|     return "migration-passwords-from-file-progress-header";
 | |
|   }
 | |
| 
 | |
|   get successHeaderL10nID() {
 | |
|     return "migration-passwords-from-file-success-header";
 | |
|   }
 | |
| 
 | |
|   async getFilePickerConfig() {
 | |
|     let [title, csvFilterTitle, tsvFilterTitle] =
 | |
|       await lazy.gFluentStrings.formatValues([
 | |
|         { id: "migration-passwords-from-file-picker-title" },
 | |
|         { id: "migration-passwords-from-file-csv-filter-title" },
 | |
|         { id: "migration-passwords-from-file-tsv-filter-title" },
 | |
|       ]);
 | |
| 
 | |
|     return {
 | |
|       title,
 | |
|       filters: [
 | |
|         {
 | |
|           title: csvFilterTitle,
 | |
|           extensionPattern: "*.csv",
 | |
|         },
 | |
|         {
 | |
|           title: tsvFilterTitle,
 | |
|           extensionPattern: "*.tsv",
 | |
|         },
 | |
|       ],
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   async migrate(filePath) {
 | |
|     try {
 | |
|       let summary = await lazy.LoginCSVImport.importFromCSV(filePath);
 | |
|       let newEntries = 0;
 | |
|       let updatedEntries = 0;
 | |
|       for (let entry of summary) {
 | |
|         if (entry.result == "added") {
 | |
|           newEntries++;
 | |
|         } else if (entry.result == "modified") {
 | |
|           updatedEntries++;
 | |
|         }
 | |
|       }
 | |
|       let [newMessage, updatedMessage] = await lazy.gFluentStrings.formatValues(
 | |
|         [
 | |
|           {
 | |
|             id: "migration-wizard-progress-success-new-passwords",
 | |
|             args: { newEntries },
 | |
|           },
 | |
|           {
 | |
|             id: "migration-wizard-progress-success-updated-passwords",
 | |
|             args: { updatedEntries },
 | |
|           },
 | |
|         ]
 | |
|       );
 | |
| 
 | |
|       Services.prefs.setBoolPref(
 | |
|         "browser.migrate.interactions.csvpasswords",
 | |
|         true
 | |
|       );
 | |
| 
 | |
|       return {
 | |
|         [lazy.MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES
 | |
|           .PASSWORDS_NEW]: newMessage,
 | |
|         [lazy.MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES
 | |
|           .PASSWORDS_UPDATED]: updatedMessage,
 | |
|       };
 | |
|     } catch (e) {
 | |
|       console.error(e);
 | |
| 
 | |
|       let errorMessage = await lazy.gFluentStrings.formatValue(
 | |
|         "migration-passwords-from-file-no-valid-data"
 | |
|       );
 | |
|       throw new Error(errorMessage);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * A file migrator for importing bookmarks from a HTML or JSON file.
 | |
|  *
 | |
|  * @class BookmarksFileMigrator
 | |
|  * @augments {FileMigratorBase}
 | |
|  */
 | |
| export class BookmarksFileMigrator extends FileMigratorBase {
 | |
|   static get key() {
 | |
|     return "file-bookmarks";
 | |
|   }
 | |
| 
 | |
|   static get displayNameL10nID() {
 | |
|     return "migration-wizard-migrator-display-name-file-bookmarks";
 | |
|   }
 | |
| 
 | |
|   static get brandImage() {
 | |
|     return "chrome://branding/content/document.ico";
 | |
|   }
 | |
| 
 | |
|   get enabled() {
 | |
|     return Services.prefs.getBoolPref(
 | |
|       "browser.migrate.bookmarks-file.enabled",
 | |
|       false
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   get displayedResourceTypes() {
 | |
|     return [
 | |
|       lazy.MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES
 | |
|         .BOOKMARKS_FROM_FILE,
 | |
|     ];
 | |
|   }
 | |
| 
 | |
|   get progressHeaderL10nID() {
 | |
|     return "migration-bookmarks-from-file-progress-header";
 | |
|   }
 | |
| 
 | |
|   get successHeaderL10nID() {
 | |
|     return "migration-bookmarks-from-file-success-header";
 | |
|   }
 | |
| 
 | |
|   async getFilePickerConfig() {
 | |
|     let [title, htmlFilterTitle, jsonFilterTitle] =
 | |
|       await lazy.gFluentStrings.formatValues([
 | |
|         { id: "migration-bookmarks-from-file-picker-title" },
 | |
|         { id: "migration-bookmarks-from-file-html-filter-title" },
 | |
|         { id: "migration-bookmarks-from-file-json-filter-title" },
 | |
|       ]);
 | |
| 
 | |
|     return {
 | |
|       title,
 | |
|       filters: [
 | |
|         {
 | |
|           title: htmlFilterTitle,
 | |
|           extensionPattern: "*.html",
 | |
|         },
 | |
|         {
 | |
|           title: jsonFilterTitle,
 | |
|           extensionPattern: "*.json",
 | |
|         },
 | |
|       ],
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   async migrate(filePath) {
 | |
|     try {
 | |
|       let pathCheck = filePath.toLowerCase();
 | |
|       let importedCount;
 | |
| 
 | |
|       if (pathCheck.endsWith("html")) {
 | |
|         importedCount = await lazy.BookmarkHTMLUtils.importFromFile(filePath);
 | |
|       } else if (pathCheck.endsWith("json") || pathCheck.endsWith("jsonlz4")) {
 | |
|         importedCount = await lazy.BookmarkJSONUtils.importFromFile(filePath);
 | |
|       }
 | |
| 
 | |
|       if (!importedCount) {
 | |
|         // The catch will cause us to show a default error message.
 | |
|         throw new Error();
 | |
|       }
 | |
| 
 | |
|       let importedMessage = await lazy.gFluentStrings.formatValue(
 | |
|         "migration-wizard-progress-success-new-bookmarks",
 | |
|         {
 | |
|           newEntries: importedCount,
 | |
|         }
 | |
|       );
 | |
|       return {
 | |
|         [lazy.MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES
 | |
|           .BOOKMARKS_FROM_FILE]: importedMessage,
 | |
|       };
 | |
|     } catch (e) {
 | |
|       console.error(e);
 | |
| 
 | |
|       let errorMessage = await lazy.gFluentStrings.formatValue(
 | |
|         "migration-bookmarks-from-file-no-valid-data"
 | |
|       );
 | |
|       throw new Error(errorMessage);
 | |
|     }
 | |
|   }
 | |
| }
 | 
