Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@ export const AddressMetaDataExtension = {
},
"data/JP": {
alpha_3_code: "JPN",
fmt: "〒%Z%n%S%C%n%A%n%O%n%N",
require: "ACSZ",
},
"data/JE": {
alpha_3_code: "JEY",
Expand Down Expand Up @@ -474,6 +476,7 @@ export const AddressMetaDataExtension = {
},
"data/NL": {
alpha_3_code: "NLD",
address_reversed: true,
},
"data/NC": {
alpha_3_code: "NCL",
Expand Down
36 changes: 36 additions & 0 deletions firefox-ios/Client/Assets/CC_Script/AddressParser.sys.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -313,4 +313,40 @@ export class AddressParser {
static mergeWhitespace(s) {
return s?.replace(/\s{2,}/g, " ");
}

// This is quite fragile, but handles a number of basic cases. This is intended
// to split the street number suffix from the street number. For example:
// 35B will be split into number=35,suffix=B
// Returns an array with [housenumber, suffix]
static parseHouseSuffix(address, structuredAddress) {
let streetNumber = structuredAddress?.street_number;
if (!streetNumber) {
return null;
}

let numberIndex = address.indexOf(streetNumber);
if (numberIndex < 0) {
return [streetNumber];
}

let match = streetNumber.match(/^(\d+)(\w?)/);
if (!match) {
return [streetNumber];
}

let suffix;
let result = [match[1]];
// If the house number is after the street, include the rest of the address
// as part of the suffix, otherwise just include the suffix on the number.
if (numberIndex > structuredAddress?.street_name.length) {
suffix = address.substring(numberIndex + match[1].length).trim();
} else {
suffix = match[2];
}
if (suffix) {
result.push(suffix.replace("\n", " "));
}

return result;
}
}
20 changes: 20 additions & 0 deletions firefox-ios/Client/Assets/CC_Script/AddressRecord.sys.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { FormAutofillNameUtils } from "resource://gre/modules/shared/FormAutofil
import { FormAutofillUtils } from "resource://gre/modules/shared/FormAutofillUtils.sys.mjs";
import { PhoneNumber } from "resource://gre/modules/shared/PhoneNumber.sys.mjs";
import { FormAutofill } from "resource://autofill/FormAutofill.sys.mjs";
import { AddressParser } from "resource://gre/modules/shared/AddressParser.sys.mjs";

/**
* The AddressRecord class serves to handle and normalize internal address records.
Expand All @@ -32,6 +33,7 @@ export class AddressRecord {
static computeFields(address) {
this.#computeNameFields(address);
this.#computeAddressLineFields(address);
this.#computeStreetAndHouseNumberFields(address);
this.#computeCountryFields(address);
this.#computeTelFields(address);
}
Expand Down Expand Up @@ -66,6 +68,24 @@ export class AddressRecord {
}
}

static #computeStreetAndHouseNumberFields(address) {
if (!("address-housenumber" in address) && "street-address" in address) {
let streetAddress = address["street-address"];
let parsedAddress = AddressParser.parseStreetAddress(streetAddress);
if (parsedAddress) {
address["address-housenumber"] = parsedAddress.street_number;

let splitNumber = AddressParser.parseHouseSuffix(
streetAddress,
parsedAddress
);
if (splitNumber?.length >= 2) {
address["address-extra-housesuffix"] = splitNumber[1];
}
}
}
}

static #computeCountryFields(address) {
// Compute country name
if (!("country-name" in address)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const AutofillFormFactory = {
findRootForField(element) {
let ignoreForm;
try {
const bc = element.ownerGlobal.browsingContext;
const bc = element.documentGlobal.browsingContext;
ignoreForm = bc != bc.top;
} catch {
ignoreForm = false;
Expand All @@ -32,11 +32,15 @@ export const AutofillFormFactory = {
createFromField(aField) {
let ignoreForm;
try {
const bc = aField.ownerGlobal.browsingContext;
const bc = aField.documentGlobal.browsingContext;
ignoreForm = bc != bc.top;
} catch {
ignoreForm = false;
}
return lazy.FormLikeFactory.createFromField(aField, { ignoreForm });
},

createFromDocumentRoot(aDocRoot) {
return lazy.FormLikeFactory.createFromDocumentRoot(aDocRoot);
},
};
85 changes: 21 additions & 64 deletions firefox-ios/Client/Assets/CC_Script/AutofillTelemetry.sys.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { FormAutofillUtils } from "resource://gre/modules/shared/FormAutofillUtils.sys.mjs";
import { AutofillDataTypes } from "resource://gre/modules/shared/AutofillDataTypes.sys.mjs";

const { FIELD_STATES } = FormAutofillUtils;

Expand All @@ -12,10 +13,6 @@ class AutofillTelemetryBase {
EVENT_CATEGORY = null;
EVENT_OBJECT_FORM_INTERACTION = null;

HISTOGRAM_NUM_USES = null;
HISTOGRAM_PROFILE_NUM_USES = null;
HISTOGRAM_PROFILE_NUM_USES_KEY = null;

#initFormEventExtra(value) {
let extra = {};
for (const field of Object.values(this.SUPPORTED_FIELDS)) {
Expand Down Expand Up @@ -183,17 +180,6 @@ class AutofillTelemetryBase {
throw new Error("Not implemented.");
}

recordNumberOfUse(records) {
let histogram = Services.telemetry.getKeyedHistogramById(
this.HISTOGRAM_PROFILE_NUM_USES
);
histogram.clear();

for (let record of records) {
histogram.add(this.HISTOGRAM_PROFILE_NUM_USES_KEY, record.timesUsed);
}
}

recordIframeLayoutDetection(flowId, fieldDetails) {
const fieldsInMainFrame = [];
const fieldsInIframe = [];
Expand Down Expand Up @@ -238,9 +224,6 @@ export class AddressTelemetry extends AutofillTelemetryBase {
EVENT_OBJECT_FORM_INTERACTION = "AddressForm";
EVENT_OBJECT_FORM_INTERACTION_EXT = "AddressFormExt";

HISTOGRAM_PROFILE_NUM_USES = "AUTOFILL_PROFILE_NUM_USES";
HISTOGRAM_PROFILE_NUM_USES_KEY = "address";

// Fields that are recorded in `address_form` and `address_form_ext` telemetry
SUPPORTED_FIELDS = {
"street-address": "street_address",
Expand Down Expand Up @@ -316,10 +299,6 @@ class CreditCardTelemetry extends AutofillTelemetryBase {
EVENT_CATEGORY = "creditcard";
EVENT_OBJECT_FORM_INTERACTION = "CcFormV2";

HISTOGRAM_NUM_USES = "CREDITCARD_NUM_USES";
HISTOGRAM_PROFILE_NUM_USES = "AUTOFILL_PROFILE_NUM_USES";
HISTOGRAM_PROFILE_NUM_USES_KEY = "credit_card";

// Mapping of field name used in formautofill code to the field name
// used in the telemetry.
SUPPORTED_FIELDS = {
Expand Down Expand Up @@ -369,23 +348,6 @@ class CreditCardTelemetry extends AutofillTelemetryBase {
}
}

recordNumberOfUse(records) {
super.recordNumberOfUse(records);

if (!this.HISTOGRAM_NUM_USES) {
return;
}

let histogram = Services.telemetry.getHistogramById(
this.HISTOGRAM_NUM_USES
);
histogram.clear();

for (let record of records) {
histogram.add(record.timesUsed);
}
}

recordAutofillProfileCount(count) {
Glean.formautofillCreditcards.autofillProfilesCount.set(count);
}
Expand All @@ -395,20 +357,23 @@ export class AutofillTelemetry {
static #creditCardTelemetry = new CreditCardTelemetry();
static #addressTelemetry = new AddressTelemetry();

// const for `type` parameter used in the utility functions
static ADDRESS = "address";
static CREDIT_CARD = "creditcard";

static #getTelemetryByFieldDetail(fieldDetail) {
return FormAutofillUtils.isAddressField(fieldDetail.fieldName)
? this.#addressTelemetry
: this.#creditCardTelemetry;
// Maps an AutofillDataType's id to its telemetry instance, or null for a type
// with no telemetry schema (callers no-op on null). The Glean metric
// category lives on each instance's
// EVENT_CATEGORY.
static #getTelemetryByType(typeId) {
switch (typeId) {
case AutofillDataTypes.ADDRESS:
return this.#addressTelemetry;
case AutofillDataTypes.CREDIT_CARD:
return this.#creditCardTelemetry;
}
return null;
}

static #getTelemetryByType(type) {
return type == AutofillTelemetry.CREDIT_CARD
? this.#creditCardTelemetry
: this.#addressTelemetry;
static #getTelemetryByFieldDetail(fieldDetail) {
const typeId = AutofillDataTypes.typeIdForFieldName(fieldDetail.fieldName);
return this.#getTelemetryByType(typeId);
}

/**
Expand All @@ -419,7 +384,7 @@ export class AutofillTelemetry {
*/
static recordDoorhangerShown(type, object, flowId) {
const telemetry = this.#getTelemetryByType(type);
telemetry.recordDoorhangerEvent("show", object, flowId);
telemetry?.recordDoorhangerEvent("show", object, flowId);
}

static recordDoorhangerClicked(type, method, object, flowId) {
Expand All @@ -438,7 +403,7 @@ export class AutofillTelemetry {
break;
}

telemetry.recordDoorhangerEvent(method, object, flowId);
telemetry?.recordDoorhangerEvent(method, object, flowId);
}

/**
Expand All @@ -450,25 +415,17 @@ export class AutofillTelemetry {

static recordFormInteractionEvent(method, flowId, fieldDetails, data) {
const telemetry = this.#getTelemetryByFieldDetail(fieldDetails[0]);
telemetry.recordFormInteractionEvent(method, flowId, fieldDetails, data);
telemetry?.recordFormInteractionEvent(method, flowId, fieldDetails, data);
}

static recordManageEvent(type, method) {
const telemetry = this.#getTelemetryByType(type);
telemetry.recordManageEvent(method);
telemetry?.recordManageEvent(method);
}

static recordAutofillProfileCount(type, count) {
const telemetry = this.#getTelemetryByType(type);
telemetry.recordAutofillProfileCount(count);
}

/**
* Utility functions for address/credit card number of use
*/
static recordNumberOfUse(type, records) {
const telemetry = this.#getTelemetryByType(type);
telemetry.recordNumberOfUse(records);
telemetry?.recordAutofillProfileCount(count);
}

static recordFormSubmissionHeuristicCount(label) {
Expand Down
5 changes: 2 additions & 3 deletions firefox-ios/Client/Assets/CC_Script/Constants.ios.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
const IOS_DEFAULT_PREFERENCES = {
"extensions.formautofill.creditCards.heuristics.mode": 1,
"extensions.formautofill.creditCards.heuristics.fathom.confidenceThreshold": 0.5,
"extensions.formautofill.creditCards.heuristics.fathom.highConfidenceThreshold": 0.95,
"extensions.formautofill.creditCards.heuristics.fathom.testConfidence": 0,
"extensions.formautofill.creditCards.heuristics.fathom.types":
"cc-number,cc-name",
Expand All @@ -32,15 +31,15 @@ const IOS_DEFAULT_PREFERENCES = {
"extensions.formautofill.heuristics.captureOnPageNavigation": false,
"extensions.formautofill.heuristics.detectDynamicFormChanges": false,
"extensions.formautofill.heuristics.fillOnDynamicFormChanges": false,
"extensions.formautofill.heuristics.refillOnSiteClearingFields": false,
"extensions.formautofill.focusOnAutofill": false,
"extensions.formautofill.test.ignoreVisibilityCheck": false,
"extensions.formautofill.heuristics.autofillSameOriginWithTop": false,
"signon.generation.confidenceThreshold": 0.75,
"extensions.formautofill.ml.experiment.enabled": false,
};

// Used Mimic the behavior of .getAutocompleteInfo()
// List from: https://searchfox.org/mozilla-central/source/dom/base/AutocompleteFieldList.h#89-149
// List from: https://searchfox.org/firefox-main/source/dom/base/AutocompleteFieldList.h#89-149
// Also found here: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete
const VALID_AUTOCOMPLETE_FIELDS = [
"off",
Expand Down
Loading