From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../android/FormAutofillPrompter.sys.mjs | 69 ++++++ .../android/FormAutofillStorage.sys.mjs | 265 +++++++++++++++++++++ 2 files changed, 334 insertions(+) create mode 100644 toolkit/components/formautofill/android/FormAutofillPrompter.sys.mjs create mode 100644 toolkit/components/formautofill/android/FormAutofillStorage.sys.mjs (limited to 'toolkit/components/formautofill/android') diff --git a/toolkit/components/formautofill/android/FormAutofillPrompter.sys.mjs b/toolkit/components/formautofill/android/FormAutofillPrompter.sys.mjs new file mode 100644 index 0000000000..6bb0e991b1 --- /dev/null +++ b/toolkit/components/formautofill/android/FormAutofillPrompter.sys.mjs @@ -0,0 +1,69 @@ +/* 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. + */ + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + CreditCard: "resource://gre/modules/GeckoViewAutocomplete.sys.mjs", + GeckoViewAutocomplete: "resource://gre/modules/GeckoViewAutocomplete.sys.mjs", + GeckoViewPrompter: "resource://gre/modules/GeckoViewPrompter.sys.mjs", +}); + +// 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, + storage, + flowId, + { oldRecord, newRecord } + ) { + throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED); + }, + + async promptToSaveCreditCard( + browser, + storage, + flowId, + { oldRecord, newRecord } + ) { + if (oldRecord) { + newRecord = { ...oldRecord, ...newRecord }; + } + + const prompt = new lazy.GeckoViewPrompter(browser.ownerGlobal); + prompt.asyncShowPrompt( + this._createMessage([lazy.CreditCard.fromGecko(newRecord)]), + 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..0d11880ff5 --- /dev/null +++ b/toolkit/components/formautofill/android/FormAutofillStorage.sys.mjs @@ -0,0 +1,265 @@ +/* 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. + */ + +import { + FormAutofillStorageBase, + CreditCardsBase, + AddressesBase, +} from "resource://autofill/FormAutofillStorageBase.sys.mjs"; +import { JSONFile } from "resource://gre/modules/JSONFile.sys.mjs"; + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + Address: "resource://gre/modules/GeckoViewAutocomplete.sys.mjs", + CreditCard: "resource://gre/modules/GeckoViewAutocomplete.sys.mjs", + GeckoViewAutocomplete: "resource://gre/modules/GeckoViewAutocomplete.sys.mjs", +}); + +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} + * 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>} + * 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); + } +} + +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} + * 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>} + * 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); + } +} + +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(); -- cgit v1.2.3