1function hookLocationAccess(onAccess) { 2 const originalDescriptors = new Map(); 3 const targets = [ 4 { 5 obj: window.location, 6 props: ['href', 'pathname', 'search', 'hash', 'origin'] 7 }, 8 { 9 obj: document, 10 props: ['URL', 'documentURI'] 11 } // document.URL is often synonymous with location.href 12 ]; 13 14 targets.forEach(({ 15 obj, 16 props 17 }) => { 18 props.forEach(prop => { 19 try { 20 // Get the original property descriptor 21 const originalDescriptor = Object.getOwnPropertyDescriptor(obj, prop); 22 23 // If the property doesn't exist, is not configurable, or has no getter/value, skip it. 24 if (!originalDescriptor || !originalDescriptor.configurable || (!originalDescriptor.get && 25 !originalDescriptor.value)) { 26 console.warn(`[HookLocation] Could not hook property "${prop}" on`, obj, 27 `- not found, not configurable, or no getter/value.`); 28 return; 29 } 30 31 // Store the original descriptor for restoration 32 originalDescriptors.set([obj, prop], originalDescriptor); 33 34 // Define the new property 35 Object.defineProperty(obj, prop, { 36 configurable: true, // Keep configurable so we can unhook 37 enumerable: originalDescriptor.enumerable, // Keep original enumerability 38 get: function () { 39 // Call the original getter or return the original value 40 const originalValue = originalDescriptor.get ? 41 originalDescriptor.get.call(this) : // Use .call(this) to maintain context 42 originalDescriptor.value; 43 44 // Call the user's hook function 45 const modifiedValue = onAccess(prop, originalValue); 46 47 // Return the modified value if the hook returns something, otherwise return the original 48 return modifiedValue !== undefined ? modifiedValue : originalValue; 49 } 50 // Note: We are only hooking the getter (read). Setting these properties is not hooked by this code. 51 }); 52 53 console.log(`[HookLocation] Successfully hooked property "${prop}" on`, obj); 54 55 } catch (e) { 56 console.error(`[HookLocation] Error hooking property "${prop}" on`, obj, e); 57 } 58 }); 59 }); 60 61 /** 62 * Restores the original property definitions. 63 */ 64 const unhook = () => { 65 originalDescriptors.forEach((originalDescriptor, [obj, prop]) => { 66 try { 67 Object.defineProperty(obj, prop, originalDescriptor); 68 console.log(`[HookLocation] Successfully unhooked property "${prop}" on`, obj); 69 } catch (e) { 70 console.error(`[HookLocation] Error unhooking property "${prop}" on`, obj, e); 71 } 72 }); 73 originalDescriptors.clear(); // Clear the map after unhooking 74 }; 75 76 return unhook; // Return the unhook function 77} 78 79// const restoreOriginal = hookLocationAccess((propertyName, originalValue) => { 80// console.log(`[HOOKED ACCESS] Property "${propertyName}" accessed. Original value: "${originalValue}"`); 81// debugger; 82// return undefined; 83// });
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.