summaryrefslogtreecommitdiffstats
path: root/toolkit/components/formautofill/android
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/formautofill/android')
-rw-r--r--toolkit/components/formautofill/android/FormAutofillPrompter.jsm75
-rw-r--r--toolkit/components/formautofill/android/FormAutofillStorage.jsm277
2 files changed, 352 insertions, 0 deletions
diff --git a/toolkit/components/formautofill/android/FormAutofillPrompter.jsm b/toolkit/components/formautofill/android/FormAutofillPrompter.jsm
new file mode 100644
index 0000000000..f869ad851e
--- /dev/null
+++ b/toolkit/components/formautofill/android/FormAutofillPrompter.jsm
@@ -0,0 +1,75 @@
+/* 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/. */
+
+/*
+ * Implements doorhanger singleton that wraps up the PopupNotifications and handles
+ * the doorhager UI for formautofill related features.
+ */
+
+"use strict";
+
+var EXPORTED_SYMBOLS = ["FormAutofillPrompter"];
+
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ GeckoViewPrompter: "resource://gre/modules/GeckoViewPrompter.sys.mjs",
+});
+
+XPCOMUtils.defineLazyModuleGetters(lazy, {
+ CreditCard: "resource://gre/modules/GeckoViewAutocomplete.jsm",
+ GeckoViewAutocomplete: "resource://gre/modules/GeckoViewAutocomplete.jsm",
+});
+
+// Sync with Autocomplete.SaveOption.Hint in Autocomplete.java
+const CreditCardStorageHint = {
+ NONE: 0,
+ GENERATED: 1 << 0,
+ LOW_CONFIDENCE: 1 << 1,
+};
+
+let FormAutofillPrompter = {
+ _createMessage(creditCards) {
+ let hint = CreditCardStorageHint.NONE;
+ return {
+ // Sync with PromptController
+ type: "Autocomplete:Save:CreditCard",
+ hint,
+ creditCards,
+ };
+ },
+
+ async promptToSaveAddress(browser, type, description) {
+ throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
+ },
+
+ async promptToSaveCreditCard(browser, creditCard, storage) {
+ const prompt = new lazy.GeckoViewPrompter(browser.ownerGlobal);
+
+ let newCreditCard;
+ if (creditCard.guid) {
+ let originalCCData = await storage.creditCards.get(creditCard.guid);
+ newCreditCard = { ...originalCCData, ...creditCard.record };
+ } else {
+ newCreditCard = creditCard.record;
+ }
+
+ prompt.asyncShowPrompt(
+ this._createMessage([lazy.CreditCard.fromGecko(newCreditCard)]),
+ result => {
+ const selectedCreditCard = result?.selection?.value;
+
+ if (!selectedCreditCard) {
+ return;
+ }
+
+ lazy.GeckoViewAutocomplete.onCreditCardSave(selectedCreditCard);
+ }
+ );
+ },
+};
diff --git a/toolkit/components/formautofill/android/FormAutofillStorage.jsm b/toolkit/components/formautofill/android/FormAutofillStorage.jsm
new file mode 100644
index 0000000000..794b8ecdbd
--- /dev/null
+++ b/toolkit/components/formautofill/android/FormAutofillStorage.jsm
@@ -0,0 +1,277 @@
+/* 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/. */
+
+/*
+ * Implements an interface of the storage of Form Autofill for GeckoView.
+ */
+
+"use strict";
+
+// We expose a singleton from this module. Some tests may import the
+// constructor via a backstage pass.
+const EXPORTED_SYMBOLS = ["formAutofillStorage", "FormAutofillStorage"];
+
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+const {
+ FormAutofillStorageBase,
+ CreditCardsBase,
+ AddressesBase,
+} = ChromeUtils.import("resource://autofill/FormAutofillStorageBase.jsm");
+const { JSONFile } = ChromeUtils.importESModule(
+ "resource://gre/modules/JSONFile.sys.mjs"
+);
+
+const lazy = {};
+
+XPCOMUtils.defineLazyModuleGetters(lazy, {
+ Address: "resource://gre/modules/GeckoViewAutocomplete.jsm",
+ CreditCard: "resource://gre/modules/GeckoViewAutocomplete.jsm",
+ GeckoViewAutocomplete: "resource://gre/modules/GeckoViewAutocomplete.jsm",
+});
+
+class GeckoViewStorage extends JSONFile {
+ constructor() {
+ super({ path: null, sanitizedBasename: "GeckoViewStorage" });
+ }
+
+ async updateCreditCards() {
+ const creditCards = await lazy.GeckoViewAutocomplete.fetchCreditCards().then(
+ results => results?.map(r => lazy.CreditCard.parse(r).toGecko()) ?? [],
+ _ => []
+ );
+ super.data.creditCards = creditCards;
+ }
+
+ async updateAddresses() {
+ const addresses = await lazy.GeckoViewAutocomplete.fetchAddresses().then(
+ results => results?.map(r => lazy.Address.parse(r).toGecko()) ?? [],
+ _ => []
+ );
+ super.data.addresses = addresses;
+ }
+
+ async load() {
+ super.data = { creditCards: {}, addresses: {} };
+ await this.updateCreditCards();
+ await this.updateAddresses();
+ }
+
+ ensureDataReady() {
+ if (this.dataReady) {
+ return;
+ }
+ throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
+ }
+
+ async _save() {
+ throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
+ }
+}
+
+class Addresses extends AddressesBase {
+ // Override AutofillRecords methods.
+
+ _initialize() {
+ this._initializePromise = Promise.resolve();
+ }
+
+ async _saveRecord(record, { sourceSync = false } = {}) {
+ lazy.GeckoViewAutocomplete.onAddressSave(lazy.Address.fromGecko(record));
+ }
+
+ /**
+ * Returns the record with the specified GUID.
+ *
+ * @param {string} guid
+ * Indicates which record to retrieve.
+ * @param {object} options
+ * @param {boolean} [options.rawData = false]
+ * Returns a raw record without modifications and the computed fields
+ * (this includes private fields)
+ * @returns {Promise<object>}
+ * A clone of the record.
+ */
+ async get(guid, { rawData = false } = {}) {
+ await this._store.updateAddresses();
+ return super.get(guid, { rawData });
+ }
+
+ /**
+ * Returns all records.
+ *
+ * @param {object} options
+ * @param {boolean} [options.rawData = false]
+ * Returns raw records without modifications and the computed fields.
+ * @param {boolean} [options.includeDeleted = false]
+ * Also return any tombstone records.
+ * @returns {Promise<Array.<object>>}
+ * An array containing clones of all records.
+ */
+ async getAll({ rawData = false, includeDeleted = false } = {}) {
+ await this._store.updateAddresses();
+ return super.getAll({ rawData, includeDeleted });
+ }
+
+ /**
+ * Return all saved field names in the collection.
+ *
+ * @returns {Set} Set containing saved field names.
+ */
+ async getSavedFieldNames() {
+ await this._store.updateAddresses();
+ return super.getSavedFieldNames();
+ }
+
+ async reconcile(remoteRecord) {
+ throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
+ }
+
+ async findDuplicateGUID(remoteRecord) {
+ throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
+ }
+
+ async mergeToStorage(targetRecord, strict = false) {
+ throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
+ }
+}
+
+class CreditCards extends CreditCardsBase {
+ async _encryptNumber(creditCard) {
+ // Don't encrypt or obfuscate for GV, since we don't store or show
+ // the number. The API has to always provide the original number.
+ }
+
+ // Override AutofillRecords methods.
+
+ _initialize() {
+ this._initializePromise = Promise.resolve();
+ }
+
+ async _saveRecord(record, { sourceSync = false } = {}) {
+ lazy.GeckoViewAutocomplete.onCreditCardSave(
+ lazy.CreditCard.fromGecko(record)
+ );
+ }
+
+ /**
+ * Returns the record with the specified GUID.
+ *
+ * @param {string} guid
+ * Indicates which record to retrieve.
+ * @param {object} options
+ * @param {boolean} [options.rawData = false]
+ * Returns a raw record without modifications and the computed fields
+ * (this includes private fields)
+ * @returns {Promise<object>}
+ * A clone of the record.
+ */
+ async get(guid, { rawData = false } = {}) {
+ await this._store.updateCreditCards();
+ return super.get(guid, { rawData });
+ }
+
+ /**
+ * Returns all records.
+ *
+ * @param {object} options
+ * @param {boolean} [options.rawData = false]
+ * Returns raw records without modifications and the computed fields.
+ * @param {boolean} [options.includeDeleted = false]
+ * Also return any tombstone records.
+ * @returns {Promise<Array.<object>>}
+ * An array containing clones of all records.
+ */
+ async getAll({ rawData = false, includeDeleted = false } = {}) {
+ await this._store.updateCreditCards();
+ return super.getAll({ rawData, includeDeleted });
+ }
+
+ /**
+ * Return all saved field names in the collection.
+ *
+ * @returns {Set} Set containing saved field names.
+ */
+ async getSavedFieldNames() {
+ await this._store.updateCreditCards();
+ return super.getSavedFieldNames();
+ }
+
+ /**
+ * Normalize the given record and return the first matched guid if storage has the same record.
+ *
+ * @param {object} targetCreditCard
+ * The credit card for duplication checking.
+ * @returns {Promise<string|null>}
+ * Return the first guid if storage has the same credit card and null otherwise.
+ */
+ async getDuplicateGuid(targetCreditCard) {
+ let clonedTargetCreditCard = this._clone(targetCreditCard);
+ this._normalizeRecord(clonedTargetCreditCard);
+ if (!clonedTargetCreditCard["cc-number"]) {
+ return null;
+ }
+
+ await this._store.updateCreditCards();
+ for (let creditCard of this._data) {
+ if (creditCard.deleted) {
+ continue;
+ }
+
+ if (creditCard["cc-number"] == clonedTargetCreditCard["cc-number"]) {
+ return creditCard.guid;
+ }
+ }
+ return null;
+ }
+
+ async reconcile(remoteRecord) {
+ throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
+ }
+
+ async findDuplicateGUID(remoteRecord) {
+ throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
+ }
+
+ async mergeToStorage(targetRecord, strict = false) {
+ throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
+ }
+}
+
+class FormAutofillStorage extends FormAutofillStorageBase {
+ constructor() {
+ super(null);
+ }
+
+ getAddresses() {
+ if (!this._addresses) {
+ this._store.ensureDataReady();
+ this._addresses = new Addresses(this._store);
+ }
+ return this._addresses;
+ }
+
+ getCreditCards() {
+ if (!this._creditCards) {
+ this._store.ensureDataReady();
+ this._creditCards = new CreditCards(this._store);
+ }
+ return this._creditCards;
+ }
+
+ /**
+ * Initializes the in-memory async store API.
+ *
+ * @returns {JSONFile}
+ * The JSONFile store.
+ */
+ _initializeStore() {
+ return new GeckoViewStorage();
+ }
+}
+
+// The singleton exposed by this module.
+const formAutofillStorage = new FormAutofillStorage();