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"use strict"; 6 7var EXPORTED_SYMBOLS = ["FormAutofill"]; 8 9const { XPCOMUtils } = ChromeUtils.import( 10 "resource://gre/modules/XPCOMUtils.jsm" 11); 12const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); 13 14XPCOMUtils.defineLazyModuleGetters(this, { 15 Region: "resource://gre/modules/Region.jsm", 16}); 17 18const ADDRESSES_FIRST_TIME_USE_PREF = "extensions.formautofill.firstTimeUse"; 19const AUTOFILL_ADDRESSES_AVAILABLE_PREF = 20 "extensions.formautofill.addresses.supported"; 21// This pref should be refactored after the migration of the old bool pref 22const AUTOFILL_CREDITCARDS_AVAILABLE_PREF = 23 "extensions.formautofill.creditCards.supported"; 24const BROWSER_SEARCH_REGION_PREF = "browser.search.region"; 25const CREDITCARDS_USED_STATUS_PREF = "extensions.formautofill.creditCards.used"; 26const CREDITCARDS_AUTOFILL_SUPPORTED_COUNTRIES_PREF = 27 "extensions.formautofill.creditCards.supportedCountries"; 28const ENABLED_AUTOFILL_ADDRESSES_PREF = 29 "extensions.formautofill.addresses.enabled"; 30const ENABLED_AUTOFILL_ADDRESSES_CAPTURE_PREF = 31 "extensions.formautofill.addresses.capture.enabled"; 32const ENABLED_AUTOFILL_ADDRESSES_SUPPORTED_COUNTRIES_PREF = 33 "extensions.formautofill.addresses.supportedCountries"; 34const ENABLED_AUTOFILL_CREDITCARDS_PREF = 35 "extensions.formautofill.creditCards.enabled"; 36const ENABLED_AUTOFILL_CREDITCARDS_REAUTH_PREF = 37 "extensions.formautofill.reauth.enabled"; 38const AUTOFILL_CREDITCARDS_HIDE_UI_PREF = 39 "extensions.formautofill.creditCards.hideui"; 40const FORM_AUTOFILL_SUPPORT_RTL_PREF = "extensions.formautofill.supportRTL"; 41 42XPCOMUtils.defineLazyPreferenceGetter( 43 this, 44 "logLevel", 45 "extensions.formautofill.loglevel", 46 "Warn" 47); 48 49// A logging helper for debug logging to avoid creating Console objects 50// or triggering expensive JS -> C++ calls when debug logging is not 51// enabled. 52// 53// Console objects, even natively-implemented ones, can consume a lot of 54// memory, and since this code may run in every content process, that 55// memory can add up quickly. And, even when debug-level messages are 56// being ignored, console.debug() calls can be expensive. 57// 58// This helper avoids both of those problems by never touching the 59// console object unless debug logging is enabled. 60function debug() { 61 if (logLevel.toLowerCase() == "debug") { 62 this.log.debug(...arguments); 63 } 64} 65 66var FormAutofill = { 67 ENABLED_AUTOFILL_ADDRESSES_PREF, 68 ENABLED_AUTOFILL_ADDRESSES_CAPTURE_PREF, 69 ENABLED_AUTOFILL_CREDITCARDS_PREF, 70 ENABLED_AUTOFILL_CREDITCARDS_REAUTH_PREF, 71 ADDRESSES_FIRST_TIME_USE_PREF, 72 CREDITCARDS_USED_STATUS_PREF, 73 74 get DEFAULT_REGION() { 75 return Region.home || "US"; 76 }, 77 /** 78 * Determines if an autofill feature should be enabled based on the "available" 79 * and "supportedCountries" parameters. 80 * 81 * @param {string} available Available can be one of the following: "on", "detect", "off". 82 * "on" forces the particular Form Autofill feature on, while "detect" utilizes the supported countries 83 * to see if the feature should be available. 84 * @param {string[]} supportedCountries 85 * @returns {boolean} `true` if autofill feature is supported in the current browser search region 86 */ 87 _isSupportedRegion(available, supportedCountries) { 88 if (available == "on") { 89 return true; 90 } else if (available == "detect") { 91 if (!FormAutofill.supportRTL && Services.locale.isAppLocaleRTL) { 92 return false; 93 } 94 // TODO: Bug 1747284. Use Region.home instead of reading "browser.serach.region" 95 // by default. However, Region.home doesn't observe preference change at this point, 96 // we should also fix that issue. 97 let region = Services.prefs.getCharPref( 98 BROWSER_SEARCH_REGION_PREF, 99 this.DEFAULT_REGION 100 ); 101 return supportedCountries.includes(region); 102 } 103 return false; 104 }, 105 isAutofillAddressesAvailableInCountry(country) { 106 return FormAutofill._addressAutofillSupportedCountries.includes(country); 107 }, 108 get isAutofillEnabled() { 109 return this.isAutofillAddressesEnabled || this.isAutofillCreditCardsEnabled; 110 }, 111 /** 112 * Determines if the credit card autofill feature is available to use in the browser. 113 * If the feature is not available, then there are no user facing ways to enable it. 114 * @returns {boolean} `true` if credit card autofill is available 115 */ 116 get isAutofillCreditCardsAvailable() { 117 return this._isSupportedRegion( 118 FormAutofill._isAutofillCreditCardsAvailable, 119 FormAutofill._creditCardAutofillSupportedCountries 120 ); 121 }, 122 /** 123 * Determines if the address autofill feature is available to use in the browser. 124 * If the feature is not available, then there are no user facing ways to enable it. 125 * @returns {boolean} `true` if address autofill is available 126 */ 127 get isAutofillAddressesAvailable() { 128 return this._isSupportedRegion( 129 FormAutofill._isAutofillAddressesAvailable, 130 FormAutofill._addressAutofillSupportedCountries 131 ); 132 }, 133 /** 134 * Determines if the user has enabled or disabled credit card autofill. 135 * @returns {boolean} `true` if credit card autofill is enabled 136 */ 137 get isAutofillCreditCardsEnabled() { 138 return ( 139 this.isAutofillCreditCardsAvailable && 140 FormAutofill._isAutofillCreditCardsEnabled 141 ); 142 }, 143 /** 144 * Determines if the user has enabled or disabled address autofill. 145 * @returns {boolean} `true` if address autofill is enabled 146 */ 147 get isAutofillAddressesEnabled() { 148 return ( 149 this.isAutofillAddressesAvailable && 150 FormAutofill._isAutofillAddressesEnabled 151 ); 152 }, 153 154 defineLazyLogGetter(scope, logPrefix) { 155 scope.debug = debug; 156 157 XPCOMUtils.defineLazyGetter(scope, "log", () => { 158 let ConsoleAPI = ChromeUtils.import( 159 "resource://gre/modules/Console.jsm", 160 {} 161 ).ConsoleAPI; 162 return new ConsoleAPI({ 163 maxLogLevelPref: "extensions.formautofill.loglevel", 164 prefix: logPrefix, 165 }); 166 }); 167 }, 168}; 169 170XPCOMUtils.defineLazyPreferenceGetter( 171 FormAutofill, 172 "_isAutofillAddressesAvailable", 173 AUTOFILL_ADDRESSES_AVAILABLE_PREF 174); 175XPCOMUtils.defineLazyPreferenceGetter( 176 FormAutofill, 177 "_isAutofillAddressesEnabled", 178 ENABLED_AUTOFILL_ADDRESSES_PREF 179); 180XPCOMUtils.defineLazyPreferenceGetter( 181 FormAutofill, 182 "isAutofillAddressesCaptureEnabled", 183 ENABLED_AUTOFILL_ADDRESSES_CAPTURE_PREF 184); 185XPCOMUtils.defineLazyPreferenceGetter( 186 FormAutofill, 187 "_isAutofillCreditCardsAvailable", 188 AUTOFILL_CREDITCARDS_AVAILABLE_PREF 189); 190XPCOMUtils.defineLazyPreferenceGetter( 191 FormAutofill, 192 "_isAutofillCreditCardsEnabled", 193 ENABLED_AUTOFILL_CREDITCARDS_PREF 194); 195XPCOMUtils.defineLazyPreferenceGetter( 196 FormAutofill, 197 "isAutofillCreditCardsHideUI", 198 AUTOFILL_CREDITCARDS_HIDE_UI_PREF 199); 200XPCOMUtils.defineLazyPreferenceGetter( 201 FormAutofill, 202 "isAutofillAddressesFirstTimeUse", 203 ADDRESSES_FIRST_TIME_USE_PREF 204); 205XPCOMUtils.defineLazyPreferenceGetter( 206 FormAutofill, 207 "AutofillCreditCardsUsedStatus", 208 CREDITCARDS_USED_STATUS_PREF 209); 210XPCOMUtils.defineLazyPreferenceGetter( 211 FormAutofill, 212 "_addressAutofillSupportedCountries", 213 ENABLED_AUTOFILL_ADDRESSES_SUPPORTED_COUNTRIES_PREF, 214 null, 215 val => val.split(",") 216); 217XPCOMUtils.defineLazyPreferenceGetter( 218 FormAutofill, 219 "_creditCardAutofillSupportedCountries", 220 CREDITCARDS_AUTOFILL_SUPPORTED_COUNTRIES_PREF, 221 null, 222 null, 223 val => val.split(",") 224); 225XPCOMUtils.defineLazyPreferenceGetter( 226 FormAutofill, 227 "supportRTL", 228 FORM_AUTOFILL_SUPPORT_RTL_PREF 229); 230 231// XXX: This should be invalidated on intl:app-locales-changed. 232XPCOMUtils.defineLazyGetter(FormAutofill, "countries", () => { 233 let availableRegionCodes = Services.intl.getAvailableLocaleDisplayNames( 234 "region" 235 ); 236 let displayNames = Services.intl.getRegionDisplayNames( 237 undefined, 238 availableRegionCodes 239 ); 240 let result = new Map(); 241 for (let i = 0; i < availableRegionCodes.length; i++) { 242 result.set(availableRegionCodes[i].toUpperCase(), displayNames[i]); 243 } 244 return result; 245}); 246