diff --git a/node_modules/@duckduckgo/autofill/dist/autofill-debug.js b/node_modules/@duckduckgo/autofill/dist/autofill-debug.js index 5875c2c2a770..1469cd992a7f 100644 --- a/node_modules/@duckduckgo/autofill/dist/autofill-debug.js +++ b/node_modules/@duckduckgo/autofill/dist/autofill-debug.js @@ -78,6 +78,7 @@ class ZodError extends Error { }; const actualProto = new.target.prototype; if (Object.setPrototypeOf) { + // eslint-disable-next-line ban/ban Object.setPrototypeOf(this, actualProto); } else { this.__proto__ = actualProto; @@ -115,6 +116,13 @@ class ZodError extends Error { curr[el] = curr[el] || { _errors: [] }; + // if (typeof el === "string") { + // curr[el] = curr[el] || { _errors: [] }; + // } else if (typeof el === "number") { + // const errorArray: any = []; + // errorArray._errors = []; + // curr[el] = curr[el] || errorArray; + // } } else { curr[el] = curr[el] || { _errors: [] @@ -280,7 +288,8 @@ function addIssueToContext(ctx, issueData) { issueData: issueData, data: ctx.data, path: ctx.path, - errorMaps: [ctx.common.contextualErrorMap, ctx.schemaErrorMap, (0, errors_1.getErrorMap)(), en_1.default].filter(x => !!x) + errorMaps: [ctx.common.contextualErrorMap, ctx.schemaErrorMap, (0, errors_1.getErrorMap)(), en_1.default // then global default map + ].filter(x => !!x) }); ctx.common.issues.push(issue); } @@ -404,7 +413,9 @@ var util; return obj[e]; }); }; - util.objectKeys = typeof Object.keys === "function" ? obj => Object.keys(obj) : object => { + util.objectKeys = typeof Object.keys === "function" // eslint-disable-line ban/ban + ? obj => Object.keys(obj) // eslint-disable-line ban/ban + : object => { const keys = []; for (const key in object) { if (Object.prototype.hasOwnProperty.call(object, key)) { @@ -419,7 +430,8 @@ var util; } return undefined; }; - util.isInteger = typeof Number.isInteger === "function" ? val => Number.isInteger(val) : val => typeof val === "number" && isFinite(val) && Math.floor(val) === val; + util.isInteger = typeof Number.isInteger === "function" ? val => Number.isInteger(val) // eslint-disable-line ban/ban + : val => typeof val === "number" && isFinite(val) && Math.floor(val) === val; function joinValues(array) { let separator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : " | "; return array.map(val => typeof val === "string" ? `'${val}'` : val).join(separator); @@ -437,7 +449,7 @@ var objectUtil; objectUtil.mergeShapes = (first, second) => { return { ...first, - ...second + ...second // second overwrites first }; }; })(objectUtil = exports.objectUtil || (exports.objectUtil = {})); @@ -705,6 +717,7 @@ function processCreateParams(params) { } class ZodType { constructor(def) { + /** Alias of safeParseAsync */ this.spa = this.safeParseAsync; this._def = def; this.parse = this.parse.bind(this); @@ -965,12 +978,31 @@ exports.Schema = ZodType; exports.ZodSchema = ZodType; const cuidRegex = /^c[^\s-]{8,}$/i; const cuid2Regex = /^[a-z][a-z0-9]*$/; -const ulidRegex = /[0-9A-HJKMNP-TV-Z]{26}/; +const ulidRegex = /^[0-9A-HJKMNP-TV-Z]{26}$/; +// const uuidRegex = +// /^([a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[a-f0-9]{4}-[a-f0-9]{12}|00000000-0000-0000-0000-000000000000)$/i; const uuidRegex = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/i; -const emailRegex = /^([A-Z0-9_+-]+\.?)*[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i; -const emojiRegex = /^(\p{Extended_Pictographic}|\p{Emoji_Component})+$/u; +// from https://stackoverflow.com/a/46181/1550155 +// old version: too slow, didn't support unicode +// const emailRegex = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i; +//old email regex +// const emailRegex = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@((?!-)([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{1,})[^-<>()[\].,;:\s@"]$/i; +// eslint-disable-next-line +// const emailRegex = +// /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\])|(\[IPv6:(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))\])|([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])*(\.[A-Za-z]{2,})+))$/; +// const emailRegex = +// /^[a-zA-Z0-9\.\!\#\$\%\&\'\*\+\/\=\?\^\_\`\{\|\}\~\-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; +// const emailRegex = +// /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i; +const emailRegex = /^(?!\.)(?!.*\.\.)([A-Z0-9_+-\.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i; +// const emailRegex = +// /^[a-z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-z0-9-]+(?:\.[a-z0-9\-]+)*$/i; +// from https://thekevinscott.com/emojis-in-javascript/#writing-a-regular-expression +const _emojiRegex = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`; +let emojiRegex; const ipv4Regex = /^(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))$/; const ipv6Regex = /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/; +// Adapted from https://stackoverflow.com/a/3143231 const datetimeRegex = args => { if (args.precision) { if (args.offset) { @@ -1002,33 +1034,6 @@ function isValidIP(ip, version) { return false; } class ZodString extends ZodType { - constructor() { - super(...arguments); - this._regex = (regex, validation, message) => this.refinement(data => regex.test(data), { - validation, - code: ZodError_1.ZodIssueCode.invalid_string, - ...errorUtil_1.errorUtil.errToObj(message) - }); - this.nonempty = message => this.min(1, errorUtil_1.errorUtil.errToObj(message)); - this.trim = () => new ZodString({ - ...this._def, - checks: [...this._def.checks, { - kind: "trim" - }] - }); - this.toLowerCase = () => new ZodString({ - ...this._def, - checks: [...this._def.checks, { - kind: "toLowerCase" - }] - }); - this.toUpperCase = () => new ZodString({ - ...this._def, - checks: [...this._def.checks, { - kind: "toUpperCase" - }] - }); - } _parse(input) { if (this._def.coerce) { input.data = String(input.data); @@ -1040,7 +1045,10 @@ class ZodString extends ZodType { code: ZodError_1.ZodIssueCode.invalid_type, expected: util_1.ZodParsedType.string, received: ctx.parsedType - }); + } + // + ); + return parseUtil_1.INVALID; } const status = new parseUtil_1.ParseStatus(); @@ -1109,6 +1117,9 @@ class ZodString extends ZodType { status.dirty(); } } else if (check.kind === "emoji") { + if (!emojiRegex) { + emojiRegex = new RegExp(_emojiRegex, "u"); + } if (!emojiRegex.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); (0, parseUtil_1.addIssueToContext)(ctx, { @@ -1255,6 +1266,13 @@ class ZodString extends ZodType { value: input.data }; } + _regex(regex, validation, message) { + return this.refinement(data => regex.test(data), { + validation, + code: ZodError_1.ZodIssueCode.invalid_string, + ...errorUtil_1.errorUtil.errToObj(message) + }); + } _addCheck(check) { return new ZodString({ ...this._def, @@ -1376,6 +1394,37 @@ class ZodString extends ZodType { ...errorUtil_1.errorUtil.errToObj(message) }); } + /** + * @deprecated Use z.string().min(1) instead. + * @see {@link ZodString.min} + */ + nonempty(message) { + return this.min(1, errorUtil_1.errorUtil.errToObj(message)); + } + trim() { + return new ZodString({ + ...this._def, + checks: [...this._def.checks, { + kind: "trim" + }] + }); + } + toLowerCase() { + return new ZodString({ + ...this._def, + checks: [...this._def.checks, { + kind: "toLowerCase" + }] + }); + } + toUpperCase() { + return new ZodString({ + ...this._def, + checks: [...this._def.checks, { + kind: "toUpperCase" + }] + }); + } get isDatetime() { return !!this._def.checks.find(ch => ch.kind === "datetime"); } @@ -1432,6 +1481,7 @@ ZodString.create = params => { ...processCreateParams(params) }); }; +// https://stackoverflow.com/questions/3966484/why-does-modulus-operator-return-fractional-number-in-javascript/31711034#31711034 function floatSafeRemainder(val, step) { const valDecCount = (val.toString().split(".")[1] || "").length; const stepDecCount = (step.toString().split(".")[1] || "").length; @@ -2037,6 +2087,7 @@ ZodNull.create = params => { class ZodAny extends ZodType { constructor() { super(...arguments); + // to prevent instances of other classes from extending ZodAny. this causes issues with catchall in ZodObject. this._any = true; } _parse(input) { @@ -2053,6 +2104,7 @@ ZodAny.create = params => { class ZodUnknown extends ZodType { constructor() { super(...arguments); + // required this._unknown = true; } _parse(input) { @@ -2250,7 +2302,47 @@ class ZodObject extends ZodType { constructor() { super(...arguments); this._cached = null; + /** + * @deprecated In most cases, this is no longer needed - unknown properties are now silently stripped. + * If you want to pass through unknown properties, use `.passthrough()` instead. + */ this.nonstrict = this.passthrough; + // extend< + // Augmentation extends ZodRawShape, + // NewOutput extends util.flatten<{ + // [k in keyof Augmentation | keyof Output]: k extends keyof Augmentation + // ? Augmentation[k]["_output"] + // : k extends keyof Output + // ? Output[k] + // : never; + // }>, + // NewInput extends util.flatten<{ + // [k in keyof Augmentation | keyof Input]: k extends keyof Augmentation + // ? Augmentation[k]["_input"] + // : k extends keyof Input + // ? Input[k] + // : never; + // }> + // >( + // augmentation: Augmentation + // ): ZodObject< + // extendShape, + // UnknownKeys, + // Catchall, + // NewOutput, + // NewInput + // > { + // return new ZodObject({ + // ...this._def, + // shape: () => ({ + // ...this._def.shape(), + // ...augmentation, + // }), + // }) as any; + // } + /** + * @deprecated Use `.extend` instead + * */ this.augment = this.extend; } _getCached() { @@ -2329,6 +2421,7 @@ class ZodObject extends ZodType { throw new Error(`Internal ZodObject error: invalid unknownKeys value.`); } } else { + // run catchall validation const catchall = this._def.catchall; for (const key of extraKeys) { const value = ctx.data[key]; @@ -2337,7 +2430,9 @@ class ZodObject extends ZodType { status: "valid", value: key }, - value: catchall._parse(new ParseInputLazyPath(ctx, value, ctx.path, key)), + value: catchall._parse(new ParseInputLazyPath(ctx, value, ctx.path, key) //, ctx.child(key), value, getParsedType(value) + ), + alwaysSet: key in ctx.data }); } @@ -2395,6 +2490,23 @@ class ZodObject extends ZodType { unknownKeys: "passthrough" }); } + // const AugmentFactory = + // (def: Def) => + // ( + // augmentation: Augmentation + // ): ZodObject< + // extendShape, Augmentation>, + // Def["unknownKeys"], + // Def["catchall"] + // > => { + // return new ZodObject({ + // ...def, + // shape: () => ({ + // ...def.shape(), + // ...augmentation, + // }), + // }) as any; + // }; extend(augmentation) { return new ZodObject({ ...this._def, @@ -2404,6 +2516,11 @@ class ZodObject extends ZodType { }) }); } + /** + * Prior to zod@1.0.12 there was a bug in the + * inferred type of merged objects. Please + * upgrade if you are experiencing issues. + */ merge(merging) { const merged = new ZodObject({ unknownKeys: merging._def.unknownKeys, @@ -2416,11 +2533,67 @@ class ZodObject extends ZodType { }); return merged; } + // merge< + // Incoming extends AnyZodObject, + // Augmentation extends Incoming["shape"], + // NewOutput extends { + // [k in keyof Augmentation | keyof Output]: k extends keyof Augmentation + // ? Augmentation[k]["_output"] + // : k extends keyof Output + // ? Output[k] + // : never; + // }, + // NewInput extends { + // [k in keyof Augmentation | keyof Input]: k extends keyof Augmentation + // ? Augmentation[k]["_input"] + // : k extends keyof Input + // ? Input[k] + // : never; + // } + // >( + // merging: Incoming + // ): ZodObject< + // extendShape>, + // Incoming["_def"]["unknownKeys"], + // Incoming["_def"]["catchall"], + // NewOutput, + // NewInput + // > { + // const merged: any = new ZodObject({ + // unknownKeys: merging._def.unknownKeys, + // catchall: merging._def.catchall, + // shape: () => + // objectUtil.mergeShapes(this._def.shape(), merging._def.shape()), + // typeName: ZodFirstPartyTypeKind.ZodObject, + // }) as any; + // return merged; + // } setKey(key, schema) { return this.augment({ [key]: schema }); } + // merge( + // merging: Incoming + // ): //ZodObject = (merging) => { + // ZodObject< + // extendShape>, + // Incoming["_def"]["unknownKeys"], + // Incoming["_def"]["catchall"] + // > { + // // const mergedShape = objectUtil.mergeShapes( + // // this._def.shape(), + // // merging._def.shape() + // // ); + // const merged: any = new ZodObject({ + // unknownKeys: merging._def.unknownKeys, + // catchall: merging._def.catchall, + // shape: () => + // objectUtil.mergeShapes(this._def.shape(), merging._def.shape()), + // typeName: ZodFirstPartyTypeKind.ZodObject, + // }) as any; + // return merged; + // } catchall(index) { return new ZodObject({ ...this._def, @@ -2451,6 +2624,9 @@ class ZodObject extends ZodType { shape: () => shape }); } + /** + * @deprecated + */ deepPartial() { return deepPartialify(this); } @@ -2527,6 +2703,7 @@ class ZodUnion extends ZodType { } = this._processInputParams(input); const options = this._def.options; function handleResults(results) { + // return first issue-free validation if it exists for (const result of results) { if (result.result.status === "valid") { return result.result; @@ -2534,10 +2711,12 @@ class ZodUnion extends ZodType { } for (const result of results) { if (result.result.status === "dirty") { + // add issues from dirty option ctx.common.issues.push(...result.ctx.common.issues); return result.result; } } + // return invalid const unionErrors = results.map(result => new ZodError_1.ZodError(result.ctx.common.issues)); (0, parseUtil_1.addIssueToContext)(ctx, { code: ZodError_1.ZodIssueCode.invalid_union, @@ -2617,6 +2796,13 @@ ZodUnion.create = (types, params) => { ...processCreateParams(params) }); }; +///////////////////////////////////////////////////// +///////////////////////////////////////////////////// +////////// ////////// +////////// ZodDiscriminatedUnion ////////// +////////// ////////// +///////////////////////////////////////////////////// +///////////////////////////////////////////////////// const getDiscriminator = type => { if (type instanceof ZodLazy) { return getDiscriminator(type.schema); @@ -2627,6 +2813,7 @@ const getDiscriminator = type => { } else if (type instanceof ZodEnum) { return type.options; } else if (type instanceof ZodNativeEnum) { + // eslint-disable-next-line ban/ban return Object.keys(type.enum); } else if (type instanceof ZodDefault) { return getDiscriminator(type._def.innerType); @@ -2685,8 +2872,18 @@ class ZodDiscriminatedUnion extends ZodType { get optionsMap() { return this._def.optionsMap; } + /** + * The constructor of the discriminated union schema. Its behaviour is very similar to that of the normal z.union() constructor. + * However, it only allows a union of objects, all of which need to share a discriminator property. This property must + * have a different value for each object in the union. + * @param discriminator the name of the discriminator property + * @param types an array of object schemas + * @param params + */ static create(discriminator, options, params) { + // Get all the valid discriminator values const optionsMap = new Map(); + // try { for (const type of options) { const discriminatorValues = getDiscriminator(type.shape[discriminator]); if (!discriminatorValues) { @@ -2869,7 +3066,7 @@ class ZodTuple extends ZodType { const schema = this._def.items[itemIndex] || this._def.rest; if (!schema) return null; return schema._parse(new ParseInputLazyPath(ctx, item, ctx.path, itemIndex)); - }).filter(x => !!x); + }).filter(x => !!x); // filter nulls if (ctx.common.async) { return Promise.all(items).then(results => { return parseUtil_1.ParseStatus.mergeArray(status, results); @@ -3173,6 +3370,9 @@ class ZodFunction extends ZodType { }; const fn = ctx.data; if (this._def.returns instanceof ZodPromise) { + // Would love a way to avoid disabling this rule, but we need + // an alias (using an arrow function was what caused 2651). + // eslint-disable-next-line @typescript-eslint/no-this-alias const me = this; return (0, parseUtil_1.OK)(async function () { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { @@ -3191,6 +3391,9 @@ class ZodFunction extends ZodType { return parsedReturns; }); } else { + // Would love a way to avoid disabling this rule, but we need + // an alias (using an arrow function was what caused 2651). + // eslint-disable-next-line @typescript-eslint/no-this-alias const me = this; return (0, parseUtil_1.OK)(function () { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { @@ -3485,7 +3688,9 @@ class ZodEffects extends ZodType { } } if (effect.type === "refinement") { - const executeRefinement = acc => { + const executeRefinement = (acc + // effect: RefinementEffect + ) => { const result = effect.refinement(acc, checkCtx); if (ctx.common.async) { return Promise.resolve(result); @@ -3503,6 +3708,7 @@ class ZodEffects extends ZodType { }); if (inner.status === "aborted") return parseUtil_1.INVALID; if (inner.status === "dirty") status.dirty(); + // return value is ignored executeRefinement(inner.value); return { status: status.value, @@ -3652,6 +3858,7 @@ class ZodCatch extends ZodType { const { ctx } = this._processInputParams(input); + // newCtx is used to not collect issues from inner types in ctx const newCtx = { ...ctx, common: { @@ -3822,7 +4029,18 @@ ZodReadonly.create = (type, params) => { }; const custom = function (check) { let params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - let fatal = arguments.length > 2 ? arguments[2] : undefined; + let + /** + * @deprecated + * + * Pass `fatal` into the params object instead: + * + * ```ts + * z.string().custom((val) => val.length > 5, { fatal: false }) + * ``` + * + */ + fatal = arguments.length > 2 ? arguments[2] : undefined; if (check) return ZodAny.create().superRefine((data, ctx) => { var _a, _b; if (!check(data)) { @@ -3885,10 +4103,13 @@ var ZodFirstPartyTypeKind; ZodFirstPartyTypeKind["ZodPipeline"] = "ZodPipeline"; ZodFirstPartyTypeKind["ZodReadonly"] = "ZodReadonly"; })(ZodFirstPartyTypeKind = exports.ZodFirstPartyTypeKind || (exports.ZodFirstPartyTypeKind = {})); +// requires TS 4.4+ class Class { constructor() {} } -const instanceOfType = function (cls) { +const instanceOfType = function ( +// const instanceOfType = any>( +cls) { let params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { message: `Input not instance of ${cls.name}` }; @@ -9437,7 +9658,8 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de const { ATTR_AUTOFILL, ATTR_INPUT_TYPE, - MAX_INPUTS_PER_FORM + MAX_INPUTS_PER_FORM, + MAX_FORM_RESCANS } = _constants.constants; class Form { /** @type {import("../Form/matching").Matching} */ @@ -9485,6 +9707,31 @@ class Form { if (!entry.isIntersecting) this.removeTooltip(); } }); + this.rescanCount = 0; + this.mutObsConfig = { + childList: true, + subtree: true + }; + this.mutObs = new MutationObserver(records => { + const anythingRemoved = records.some(record => record.removedNodes.length > 0); + if (anythingRemoved) { + // Ensure we destroy the form if it's removed from the DOM + if (!this.form.isConnected) { + this.destroy(); + return; + } + // Must check for inputs because a parent may be removed and not show up in record.removedNodes + if ([...this.inputs.all].some(input => !input.isConnected)) { + // This is re-connected in recategorizeAllInputs, disconnecting here to avoid risk of re-work + this.mutObs.disconnect(); + // If any known input has been removed from the DOM, reanalyze the whole form + window.requestIdleCallback(() => { + this.formAnalyzer = new _FormAnalyzer.default(this.form, input, this.matching); + this.recategorizeAllInputs(); + }); + } + } + }); // This ensures we fire the handler again if the form is changed this.addListener(form, 'input', () => { @@ -9703,6 +9950,12 @@ class Form { * Resets our input scoring and starts from scratch */ recategorizeAllInputs() { + // If the form mutates too much, disconnect to avoid performance issues + if (this.rescanCount >= MAX_FORM_RESCANS) { + this.mutObs.disconnect(); + return; + } + this.rescanCount++; this.initialScanComplete = false; this.removeAllDecorations(); this.forgetAllInputs(); @@ -9721,11 +9974,13 @@ class Form { } // This removes all listeners to avoid memory leaks and weird behaviours destroy() { + this.mutObs.disconnect(); this.removeAllDecorations(); this.removeTooltip(); this.forgetAllInputs(); this.matching.clear(); this.intObs = null; + this.device.scanner.forms.delete(this.form); } categorizeInputs() { const selector = this.matching.cssSelector('formInputsSelector'); @@ -9740,12 +9995,17 @@ class Form { if (foundInputs.length < MAX_INPUTS_PER_FORM) { foundInputs.forEach(input => this.addInput(input)); } else { - if ((0, _autofillUtils.shouldLog)()) { - console.log('The form has too many inputs, bailing.'); - } + // This is rather extreme, but better safe than sorry + this.device.scanner.stopScanner('The form has too many inputs, bailing.'); + return; } } this.initialScanComplete = true; + + // Observe only if the container isn't the body, to avoid performance overloads + if (this.form !== document.body) { + this.mutObs.observe(this.form, this.mutObsConfig); + } } get submitButtons() { const selector = this.matching.cssSelector('submitButtonSelector'); @@ -9798,10 +10058,14 @@ class Form { // If the form has too many inputs, destroy everything to avoid performance issues if (this.inputs.all.size > MAX_INPUTS_PER_FORM) { - if ((0, _autofillUtils.shouldLog)()) { - console.log('The form has too many inputs, destroying.'); - } - this.destroy(); + this.device.scanner.stopScanner('The form has too many inputs, destroying.'); + return this; + } + + // When new inputs are added after the initial scan, reanalyze the whole form + if (this.initialScanComplete && this.rescanCount < MAX_FORM_RESCANS) { + this.formAnalyzer = new _FormAnalyzer.default(this.form, input, this.matching); + this.recategorizeAllInputs(); return this; } @@ -12026,12 +12290,12 @@ const matchingConfiguration = exports.matchingConfiguration = { strategies: { cssSelector: { selectors: { - genericTextField: 'input:not([type=button]):not([type=checkbox]):not([type=color]):not([type=date]):not([type=datetime-local]):not([type=datetime]):not([type=file]):not([type=hidden]):not([type=month]):not([type=number]):not([type=radio]):not([type=range]):not([type=reset]):not([type=search]):not([type=submit]):not([type=time]):not([type=url]):not([type=week])', + genericTextField: 'input:not([type=button]):not([type=checkbox]):not([type=color]):not([type=file]):not([type=hidden]):not([type=radio]):not([type=range]):not([type=reset]):not([type=image]):not([type=search]):not([type=submit]):not([type=time]):not([type=url]):not([type=week]):not([name^=fake i]):not([data-description^=dummy i]):not([name*=otp]):not([autocomplete="fake"]):not([placeholder^=search i]):not([type=date]):not([type=datetime-local]):not([type=datetime]):not([type=month])', submitButtonSelector: 'input[type=submit], input[type=button], input[type=image], button:not([role=switch]):not([role=link]), [role=button], a[href="#"][id*=button i], a[href="#"][id*=btn i]', - formInputsSelector: 'input:not([type=submit]):not([type=button]):not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=file]):not([type=search]):not([type=reset]):not([type=image]):not([name^=fake i]):not([data-description^=dummy i]):not([name*=otp]):not([autocomplete="fake"]), [autocomplete=username], select', + formInputsSelector: 'input:not([type=button]):not([type=checkbox]):not([type=color]):not([type=file]):not([type=hidden]):not([type=radio]):not([type=range]):not([type=reset]):not([type=image]):not([type=search]):not([type=submit]):not([type=time]):not([type=url]):not([type=week]):not([name^=fake i]):not([data-description^=dummy i]):not([name*=otp]):not([autocomplete="fake"]):not([placeholder^=search i]):not([type=date]):not([type=datetime-local]):not([type=datetime]):not([type=month]),[autocomplete=username],select', safeUniversalSelector: '*:not(select):not(option):not(script):not(noscript):not(style):not(br)', emailAddress: 'input:not([type])[name*=email i]:not([placeholder*=search i]):not([placeholder*=filter i]):not([placeholder*=subject i]):not([name*=code i]), input[type=""][name*=email i]:not([placeholder*=search i]):not([placeholder*=filter i]):not([placeholder*=subject i]):not([type=tel]), input[type=text][name*=email i]:not([placeholder*=search i]):not([placeholder*=filter i]):not([placeholder*=subject i]):not([name*=title i]):not([name*=tab i]):not([name*=code i]), input:not([type])[placeholder*=email i]:not([placeholder*=search i]):not([placeholder*=filter i]):not([placeholder*=subject i]):not([name*=code i]), input[type=text][placeholder*=email i]:not([placeholder*=search i]):not([placeholder*=filter i]):not([placeholder*=subject i]), input[type=""][placeholder*=email i]:not([placeholder*=search i]):not([placeholder*=filter i]):not([placeholder*=subject i]), input[type=email], input[type=text][aria-label*=email i]:not([aria-label*=search i]), input:not([type])[aria-label*=email i]:not([aria-label*=search i]), input[name=username][type=email], input[autocomplete=username][type=email], input[autocomplete=username][placeholder*=email i], input[autocomplete=email],input[name="mail_tel" i],input[value=email i]', - username: 'input:not([type=button]):not([type=checkbox]):not([type=color]):not([type=date]):not([type=datetime-local]):not([type=datetime]):not([type=file]):not([type=hidden]):not([type=month]):not([type=number]):not([type=radio]):not([type=range]):not([type=reset]):not([type=search]):not([type=submit]):not([type=time]):not([type=url]):not([type=week])[autocomplete^=user i],input[name=username i],input[name="loginId" i],input[name="userid" i],input[id="userid" i],input[name="user_id" i],input[name="user-id" i],input[id="login-id" i],input[id="login_id" i],input[id="loginid" i],input[name="login" i],input[name=accountname i],input[autocomplete=username i],input[name*=accountid i],input[name="j_username" i],input[id="j_username" i],input[name="uwinid" i],input[name="livedoor_id" i],input[name="ssousername" i],input[name="j_userlogin_pwd" i],input[name="user[login]" i],input[name="user" i],input[name$="_username" i],input[id="lmSsoinput" i],input[name="account_subdomain" i],input[name="masterid" i],input[name="tridField" i],input[id="signInName" i],input[id="w3c_accountsbundle_accountrequeststep1_login" i],input[id="username" i],input[name="_user" i],input[name="login_username" i],input[name^="login-user-account" i],input[id="loginusuario" i],input[name="usuario" i],input[id="UserLoginFormUsername" i],input[id="nw_username" i],input[can-field="accountName"],input[placeholder^="username" i]', + username: 'input:not([type=button]):not([type=checkbox]):not([type=color]):not([type=file]):not([type=hidden]):not([type=radio]):not([type=range]):not([type=reset]):not([type=image]):not([type=search]):not([type=submit]):not([type=time]):not([type=url]):not([type=week]):not([name^=fake i]):not([data-description^=dummy i]):not([name*=otp]):not([autocomplete="fake"]):not([placeholder^=search i]):not([type=date]):not([type=datetime-local]):not([type=datetime]):not([type=month])[autocomplete^=user i],input[name=username i],input[name="loginId" i],input[name="userid" i],input[id="userid" i],input[name="user_id" i],input[name="user-id" i],input[id="login-id" i],input[id="login_id" i],input[id="loginid" i],input[name="login" i],input[name=accountname i],input[autocomplete=username i],input[name*=accountid i],input[name="j_username" i],input[id="j_username" i],input[name="uwinid" i],input[name="livedoor_id" i],input[name="ssousername" i],input[name="j_userlogin_pwd" i],input[name="user[login]" i],input[name="user" i],input[name$="_username" i],input[id="lmSsoinput" i],input[name="account_subdomain" i],input[name="masterid" i],input[name="tridField" i],input[id="signInName" i],input[id="w3c_accountsbundle_accountrequeststep1_login" i],input[id="username" i],input[name="_user" i],input[name="login_username" i],input[name^="login-user-account" i],input[id="loginusuario" i],input[name="usuario" i],input[id="UserLoginFormUsername" i],input[id="nw_username" i],input[can-field="accountName"],input[placeholder^="username" i]', password: 'input[type=password]:not([autocomplete*=cc]):not([autocomplete=one-time-code]):not([name*=answer i]):not([name*=mfa i]):not([name*=tin i]):not([name*=card i]):not([name*=cvv i]),input.js-cloudsave-phrase', cardName: 'input[autocomplete="cc-name" i], input[autocomplete="ccname" i], input[name="ccname" i], input[name="cc-name" i], input[name="ppw-accountHolderName" i], input[id*=cardname i], input[id*=card-name i], input[id*=card_name i]', cardNumber: 'input[autocomplete="cc-number" i], input[autocomplete="ccnumber" i], input[autocomplete="cardnumber" i], input[autocomplete="card-number" i], input[name="ccnumber" i], input[name="cc-number" i], input[name*=card i][name*=number i], input[name*=cardnumber i], input[id*=cardnumber i], input[id*=card-number i], input[id*=card_number i]', @@ -12605,7 +12869,9 @@ class Matching { if (this.subtypeFromMatchers('password', input)) { // Any other input type is likely a false match // Arguably "text" should be as well, but it can be used for password reveal fields - if (['password', 'text'].includes(input.type) && input.name !== 'email' && input.placeholder !== 'Username') { + if (['password', 'text'].includes(input.type) && input.name !== 'email' && + // pcsretirement.com, improper use of the for attribute + input.name !== 'Username') { return 'credentials.password'; } } @@ -13087,7 +13353,8 @@ function getInputSubtype(input) { */ const removeExcessWhitespace = function () { let string = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; - if (!string) return ''; + // The length check is extra safety to avoid trimming strings that would be discarded anyway + if (!string || string.length > TEXT_LENGTH_CUTOFF + 50) return ''; return string.replace(/\n/g, ' ').replace(/\s{2,}/g, ' ').trim(); }; @@ -13653,6 +13920,7 @@ const { * findEligibleInputs(context): Scanner; * matching: import("./Form/matching").Matching; * options: ScannerOptions; + * stopScanner: (reason: string, ...rest: any) => void; * }} Scanner * * @typedef {{ @@ -13794,7 +14062,7 @@ class DefaultScanner { /** * Stops scanning, switches off the mutation observer and clears all forms * @param {string} reason - * @param {...any} rest + * @param {any} rest */ stopScanner(reason) { this.stopped = true; @@ -13835,9 +14103,15 @@ class DefaultScanner { } } } + + /** + * Max number of nodes we want to traverse upwards, critical to avoid enclosing large portions of the DOM + * @type {number} + */ + let traversalLayerCount = 0; let element = input; // traverse the DOM to search for related inputs - while (element.parentElement && element.parentElement !== document.documentElement) { + while (traversalLayerCount <= 5 && element.parentElement && element.parentElement !== document.documentElement) { // Avoid overlapping containers or forms const siblingForm = element.parentElement?.querySelector('form'); if (siblingForm && siblingForm !== element) { @@ -13851,6 +14125,7 @@ class DefaultScanner { // found related input, return common ancestor return element; } + traversalLayerCount++; } return input; } @@ -16560,7 +16835,7 @@ const constants = exports.constants = { MAX_INPUTS_PER_PAGE: 100, MAX_FORMS_PER_PAGE: 30, MAX_INPUTS_PER_FORM: 80, - MAX_FORM_MUT_OBS_COUNT: 50 + MAX_FORM_RESCANS: 50 }; },{}],65:[function(require,module,exports){ diff --git a/node_modules/@duckduckgo/autofill/dist/autofill.js b/node_modules/@duckduckgo/autofill/dist/autofill.js index f8f0227688ec..ca382cd2aad0 100644 --- a/node_modules/@duckduckgo/autofill/dist/autofill.js +++ b/node_modules/@duckduckgo/autofill/dist/autofill.js @@ -5492,7 +5492,8 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de const { ATTR_AUTOFILL, ATTR_INPUT_TYPE, - MAX_INPUTS_PER_FORM + MAX_INPUTS_PER_FORM, + MAX_FORM_RESCANS } = _constants.constants; class Form { /** @type {import("../Form/matching").Matching} */ @@ -5540,6 +5541,31 @@ class Form { if (!entry.isIntersecting) this.removeTooltip(); } }); + this.rescanCount = 0; + this.mutObsConfig = { + childList: true, + subtree: true + }; + this.mutObs = new MutationObserver(records => { + const anythingRemoved = records.some(record => record.removedNodes.length > 0); + if (anythingRemoved) { + // Ensure we destroy the form if it's removed from the DOM + if (!this.form.isConnected) { + this.destroy(); + return; + } + // Must check for inputs because a parent may be removed and not show up in record.removedNodes + if ([...this.inputs.all].some(input => !input.isConnected)) { + // This is re-connected in recategorizeAllInputs, disconnecting here to avoid risk of re-work + this.mutObs.disconnect(); + // If any known input has been removed from the DOM, reanalyze the whole form + window.requestIdleCallback(() => { + this.formAnalyzer = new _FormAnalyzer.default(this.form, input, this.matching); + this.recategorizeAllInputs(); + }); + } + } + }); // This ensures we fire the handler again if the form is changed this.addListener(form, 'input', () => { @@ -5758,6 +5784,12 @@ class Form { * Resets our input scoring and starts from scratch */ recategorizeAllInputs() { + // If the form mutates too much, disconnect to avoid performance issues + if (this.rescanCount >= MAX_FORM_RESCANS) { + this.mutObs.disconnect(); + return; + } + this.rescanCount++; this.initialScanComplete = false; this.removeAllDecorations(); this.forgetAllInputs(); @@ -5776,11 +5808,13 @@ class Form { } // This removes all listeners to avoid memory leaks and weird behaviours destroy() { + this.mutObs.disconnect(); this.removeAllDecorations(); this.removeTooltip(); this.forgetAllInputs(); this.matching.clear(); this.intObs = null; + this.device.scanner.forms.delete(this.form); } categorizeInputs() { const selector = this.matching.cssSelector('formInputsSelector'); @@ -5795,12 +5829,17 @@ class Form { if (foundInputs.length < MAX_INPUTS_PER_FORM) { foundInputs.forEach(input => this.addInput(input)); } else { - if ((0, _autofillUtils.shouldLog)()) { - console.log('The form has too many inputs, bailing.'); - } + // This is rather extreme, but better safe than sorry + this.device.scanner.stopScanner('The form has too many inputs, bailing.'); + return; } } this.initialScanComplete = true; + + // Observe only if the container isn't the body, to avoid performance overloads + if (this.form !== document.body) { + this.mutObs.observe(this.form, this.mutObsConfig); + } } get submitButtons() { const selector = this.matching.cssSelector('submitButtonSelector'); @@ -5853,10 +5892,14 @@ class Form { // If the form has too many inputs, destroy everything to avoid performance issues if (this.inputs.all.size > MAX_INPUTS_PER_FORM) { - if ((0, _autofillUtils.shouldLog)()) { - console.log('The form has too many inputs, destroying.'); - } - this.destroy(); + this.device.scanner.stopScanner('The form has too many inputs, destroying.'); + return this; + } + + // When new inputs are added after the initial scan, reanalyze the whole form + if (this.initialScanComplete && this.rescanCount < MAX_FORM_RESCANS) { + this.formAnalyzer = new _FormAnalyzer.default(this.form, input, this.matching); + this.recategorizeAllInputs(); return this; } @@ -8081,12 +8124,12 @@ const matchingConfiguration = exports.matchingConfiguration = { strategies: { cssSelector: { selectors: { - genericTextField: 'input:not([type=button]):not([type=checkbox]):not([type=color]):not([type=date]):not([type=datetime-local]):not([type=datetime]):not([type=file]):not([type=hidden]):not([type=month]):not([type=number]):not([type=radio]):not([type=range]):not([type=reset]):not([type=search]):not([type=submit]):not([type=time]):not([type=url]):not([type=week])', + genericTextField: 'input:not([type=button]):not([type=checkbox]):not([type=color]):not([type=file]):not([type=hidden]):not([type=radio]):not([type=range]):not([type=reset]):not([type=image]):not([type=search]):not([type=submit]):not([type=time]):not([type=url]):not([type=week]):not([name^=fake i]):not([data-description^=dummy i]):not([name*=otp]):not([autocomplete="fake"]):not([placeholder^=search i]):not([type=date]):not([type=datetime-local]):not([type=datetime]):not([type=month])', submitButtonSelector: 'input[type=submit], input[type=button], input[type=image], button:not([role=switch]):not([role=link]), [role=button], a[href="#"][id*=button i], a[href="#"][id*=btn i]', - formInputsSelector: 'input:not([type=submit]):not([type=button]):not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=file]):not([type=search]):not([type=reset]):not([type=image]):not([name^=fake i]):not([data-description^=dummy i]):not([name*=otp]):not([autocomplete="fake"]), [autocomplete=username], select', + formInputsSelector: 'input:not([type=button]):not([type=checkbox]):not([type=color]):not([type=file]):not([type=hidden]):not([type=radio]):not([type=range]):not([type=reset]):not([type=image]):not([type=search]):not([type=submit]):not([type=time]):not([type=url]):not([type=week]):not([name^=fake i]):not([data-description^=dummy i]):not([name*=otp]):not([autocomplete="fake"]):not([placeholder^=search i]):not([type=date]):not([type=datetime-local]):not([type=datetime]):not([type=month]),[autocomplete=username],select', safeUniversalSelector: '*:not(select):not(option):not(script):not(noscript):not(style):not(br)', emailAddress: 'input:not([type])[name*=email i]:not([placeholder*=search i]):not([placeholder*=filter i]):not([placeholder*=subject i]):not([name*=code i]), input[type=""][name*=email i]:not([placeholder*=search i]):not([placeholder*=filter i]):not([placeholder*=subject i]):not([type=tel]), input[type=text][name*=email i]:not([placeholder*=search i]):not([placeholder*=filter i]):not([placeholder*=subject i]):not([name*=title i]):not([name*=tab i]):not([name*=code i]), input:not([type])[placeholder*=email i]:not([placeholder*=search i]):not([placeholder*=filter i]):not([placeholder*=subject i]):not([name*=code i]), input[type=text][placeholder*=email i]:not([placeholder*=search i]):not([placeholder*=filter i]):not([placeholder*=subject i]), input[type=""][placeholder*=email i]:not([placeholder*=search i]):not([placeholder*=filter i]):not([placeholder*=subject i]), input[type=email], input[type=text][aria-label*=email i]:not([aria-label*=search i]), input:not([type])[aria-label*=email i]:not([aria-label*=search i]), input[name=username][type=email], input[autocomplete=username][type=email], input[autocomplete=username][placeholder*=email i], input[autocomplete=email],input[name="mail_tel" i],input[value=email i]', - username: 'input:not([type=button]):not([type=checkbox]):not([type=color]):not([type=date]):not([type=datetime-local]):not([type=datetime]):not([type=file]):not([type=hidden]):not([type=month]):not([type=number]):not([type=radio]):not([type=range]):not([type=reset]):not([type=search]):not([type=submit]):not([type=time]):not([type=url]):not([type=week])[autocomplete^=user i],input[name=username i],input[name="loginId" i],input[name="userid" i],input[id="userid" i],input[name="user_id" i],input[name="user-id" i],input[id="login-id" i],input[id="login_id" i],input[id="loginid" i],input[name="login" i],input[name=accountname i],input[autocomplete=username i],input[name*=accountid i],input[name="j_username" i],input[id="j_username" i],input[name="uwinid" i],input[name="livedoor_id" i],input[name="ssousername" i],input[name="j_userlogin_pwd" i],input[name="user[login]" i],input[name="user" i],input[name$="_username" i],input[id="lmSsoinput" i],input[name="account_subdomain" i],input[name="masterid" i],input[name="tridField" i],input[id="signInName" i],input[id="w3c_accountsbundle_accountrequeststep1_login" i],input[id="username" i],input[name="_user" i],input[name="login_username" i],input[name^="login-user-account" i],input[id="loginusuario" i],input[name="usuario" i],input[id="UserLoginFormUsername" i],input[id="nw_username" i],input[can-field="accountName"],input[placeholder^="username" i]', + username: 'input:not([type=button]):not([type=checkbox]):not([type=color]):not([type=file]):not([type=hidden]):not([type=radio]):not([type=range]):not([type=reset]):not([type=image]):not([type=search]):not([type=submit]):not([type=time]):not([type=url]):not([type=week]):not([name^=fake i]):not([data-description^=dummy i]):not([name*=otp]):not([autocomplete="fake"]):not([placeholder^=search i]):not([type=date]):not([type=datetime-local]):not([type=datetime]):not([type=month])[autocomplete^=user i],input[name=username i],input[name="loginId" i],input[name="userid" i],input[id="userid" i],input[name="user_id" i],input[name="user-id" i],input[id="login-id" i],input[id="login_id" i],input[id="loginid" i],input[name="login" i],input[name=accountname i],input[autocomplete=username i],input[name*=accountid i],input[name="j_username" i],input[id="j_username" i],input[name="uwinid" i],input[name="livedoor_id" i],input[name="ssousername" i],input[name="j_userlogin_pwd" i],input[name="user[login]" i],input[name="user" i],input[name$="_username" i],input[id="lmSsoinput" i],input[name="account_subdomain" i],input[name="masterid" i],input[name="tridField" i],input[id="signInName" i],input[id="w3c_accountsbundle_accountrequeststep1_login" i],input[id="username" i],input[name="_user" i],input[name="login_username" i],input[name^="login-user-account" i],input[id="loginusuario" i],input[name="usuario" i],input[id="UserLoginFormUsername" i],input[id="nw_username" i],input[can-field="accountName"],input[placeholder^="username" i]', password: 'input[type=password]:not([autocomplete*=cc]):not([autocomplete=one-time-code]):not([name*=answer i]):not([name*=mfa i]):not([name*=tin i]):not([name*=card i]):not([name*=cvv i]),input.js-cloudsave-phrase', cardName: 'input[autocomplete="cc-name" i], input[autocomplete="ccname" i], input[name="ccname" i], input[name="cc-name" i], input[name="ppw-accountHolderName" i], input[id*=cardname i], input[id*=card-name i], input[id*=card_name i]', cardNumber: 'input[autocomplete="cc-number" i], input[autocomplete="ccnumber" i], input[autocomplete="cardnumber" i], input[autocomplete="card-number" i], input[name="ccnumber" i], input[name="cc-number" i], input[name*=card i][name*=number i], input[name*=cardnumber i], input[id*=cardnumber i], input[id*=card-number i], input[id*=card_number i]', @@ -8660,7 +8703,9 @@ class Matching { if (this.subtypeFromMatchers('password', input)) { // Any other input type is likely a false match // Arguably "text" should be as well, but it can be used for password reveal fields - if (['password', 'text'].includes(input.type) && input.name !== 'email' && input.placeholder !== 'Username') { + if (['password', 'text'].includes(input.type) && input.name !== 'email' && + // pcsretirement.com, improper use of the for attribute + input.name !== 'Username') { return 'credentials.password'; } } @@ -9142,7 +9187,8 @@ function getInputSubtype(input) { */ const removeExcessWhitespace = function () { let string = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; - if (!string) return ''; + // The length check is extra safety to avoid trimming strings that would be discarded anyway + if (!string || string.length > TEXT_LENGTH_CUTOFF + 50) return ''; return string.replace(/\n/g, ' ').replace(/\s{2,}/g, ' ').trim(); }; @@ -9708,6 +9754,7 @@ const { * findEligibleInputs(context): Scanner; * matching: import("./Form/matching").Matching; * options: ScannerOptions; + * stopScanner: (reason: string, ...rest: any) => void; * }} Scanner * * @typedef {{ @@ -9849,7 +9896,7 @@ class DefaultScanner { /** * Stops scanning, switches off the mutation observer and clears all forms * @param {string} reason - * @param {...any} rest + * @param {any} rest */ stopScanner(reason) { this.stopped = true; @@ -9890,9 +9937,15 @@ class DefaultScanner { } } } + + /** + * Max number of nodes we want to traverse upwards, critical to avoid enclosing large portions of the DOM + * @type {number} + */ + let traversalLayerCount = 0; let element = input; // traverse the DOM to search for related inputs - while (element.parentElement && element.parentElement !== document.documentElement) { + while (traversalLayerCount <= 5 && element.parentElement && element.parentElement !== document.documentElement) { // Avoid overlapping containers or forms const siblingForm = element.parentElement?.querySelector('form'); if (siblingForm && siblingForm !== element) { @@ -9906,6 +9959,7 @@ class DefaultScanner { // found related input, return common ancestor return element; } + traversalLayerCount++; } return input; } @@ -12615,7 +12669,7 @@ const constants = exports.constants = { MAX_INPUTS_PER_PAGE: 100, MAX_FORMS_PER_PAGE: 30, MAX_INPUTS_PER_FORM: 80, - MAX_FORM_MUT_OBS_COUNT: 50 + MAX_FORM_RESCANS: 50 }; },{}],55:[function(require,module,exports){ diff --git a/package-lock.json b/package-lock.json index db169066a0d6..5a22a205daf0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "dependencies": { "@duckduckgo/autoconsent": "^5.1.0", - "@duckduckgo/autofill": "github:duckduckgo/duckduckgo-autofill#9.0.0", + "@duckduckgo/autofill": "github:duckduckgo/duckduckgo-autofill#9.1.0", "@duckduckgo/content-scope-scripts": "github:duckduckgo/content-scope-scripts#4.41.0", "@duckduckgo/privacy-dashboard": "github:duckduckgo/privacy-dashboard#1.7.0", "@duckduckgo/privacy-reference-tests": "github:duckduckgo/privacy-reference-tests#1698156591" @@ -64,7 +64,7 @@ "integrity": "sha512-/ZUdNt+FLhtT40f53Pl/TwOLX1Rr4vCyzgDXQjtXBHF7vSaQJLRdkDkiEm4P24HAxNbg+WGeleJUiIEyQgfp2A==" }, "node_modules/@duckduckgo/autofill": { - "resolved": "git+ssh://git@github.com/duckduckgo/duckduckgo-autofill.git#c8e895c8fd50dc76e8d8dc827a636ad77b7f46ff", + "resolved": "git+ssh://git@github.com/duckduckgo/duckduckgo-autofill.git#3b8211a59020c875422c65937e41f9b2536606e1", "hasInstallScript": true, "license": "Apache-2.0" }, diff --git a/package.json b/package.json index aa248c9c818f..2fd64d1d4b7e 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@duckduckgo/autoconsent": "^5.1.0", - "@duckduckgo/autofill": "github:duckduckgo/duckduckgo-autofill#9.0.0", + "@duckduckgo/autofill": "github:duckduckgo/duckduckgo-autofill#9.1.0", "@duckduckgo/content-scope-scripts": "github:duckduckgo/content-scope-scripts#4.41.0", "@duckduckgo/privacy-dashboard": "github:duckduckgo/privacy-dashboard#1.7.0", "@duckduckgo/privacy-reference-tests": "github:duckduckgo/privacy-reference-tests#1698156591"