( key: T, )
| 55 | }; |
| 56 | |
| 57 | export function getUntaintedPrototype<T extends keyof BasePrototypeCache>( |
| 58 | key: T, |
| 59 | ): BasePrototypeCache[T] { |
| 60 | if (untaintedBasePrototype[key]) |
| 61 | return untaintedBasePrototype[key] as BasePrototypeCache[T]; |
| 62 | |
| 63 | const defaultObj = globalThis[key] as TypeofPrototypeOwner; |
| 64 | const defaultPrototype = defaultObj.prototype as BasePrototypeCache[T]; |
| 65 | |
| 66 | // use list of testable accessors to check if the prototype is tainted |
| 67 | const accessorNames = |
| 68 | key in testableAccessors ? testableAccessors[key] : undefined; |
| 69 | const isUntaintedAccessors = Boolean( |
| 70 | accessorNames && |
| 71 | // @ts-expect-error 2345 |
| 72 | accessorNames.every((accessor: keyof typeof defaultPrototype) => |
| 73 | Boolean( |
| 74 | Object.getOwnPropertyDescriptor(defaultPrototype, accessor) |
| 75 | ?.get?.toString() |
| 76 | .includes('[native code]'), |
| 77 | ), |
| 78 | ), |
| 79 | ); |
| 80 | |
| 81 | const methodNames = key in testableMethods ? testableMethods[key] : undefined; |
| 82 | const isUntaintedMethods = Boolean( |
| 83 | methodNames && |
| 84 | methodNames.every( |
| 85 | // @ts-expect-error 2345 |
| 86 | (method: keyof typeof defaultPrototype) => |
| 87 | typeof defaultPrototype[method] === 'function' && |
| 88 | defaultPrototype[method]?.toString().includes('[native code]'), |
| 89 | ), |
| 90 | ); |
| 91 | |
| 92 | if (isUntaintedAccessors && isUntaintedMethods && !isAngularZonePresent()) { |
| 93 | untaintedBasePrototype[key] = defaultObj.prototype as BasePrototypeCache[T]; |
| 94 | return defaultObj.prototype as BasePrototypeCache[T]; |
| 95 | } |
| 96 | |
| 97 | try { |
| 98 | const iframeEl = document.createElement('iframe'); |
| 99 | iframeEl.style.display = 'none'; |
| 100 | document.body.appendChild(iframeEl); |
| 101 | const win = iframeEl.contentWindow; |
| 102 | if (!win) return defaultObj.prototype as BasePrototypeCache[T]; |
| 103 | |
| 104 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any |
| 105 | const untaintedObject = (win as any)[key] |
| 106 | .prototype as BasePrototypeCache[T]; |
| 107 | |
| 108 | if (!untaintedObject) { |
| 109 | iframeEl.remove(); |
| 110 | return defaultPrototype; |
| 111 | } |
| 112 | |
| 113 | // WebKit/Safari: WebKit tears down an iframe's ScriptExecutionContext when it is |
| 114 | // detached from the DOM. MutationObserver.deliver() silently drops callbacks when |
no test coverage detected