mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			265 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			265 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* 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) {
 | 
						|
    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);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
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) {
 | 
						|
    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);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
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();
 |