Files
safari-internal-js/js/forms/FormMetadataClassification.js
2026-01-17 13:12:26 +01:00

639 lines
23 KiB
JavaScript

//# sourceURL=__InjectedScript_FormMetadataClassification.js
/* Copyright (c) 2025 Apple Inc. All rights reserved. */
"use strict";
const WBSABAddressProperty = "Address",
WBSABPhoneProperty = "Phone",
_WBSABAddressZIPKey = "ZIP",
WBSFormControlMetadataDefaultMaxLength = 524288,
WBSIgnoredClassificationToken = "-sf-ignored",
WBSDateDayOrderedPartToken = "-sf-day",
WBSDateMonthOrderedPartToken = "-sf-month",
WBSDateYearOrderedPartToken = "-sf-year",
WBSGivenNameOrderedPartToken = "given-name",
WBSAdditionalNameOrderedPartToken = "additional-name",
WBSFamilyNameOrderedPartToken = "family-name",
WBSLocaleForCreditCardExpirationDate = "en_US",
WBSCreditCardTypeClassificationToken = "cc-type",
WBSCreditCardHolderNameClassificationToken = "cc-name",
WBSCreditCardNumberClassificationToken = "cc-number",
WBSCreditCardExpirationClassificationToken = "cc-exp",
WBSCreditCardSecurityCodeClassificationToken = "cc-csc",
WBSCreditCardHolderNameClassificationDefaultOrderedParts = [
WBSGivenNameOrderedPartToken,
WBSAdditionalNameOrderedPartToken,
WBSFamilyNameOrderedPartToken,
],
WBSCreditCardExpirationClassificationDefaultOrderedParts = [
WBSDateMonthOrderedPartToken,
WBSDateYearOrderedPartToken,
],
WBSCredentialUsernameClassificationToken = "username",
WBSCredentialCurrentPasswordClassificationToken = "current-password",
WBSCredentialNewPasswordClassificationToken = "new-password",
WBSContactNameClassificationToken = "name",
WBSContactNameClassificationDefaultOrderedParts = [
WBSGivenNameOrderedPartToken,
WBSAdditionalNameOrderedPartToken,
WBSFamilyNameOrderedPartToken,
],
WBSNameOrderedPartTokensSet = new Set(
WBSContactNameClassificationDefaultOrderedParts,
),
WBSContactInstantMessageClassificationToken = "-sf-instant-message",
WBSContactPostalCodeClassificationToken = "postal-code",
WBSContactStreetAddressClassificationToken = "street-address",
WBSContactStreetAddressLine1OrderedPartToken = "address-line1",
WBSContactStreetAddressLine2OrderedPartToken = "address-line2",
WBSContactStreetAddressLine3OrderedPartToken = "address-line3",
WBSContactTelephoneClassificationToken = "tel",
WBSTelephoneCountryCodeOrderedPartToken = "tel-country-code",
WBSTelephoneAreaCodeOrderedPartToken = "tel-area-code",
WBSTelephoneLocalPrefixOrderedPartToken = "tel-local-prefix",
WBSTelephoneLocalSuffixOrderedPartToken = "tel-local-suffix",
WBSTelephoneExtensionOrderedPartToken = "tel-extension",
WBSTelephoneDefaultOrderedParts = [
WBSTelephoneCountryCodeOrderedPartToken,
WBSTelephoneAreaCodeOrderedPartToken,
WBSTelephoneLocalPrefixOrderedPartToken,
WBSTelephoneLocalSuffixOrderedPartToken,
WBSTelephoneExtensionOrderedPartToken,
],
WBSContactBirthdayClassificationToken = "bday",
WBSContactEmailClassificationToken = "email",
WBSDeviceEIDClassificationToken = "device-eid",
WBSDeviceIMEIClassificationToken = "device-imei",
AllowedControlTagsForStandaloneCreditCardCompositeExpirationControl = new Set(
["input", "select", "textarea"],
);
class FormMetadataClassification {
#e(e) {
return null != e && "object" == typeof e;
}
#t(e) {
return this.#e(e) && "string" == typeof e.ControlTagName;
}
#o(e) {
return this.#e(e) && "string" == typeof e.property;
}
fieldLooksLikeDateField(e) {
return !!(
e.ControlLooksLikeDayField ||
e.ControlLooksLikeMonthField ||
e.ControlLooksLikeYearField
);
}
#r(e) {
let t = e.ControlMaxLength;
return (
(void 0 === t || t < 0 || t > WBSFormControlMetadataDefaultMaxLength) &&
(t = WBSFormControlMetadataDefaultMaxLength),
t
);
}
fieldLooksLikeItExpectsDataOfSize(e, t) {
return (e.ControlSize ?? 0) <= t || this.#r(e) <= t;
}
fieldCouldBeCreditCardNumberContinuation(e, t) {
const o = 4;
if (t.length >= o) return !1;
if (!t[0]?.ControlLooksLikeCreditCardNumberField) return !1;
const r = 2;
if (e.ControlMaxLength === r) return !1;
if (e.ControlLooksLikeCreditCardNumberField) return !0;
if (e.ControlLooksLikeCreditCardSecurityCodeField) return !1;
if (e.ControlLooksLikeCreditCardCompositeExpirationDateField) return !1;
const n = 6;
if (!this.fieldLooksLikeItExpectsDataOfSize(e, n)) return !1;
const i = t.at(-1);
return !(i && !this.fieldLooksLikeItExpectsDataOfSize(i, n));
}
labelsCouldRepresentContinuation(e, t, o, r) {
return (
!(!e || !o) &&
(e === o ||
(!!t &&
(!r ||
(t.property === r.property &&
(!r.component || t.component === r.component)))))
);
}
#n(e) {
const t = [
WBSContactStreetAddressLine1OrderedPartToken,
WBSContactStreetAddressLine2OrderedPartToken,
WBSContactStreetAddressLine3OrderedPartToken,
],
o = [
WBSContactStreetAddressLine2OrderedPartToken,
WBSContactStreetAddressLine3OrderedPartToken,
];
if (e.AutocompleteTokens)
for (let o of e.AutocompleteTokens)
switch (o) {
case "street-address":
return t;
case "address-line1":
return [WBSContactStreetAddressLine1OrderedPartToken];
case "address-line2":
case "address-level2":
return [WBSContactStreetAddressLine2OrderedPartToken];
case "address-line3":
case "address-level1":
return [WBSContactStreetAddressLine3OrderedPartToken];
}
let r = e.ControlFieldName,
n = r?.indexOf("1") ?? -1,
i = r?.indexOf("2") ?? -1;
return -1 === n
? -1 === i
? t
: o
: -1 === i || digit1location < digit2location
? [WBSContactStreetAddressLine1OrderedPartToken]
: o;
}
fieldCouldBePhoneNumberContinuation(e, t) {
const o = 5;
if (t.length >= o) return !1;
if (t[0]?.AddressBookValueSpecifier?.property !== WBSABPhoneProperty)
return !1;
const r = 5;
return !!this.fieldLooksLikeItExpectsDataOfSize(e, r);
}
fieldCouldBePostCodeContinuation(e, t) {
const o = 3;
if (t.length >= o) return !1;
if (t[0]?.AddressBookValueSpecifier?.component != _WBSABAddressZIPKey)
return !1;
const r = 6;
return !!this.fieldLooksLikeItExpectsDataOfSize(e, r);
}
fieldLooksLikeSameDataType(e, t) {
const o = t.at(-1);
return (
!!this.labelsCouldRepresentContinuation(
o?.AddressBookLabel,
o?.AddressBookValueSpecifier,
e?.AddressBookLabel,
e?.AddressBookValueSpecifier,
) ||
!!(
o &&
this.fieldLooksLikeDateField(o) &&
this.fieldLooksLikeDateField(e)
) ||
!!this.fieldCouldBePhoneNumberContinuation(e, t) ||
!!this.fieldCouldBePostCodeContinuation(e, t) ||
!!this.fieldCouldBeCreditCardNumberContinuation(e, t)
);
}
#i(e) {
if (
(globalThis.DOMRect ||
(globalThis.DOMRect = class {
constructor(e, t, o, r) {
((this.left = e),
(this.right = e + o),
(this.top = t),
(this.bottom = t + r),
(this.width = o),
(this.height = r));
}
}),
e.ControlRectLeft ||
e.ControlRectTop ||
e.ControlRectWidth ||
e.ControlRectHeight)
)
return new DOMRect(
e.ControlRectLeft,
e.ControlRectTop,
e.ControlRectWidth,
e.ControlRectHeight,
);
let t = globalThis.FormMetadataJS?.formControlWithUniqueID(
e.ControlUniqueID,
);
return t ? t.getBoundingClientRect() : new DOMRect(0, 0, 0, 0);
}
fieldLooksLikeContinuation(e, t, o) {
if (!e.ControlIsTextField && "SELECT" !== e.ControlTagName.toUpperCase())
return !1;
if (!this.fieldLooksLikeSameDataType(e, t)) return !1;
if (o) return !0;
const r = this.#i(t.at(-1)),
n = this.#i(e);
if (Math.abs(r.top - n.top) > 3) return !1;
let i, a;
return (
r.left < n.left ? ((i = r), (a = n)) : ((i = n), (a = r)),
!(a.left - i.right > 60)
);
}
continuingFieldsInFormControls(e, t, o, r) {
const n = [e[t]];
for (let i = t + 1; i < e.length; ++i) {
const t = e[i];
if (o && !t.ControlIsTextField) break;
if (!this.fieldLooksLikeContinuation(t, n, r)) break;
n.push(t);
}
return n;
}
classifyControlsRelatedToNameParts(e, t, o) {
const r = e[t];
((r.ControlClassification = o),
(r.ControlOrderedParts = [r.AddressBookValueSpecifier?.classification]));
const n = new Set([r.AddressBookValueSpecifier?.classification]),
i = [e[t]];
for (let r = t + 1; r < e.length; ++r) {
const t = e[r];
if (!t.ControlIsTextField) break;
const a = t.AddressBookValueSpecifier?.classification;
if (!a) break;
if (!WBSNameOrderedPartTokensSet.has(a) || n.has(a)) break;
((t.ControlClassification = o),
(t.ControlOrderedParts = [a]),
n.add(a),
i.push(t));
}
return i;
}
identifyDateFields(e) {
let t,
o,
r,
n = !1;
for (let i of e)
if (i.ControlLooksLikeDayField) {
if (t) return [!1];
((t = i), (n = !0));
} else if (i.ControlLooksLikeMonthField) {
if (o) return [!1];
((o = i), (n = !0));
} else if (i.ControlLooksLikeYearField) {
if (r) return [!1];
((r = i), (n = !0));
}
return [n, r, o, t];
}
canonicalizedDateTemplate(e) {
if (e && (e = e.replace(/\s/g, "")).length && !/[^dmyDMY\/.-]/g.test(e))
return (e = (e = (e = e.replace(/D/g, "d")).replace(/m/g, "M")).replace(
/Y/g,
"y",
));
}
classifyDateFields(e, t, o, r, n, i, a) {
if (e.length > 3) return !1;
if (1 === e.length) {
if (!e[0].ControlIsTextField) return !1;
let i = e[0].ControlRequiredFormatForDateTimeInput;
if (!i) {
const t = n ? new Date(1999, 11, 30) : new Date(1999, 11);
let o = this.#r(e[0]),
r = this.canonicalizedDateTemplate(e[0].ControlPlaceholder),
s = r?.length ? r : n ? "ddMMy" : "MMyy";
i = FormMetadataJSController.dateFormatFromTemplate(s, a);
let l = FormMetadataJSController.stringFromDateFormat(i, t);
if (
(l.length > o &&
((s = n ? "dMMyy" : "MMyy"),
(i = FormMetadataJSController.dateFormatFromTemplate(s, a)),
(l = FormMetadataJSController.stringFromDateFormat(i, t)),
l.length > o &&
((s = n ? "dMyy" : "Myy"),
(i = FormMetadataJSController.dateFormatFromTemplate(s, a)),
(l = FormMetadataJSController.stringFromDateFormat(i, t)))),
l.length > o)
)
return !1;
}
const s = [];
for (const e of i) {
let t;
("y" === e ? (t = o) : "M" === e ? (t = r) : "d" === e && (t = n),
t && !s.includes(t) && s.push(t));
}
return (
(e[0].ControlClassification = t),
(e[0].ControlOrderedParts = s),
(e[0].ControlRequiredFormatForDateTimeInput = i),
!0
);
}
let [s, l, d, C] = this.identifyDateFields(e);
if (!s) return !1;
if (C && !d) return !1;
let c = 0;
for (const a of e)
((a.ControlClassification = t),
(a.ControlContinuationID = i),
(a.ControlContinuationIndex = c++),
a === C
? (a.ControlOrderedParts = [n])
: a === d
? (a.ControlOrderedParts = [r])
: a === l && (a.ControlOrderedParts = [o]));
return !0;
}
classify(e) {
const t = e.FormControls,
o = t.length,
r = e.AutoFillFormType === WBSAutoFillFormTypeNewAccount,
n = e.AutoFillFormType === WBSAutoFillFormTypeChangePassword,
i = e.UsernameElementUniqueID,
a = e.PasswordElementUniqueID,
s = e.OldPasswordElementUniqueID,
l = e.ConfirmPasswordElementUniqueID;
for (let e of t)
(e.AutocompleteTokens || e.AddressBookLabel) &&
(e.AddressBookValueSpecifier =
FormMetadataJSController.specifierForAutocompleteTokensAndAddressBookLabel(
e.AutocompleteTokens,
e.AddressBookLabel,
));
let d = !1,
C = !1,
c = !1,
f = !1,
S = !1,
k = 0;
for (let u = 0, T = 1; u < o; u += T, T = 1) {
const o = t[u];
if (o.ControlLooksLikeIgnoredDataTypeField) {
o.ControlClassification = WBSIgnoredClassificationToken;
continue;
}
const B = o.ControlUniqueID;
if (B === a || B === l) {
o.ControlClassification =
r || n
? WBSCredentialNewPasswordClassificationToken
: WBSCredentialCurrentPasswordClassificationToken;
continue;
}
if (B === s) {
o.ControlClassification =
WBSCredentialCurrentPasswordClassificationToken;
continue;
}
const h = o.AddressBookValueSpecifier?.classification;
if (h === WBSContactEmailClassificationToken) {
o.ControlClassification = WBSContactEmailClassificationToken;
continue;
}
if (B === i) {
o.ControlClassification = WBSCredentialUsernameClassificationToken;
continue;
}
if (!C && o.ControlLooksLikeCreditCardCardholderField) {
if (((C = !0), h && WBSNameOrderedPartTokensSet.has(h))) {
const e = this.classifyControlsRelatedToNameParts(
t,
u,
WBSCreditCardHolderNameClassificationToken,
);
if (e.length > 1) {
let t = ++k,
o = 0;
for (let r of e)
((r.ControlContinuationID = t),
(r.ControlContinuationIndex = o++));
}
T = e.length;
continue;
}
((o.ControlClassification = WBSCreditCardHolderNameClassificationToken),
(o.ControlOrderedParts =
WBSCreditCardHolderNameClassificationDefaultOrderedParts));
continue;
}
if (!d && o.ControlLooksLikeCreditCardNumberField) {
d = !0;
const e = this.continuingFieldsInFormControls(t, u, !0, !1);
let o = 0,
r = e.length > 1 ? ++k : 0;
for (let t of e)
((t.ControlClassification = WBSCreditCardNumberClassificationToken),
(t.ControlContinuationID = r),
(t.ControlContinuationIndex = o++));
T = e.length;
continue;
}
const P =
this.fieldLooksLikeDateField(o) ||
o.ControlLooksLikeCreditCardCompositeExpirationDateField;
if (!c && P) {
let e = f || C || d;
if (
((e ||=
!o.ControlLooksLikeOneTimeCodeField &&
1 ===
t.filter((e) =>
AllowedControlTagsForStandaloneCreditCardCompositeExpirationControl.has(
e.ControlTagName.toLowerCase(),
),
).length),
e)
) {
c = !0;
const e = this.continuingFieldsInFormControls(t, u, !1, !0);
let o = e.length > 1 ? ++k : 0;
(this.classifyDateFields(
e,
WBSCreditCardExpirationClassificationToken,
WBSDateYearOrderedPartToken,
WBSDateMonthOrderedPartToken,
void 0,
o,
WBSLocaleForCreditCardExpirationDate,
),
(T = e.length));
continue;
}
}
if (S || !o.ControlLooksLikeCreditCardSecurityCodeField)
if (f || !o.ControlLooksLikeCreditCardTypeField)
if (h) {
const r = o.AddressBookValueSpecifier.classificationHint;
if (h === WBSContactNameClassificationToken) {
((o.ControlClassification = h),
(o.ControlOrderedParts =
WBSContactNameClassificationDefaultOrderedParts));
continue;
}
if (WBSNameOrderedPartTokensSet.has(h)) {
const e = this.classifyControlsRelatedToNameParts(
t,
u,
WBSContactNameClassificationToken,
);
if (e.length > 1) {
let t = ++k,
o = 0;
for (let r of e)
((r.ControlContinuationID = t),
(r.ControlContinuationIndex = o++));
}
T = e.length;
continue;
}
if (h === WBSContactPostalCodeClassificationToken) {
const e = this.continuingFieldsInFormControls(t, u, !0, !1);
let o = e.length > 1 ? ++k : 0,
r = 0;
for (let t of e)
((t.ControlClassification =
WBSContactPostalCodeClassificationToken),
(t.ControlContinuationID = o),
(t.ControlContinuationIndex = r++));
T = e.length;
continue;
}
if (h === WBSContactStreetAddressClassificationToken) {
const e = this.continuingFieldsInFormControls(t, u, !0, !0);
let o = e.length > 1 ? ++k : 0,
r = 0;
for (let t of e)
((t.ControlClassification =
WBSContactStreetAddressClassificationToken),
(t.ControlContinuationID = o),
(t.ControlContinuationIndex = r++));
if (1 === e.length) {
let t = e[0];
t.ControlOrderedParts = this.#n(t);
} else
2 === e.length
? ((e[0].ControlOrderedParts = [
WBSContactStreetAddressLine1OrderedPartToken,
]),
(e[1].ControlOrderedParts = [
WBSContactStreetAddressLine2OrderedPartToken,
WBSContactStreetAddressLine3OrderedPartToken,
]))
: e.length >= 3 &&
((e[0].ControlOrderedParts = [
WBSContactStreetAddressLine1OrderedPartToken,
]),
(e[1].ControlOrderedParts = [
WBSContactStreetAddressLine2OrderedPartToken,
]),
(e[2].ControlOrderedParts = [
WBSContactStreetAddressLine3OrderedPartToken,
]));
T = e.length;
continue;
}
if (h === WBSContactInstantMessageClassificationToken) {
const e = this.continuingFieldsInFormControls(t, u, !0, !0);
(1 === e.length &&
((e[0].ControlClassification =
WBSContactInstantMessageClassificationToken),
r && (e[0].ControlClassificationHints = [r])),
(T = e.length));
continue;
}
if (h.startsWith(WBSContactTelephoneClassificationToken)) {
const e = this.continuingFieldsInFormControls(t, u, !0, !1);
if (1 == e.length) {
((e[0].ControlClassification =
WBSContactTelephoneClassificationToken),
(e[0].ControlOrderedParts = WBSTelephoneDefaultOrderedParts),
r && (e[0].ControlClassificationHints = [r]));
continue;
}
let o = ++k,
n = 0;
for (let t of e)
((t.ControlClassification =
WBSContactTelephoneClassificationToken),
(t.ControlContinuationID = o),
(t.ControlContinuationIndex = n++),
r && (t.ControlClassificationHints = [r]));
(2 === e.length
? ((e[0].ControlOrderedParts = [
WBSTelephoneAreaCodeOrderedPartToken,
]),
(e[1].ControlOrderedParts = [
WBSTelephoneLocalPrefixOrderedPartToken,
WBSTelephoneLocalSuffixOrderedPartToken,
]))
: 3 === e.length
? ((e[0].ControlOrderedParts = [
WBSTelephoneAreaCodeOrderedPartToken,
]),
(e[1].ControlOrderedParts = [
WBSTelephoneLocalPrefixOrderedPartToken,
]),
(e[2].ControlOrderedParts = [
WBSTelephoneLocalSuffixOrderedPartToken,
]))
: 4 === e.length
? ((e[0].ControlOrderedParts = [
WBSTelephoneCountryCodeOrderedPartToken,
]),
(e[1].ControlOrderedParts = [
WBSTelephoneAreaCodeOrderedPartToken,
]),
(e[2].ControlOrderedParts = [
WBSTelephoneLocalPrefixOrderedPartToken,
]),
(e[3].ControlOrderedParts = [
WBSTelephoneLocalSuffixOrderedPartToken,
]))
: ((e[0].ControlOrderedParts = [
WBSTelephoneCountryCodeOrderedPartToken,
]),
(e[1].ControlOrderedParts = [
WBSTelephoneAreaCodeOrderedPartToken,
]),
(e[2].ControlOrderedParts = [
WBSTelephoneLocalPrefixOrderedPartToken,
]),
(e[3].ControlOrderedParts = [
WBSTelephoneLocalSuffixOrderedPartToken,
]),
(e[4].ControlOrderedParts = [
WBSTelephoneExtensionOrderedPartToken,
])),
(T = e.length));
continue;
}
if (h === WBSContactBirthdayClassificationToken) {
const o = this.continuingFieldsInFormControls(t, u, !1, !1),
r = o.length > 1 ? ++k : void 0,
n =
e.RequestType === WBSFormMetadataRequestTesting
? "en_US"
: void 0;
(this.classifyDateFields(
o,
WBSContactBirthdayClassificationToken,
WBSDateYearOrderedPartToken,
WBSDateMonthOrderedPartToken,
WBSDateDayOrderedPartToken,
r,
n,
),
(T = o.length));
continue;
}
o.ControlClassification = h;
} else
o.ControlLooksLikeEIDField
? (o.ControlClassification = WBSDeviceEIDClassificationToken)
: o.ControlLooksLikeIMEIField &&
(o.ControlClassification = WBSDeviceIMEIClassificationToken);
else
((f = !0),
(o.ControlClassification = WBSCreditCardTypeClassificationToken));
else
((S = !0),
(o.ControlClassification =
WBSCreditCardSecurityCodeClassificationToken));
}
}
}
globalThis.FormMetadataClassificationJS = new FormMetadataClassification();