AddonsBackupResource.sys.mjs (5529B)
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 https://mozilla.org/MPL/2.0/. */ 4 5 import { BackupResource } from "resource:///modules/backup/BackupResource.sys.mjs"; 6 7 /** 8 * Backup for addons and extensions files and data. 9 */ 10 export class AddonsBackupResource extends BackupResource { 11 static get key() { 12 return "addons"; 13 } 14 15 static get requiresEncryption() { 16 return false; 17 } 18 19 async backup( 20 stagingPath, 21 profilePath = PathUtils.profileDir, 22 _isEncrypting = false 23 ) { 24 // Files and directories to backup. 25 let toCopy = [ 26 "extensions.json", 27 "extension-settings.json", 28 "extension-preferences.json", 29 "addonStartup.json.lz4", 30 "browser-extension-data", 31 "extension-store-permissions", 32 ]; 33 await BackupResource.copyFiles(profilePath, stagingPath, toCopy); 34 35 // Backup only the XPIs in the extensions directory. 36 let xpiFiles = []; 37 let extensionsXPIDirectoryPath = PathUtils.join(profilePath, "extensions"); 38 let xpiDirectoryChildren = await IOUtils.getChildren( 39 extensionsXPIDirectoryPath, 40 { 41 ignoreAbsent: true, 42 } 43 ); 44 for (const childFilePath of xpiDirectoryChildren) { 45 if (childFilePath.endsWith(".xpi")) { 46 let childFileName = PathUtils.filename(childFilePath); 47 xpiFiles.push(childFileName); 48 } 49 } 50 // Create the extensions directory in the staging directory. 51 let stagingExtensionsXPIDirectoryPath = PathUtils.join( 52 stagingPath, 53 "extensions" 54 ); 55 await IOUtils.makeDirectory(stagingExtensionsXPIDirectoryPath); 56 // Copy all found XPIs to the staging directory. 57 await BackupResource.copyFiles( 58 extensionsXPIDirectoryPath, 59 stagingExtensionsXPIDirectoryPath, 60 xpiFiles 61 ); 62 63 // Copy storage sync database. 64 let databases = ["storage-sync-v2.sqlite"]; 65 await BackupResource.copySqliteDatabases( 66 profilePath, 67 stagingPath, 68 databases 69 ); 70 71 return null; 72 } 73 74 async recover(_manifestEntry, recoveryPath, destProfilePath) { 75 const files = [ 76 "extensions.json", 77 "extension-settings.json", 78 "extension-preferences.json", 79 "addonStartup.json.lz4", 80 "browser-extension-data", 81 "extension-store-permissions", 82 "extensions", 83 "storage-sync-v2.sqlite", 84 ]; 85 await BackupResource.copyFiles(recoveryPath, destProfilePath, files); 86 87 return null; 88 } 89 90 async measure(profilePath = PathUtils.profileDir) { 91 // Report the total size of the extension json files. 92 const jsonFiles = [ 93 "extensions.json", 94 "extension-settings.json", 95 "extension-preferences.json", 96 "addonStartup.json.lz4", 97 ]; 98 let extensionsJsonSize = 0; 99 for (const filePath of jsonFiles) { 100 let resourcePath = PathUtils.join(profilePath, filePath); 101 let resourceSize = await BackupResource.getFileSize(resourcePath); 102 if (Number.isInteger(resourceSize)) { 103 extensionsJsonSize += resourceSize; 104 } 105 } 106 Glean.browserBackup.extensionsJsonSize.set(extensionsJsonSize); 107 108 // Report the size of permissions store data, if present. 109 let extensionStorePermissionsDataPath = PathUtils.join( 110 profilePath, 111 "extension-store-permissions", 112 "data.safe.bin" 113 ); 114 let extensionStorePermissionsDataSize = await BackupResource.getFileSize( 115 extensionStorePermissionsDataPath 116 ); 117 if (Number.isInteger(extensionStorePermissionsDataSize)) { 118 Glean.browserBackup.extensionStorePermissionsDataSize.set( 119 extensionStorePermissionsDataSize 120 ); 121 } 122 123 // Report the size of extensions storage sync database. 124 let storageSyncPath = PathUtils.join(profilePath, "storage-sync-v2.sqlite"); 125 let storageSyncSize = await BackupResource.getFileSize(storageSyncPath); 126 Glean.browserBackup.storageSyncSize.set(storageSyncSize); 127 128 // Report the total size of XPI files in the extensions directory. 129 let extensionsXPIDirectoryPath = PathUtils.join(profilePath, "extensions"); 130 let extensionsXPIDirectorySize = await BackupResource.getDirectorySize( 131 extensionsXPIDirectoryPath, 132 { 133 shouldExclude: (filePath, fileType) => 134 fileType !== "regular" || !filePath.endsWith(".xpi"), 135 } 136 ); 137 Glean.browserBackup.extensionsXpiDirectorySize.set( 138 extensionsXPIDirectorySize 139 ); 140 141 // Report the total size of the browser extension data. 142 let browserExtensionDataPath = PathUtils.join( 143 profilePath, 144 "browser-extension-data" 145 ); 146 let browserExtensionDataSize = await BackupResource.getDirectorySize( 147 browserExtensionDataPath 148 ); 149 Glean.browserBackup.browserExtensionDataSize.set(browserExtensionDataSize); 150 151 // Report the size of all moz-extension IndexedDB databases. 152 let defaultStoragePath = PathUtils.join(profilePath, "storage", "default"); 153 let extensionsStorageSize = await BackupResource.getDirectorySize( 154 defaultStoragePath, 155 { 156 shouldExclude: (filePath, _fileType, parentPath) => { 157 if ( 158 parentPath == defaultStoragePath && 159 !PathUtils.filename(filePath).startsWith("moz-extension") 160 ) { 161 return true; 162 } 163 return false; 164 }, 165 } 166 ); 167 if (Number.isInteger(extensionsStorageSize)) { 168 Glean.browserBackup.extensionsStorageSize.set(extensionsStorageSize); 169 } 170 } 171 }