diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /toolkit/components/formautofill/android | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/formautofill/android')
-rw-r--r-- | toolkit/components/formautofill/android/FormAutofillPrompter.sys.mjs | 70 | ||||
-rw-r--r-- | toolkit/components/formautofill/android/FormAutofillStorage.sys.mjs | 277 |
2 files changed, 347 insertions, 0 deletions
diff --git a/toolkit/components/formautofill/android/FormAutofillPrompter.sys.mjs b/toolkit/components/formautofill/android/FormAutofillPrompter.sys.mjs new file mode 100644 index 0000000000..6ac3744dac --- /dev/null +++ b/toolkit/components/formautofill/android/FormAutofillPrompter.sys.mjs @@ -0,0 +1,70 @@ +/* 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. + */ + +import { XPCOMUtils } from "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, +}; + +export 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, storage, record, flowId) { + const prompt = new lazy.GeckoViewPrompter(browser.ownerGlobal); + + const duplicateRecord = (await storage.getDuplicateRecords(record).next()) + .value; + let newCreditCard; + if (duplicateRecord) { + newCreditCard = { ...duplicateRecord, ...record }; + } else { + newCreditCard = 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.sys.mjs b/toolkit/components/formautofill/android/FormAutofillStorage.sys.mjs new file mode 100644 index 0000000000..76d583536b --- /dev/null +++ b/toolkit/components/formautofill/android/FormAutofillStorage.sys.mjs @@ -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. + */ + +// We expose a singleton from this module. Some tests may import the +// constructor via a backstage pass. +import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; + +import { + FormAutofillStorageBase, + CreditCardsBase, + AddressesBase, +} from "resource://autofill/FormAutofillStorageBase.sys.mjs"; +import { JSONFile } from "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(); + } + + /** + * Find a duplicate credit card record in the storage. + * + * A record is considered as a duplicate of another record when two records + * are the "same". This might be true even when some of their fields are + * different. For example, one record has the same credit card number but has + * different expiration date as the other record are still considered as + * "duplicate". + * This is different from `getMatchRecord`, which ensures all the fields with + * value in the the record is equal to the returned record. + * + * @param {object} record + * The credit card for duplication checking. please make sure the + * record is normalized. + * @returns {object} + * Return the first duplicated record found in storage, null otherwise. + */ + async *getDuplicateRecords(record) { + if (!record["cc-number"]) { + return null; + } + + await this._store.updateCreditCards(); + for (const recordInStorage of this._data) { + if (recordInStorage.deleted) { + continue; + } + + if (recordInStorage["cc-number"] == record["cc-number"]) { + yield recordInStorage; + } + } + 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); + } +} + +export 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. +export const formAutofillStorage = new FormAutofillStorage(); |