mirror of
https://github.com/xenos1337/httptoolkit-patcher.git
synced 2026-07-15 16:20:02 +02:00
refactor(patcher): use local inject.js and simplify injection mechanism
This commit is contained in:
@@ -1,206 +1,168 @@
|
||||
(function injectPageContextHooks() {
|
||||
const injectionCode = `
|
||||
(function() {
|
||||
console.log("[PAGE-INJECT] Installing hooks in page context");
|
||||
|
||||
const propertyHooks = {
|
||||
isPaidUser: true,
|
||||
isLoggedIn: true,
|
||||
userHasSubscription: true,
|
||||
userEmail: "hi@httptoolkit.com",
|
||||
mightBePaidUser: true,
|
||||
isPastDueUser: false,
|
||||
userSubscription: {
|
||||
status: "active",
|
||||
plan: "pro",
|
||||
sku: "sku",
|
||||
tierCode: "pro",
|
||||
interval: "monthly",
|
||||
quantity: 1,
|
||||
expiry: new Date("2999-01-01"),
|
||||
updateBillingDetailsUrl: "https://httptoolkit.com/",
|
||||
cancelSubscriptionUrl: "https://httptoolkit.com/",
|
||||
lastReceiptUrl: "https://httptoolkit.com/",
|
||||
canManageSubscription: true
|
||||
(function () {
|
||||
console.log("[PAGE-INJECT] Installing hooks in page context");
|
||||
|
||||
const propertyHooks = {
|
||||
isPaidUser: true,
|
||||
isLoggedIn: true,
|
||||
userHasSubscription: true,
|
||||
userEmail: "hi@httptoolkit.com",
|
||||
mightBePaidUser: true,
|
||||
isPastDueUser: false,
|
||||
isStatusUnexpired: true,
|
||||
userSubscription: {
|
||||
state: "fulfilled",
|
||||
status: "active",
|
||||
plan: "pro",
|
||||
sku: "sku",
|
||||
tierCode: "pro",
|
||||
interval: "monthly",
|
||||
quantity: 1,
|
||||
expiry: new Date(new Date().setFullYear(new Date().getFullYear() + 10)),
|
||||
updateBillingDetailsUrl: "https://httptoolkit.com/",
|
||||
cancelSubscriptionUrl: "https://httptoolkit.com/",
|
||||
lastReceiptUrl: "https://httptoolkit.com/",
|
||||
canManageSubscription: true,
|
||||
},
|
||||
};
|
||||
|
||||
const hookedObjects = new WeakSet();
|
||||
|
||||
// Override Object.defineProperty to intercept all property definitions
|
||||
const originalDefineProperty = Object.defineProperty;
|
||||
Object.defineProperty = function (target, prop, descriptor) {
|
||||
// Intercept our target properties
|
||||
if (prop in propertyHooks) {
|
||||
console.log("[PAGE-INJECT] Intercepting defineProperty for: " + prop);
|
||||
|
||||
if (descriptor && descriptor.get) {
|
||||
const originalGetter = descriptor.get;
|
||||
descriptor.get = function () {
|
||||
const originalValue = originalGetter.call(this);
|
||||
console.log("[PAGE-INJECT] " + prop + " getter called, original=" + originalValue + ", returning=" + JSON.stringify(propertyHooks[prop]));
|
||||
return propertyHooks[prop];
|
||||
};
|
||||
} else if (descriptor && descriptor.value !== undefined) {
|
||||
console.log("[PAGE-INJECT] " + prop + " value being defined, overriding to " + JSON.stringify(propertyHooks[prop]));
|
||||
descriptor.value = propertyHooks[prop];
|
||||
}
|
||||
}
|
||||
|
||||
return originalDefineProperty.call(this, target, prop, descriptor);
|
||||
};
|
||||
|
||||
// Hook Object.defineProperties too
|
||||
const originalDefineProperties = Object.defineProperties;
|
||||
Object.defineProperties = function (target, props) {
|
||||
for (let prop in props) {
|
||||
if (prop in propertyHooks) {
|
||||
console.log("[PAGE-INJECT] Intercepting defineProperties for: " + prop);
|
||||
if (props[prop].get) {
|
||||
const originalGetter = props[prop].get;
|
||||
props[prop].get = function () {
|
||||
const originalValue = originalGetter.call(this);
|
||||
console.log("[PAGE-INJECT] " + prop + " getter called, original=" + originalValue + ", returning=" + JSON.stringify(propertyHooks[prop]));
|
||||
return propertyHooks[prop];
|
||||
};
|
||||
} else if (props[prop].value !== undefined) {
|
||||
props[prop].value = propertyHooks[prop];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return originalDefineProperties.call(this, target, props);
|
||||
};
|
||||
|
||||
const hookedObjects = new WeakSet();
|
||||
|
||||
// Override Object.defineProperty to intercept all property definitions
|
||||
const originalDefineProperty = Object.defineProperty;
|
||||
Object.defineProperty = function(target, prop, descriptor) {
|
||||
// Intercept our target properties
|
||||
if (prop in propertyHooks) {
|
||||
console.log("[PAGE-INJECT] Intercepting defineProperty for: " + prop);
|
||||
|
||||
if (descriptor && descriptor.get) {
|
||||
const originalGetter = descriptor.get;
|
||||
descriptor.get = function() {
|
||||
const originalValue = originalGetter.call(this);
|
||||
console.log("[PAGE-INJECT] " + prop + " getter called, original=" + originalValue + ", returning=" + JSON.stringify(propertyHooks[prop]));
|
||||
return propertyHooks[prop];
|
||||
};
|
||||
} else if (descriptor && descriptor.value !== undefined) {
|
||||
console.log("[PAGE-INJECT] " + prop + " value being defined, overriding to " + JSON.stringify(propertyHooks[prop]));
|
||||
descriptor.value = propertyHooks[prop];
|
||||
}
|
||||
}
|
||||
|
||||
return originalDefineProperty.call(this, target, prop, descriptor);
|
||||
};
|
||||
// Periodically scan and patch existing objects
|
||||
function scanAndPatch() {
|
||||
// Search through window and common store locations
|
||||
const searchPaths = [window, window.accountStore, window.stores && window.stores.accountStore, window.appState && window.appState.accountStore];
|
||||
|
||||
// Hook Object.defineProperties too
|
||||
const originalDefineProperties = Object.defineProperties;
|
||||
Object.defineProperties = function(target, props) {
|
||||
for (let prop in props) {
|
||||
if (prop in propertyHooks) {
|
||||
console.log("[PAGE-INJECT] Intercepting defineProperties for: " + prop);
|
||||
if (props[prop].get) {
|
||||
const originalGetter = props[prop].get;
|
||||
props[prop].get = function() {
|
||||
const originalValue = originalGetter.call(this);
|
||||
console.log("[PAGE-INJECT] " + prop + " getter called, original=" + originalValue + ", returning=" + JSON.stringify(propertyHooks[prop]));
|
||||
return propertyHooks[prop];
|
||||
};
|
||||
} else if (props[prop].value !== undefined) {
|
||||
props[prop].value = propertyHooks[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
return originalDefineProperties.call(this, target, props);
|
||||
};
|
||||
searchPaths.forEach((obj, idx) => {
|
||||
if (!obj || hookedObjects.has(obj)) return;
|
||||
|
||||
// Periodically scan and patch existing objects
|
||||
function scanAndPatch() {
|
||||
// Search through window and common store locations
|
||||
const searchPaths = [
|
||||
window,
|
||||
window.accountStore,
|
||||
window.stores && window.stores.accountStore,
|
||||
window.appState && window.appState.accountStore,
|
||||
];
|
||||
|
||||
searchPaths.forEach((obj, idx) => {
|
||||
if (!obj || hookedObjects.has(obj)) return;
|
||||
|
||||
try {
|
||||
Object.keys(propertyHooks).forEach(prop => {
|
||||
try {
|
||||
Object.keys(propertyHooks).forEach(prop => {
|
||||
try {
|
||||
const desc = Object.getOwnPropertyDescriptor(obj, prop);
|
||||
if (desc && desc.configurable) {
|
||||
console.log("[PAGE-INJECT] Found " + prop + " on object #" + idx + ", patching...");
|
||||
|
||||
if (desc.get) {
|
||||
const desc = Object.getOwnPropertyDescriptor(obj, prop);
|
||||
if (desc && desc.configurable) {
|
||||
console.log("[PAGE-INJECT] Found " + prop + " on object #" + idx + ", patching...");
|
||||
|
||||
if (desc.get) {
|
||||
const originalGetter = desc.get;
|
||||
Object.defineProperty(obj, prop, {
|
||||
get: function () {
|
||||
const originalValue = originalGetter.call(this);
|
||||
console.log("[PAGE-INJECT] " + prop + " getter intercepted, original=" + originalValue + ", returning=" + JSON.stringify(propertyHooks[prop]));
|
||||
return propertyHooks[prop];
|
||||
},
|
||||
set: desc.set,
|
||||
configurable: true,
|
||||
enumerable: desc.enumerable,
|
||||
});
|
||||
} else if (desc.writable) {
|
||||
obj[prop] = propertyHooks[prop];
|
||||
console.log("[PAGE-INJECT] " + prop + " value set to " + JSON.stringify(propertyHooks[prop]));
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignore individual property errors
|
||||
}
|
||||
});
|
||||
|
||||
hookedObjects.add(obj);
|
||||
} catch (e) {
|
||||
// Ignore object access errors
|
||||
}
|
||||
});
|
||||
|
||||
// Also try to find accountStore by scanning window properties
|
||||
try {
|
||||
for (let key in window) {
|
||||
try {
|
||||
const obj = window[key];
|
||||
if (obj && typeof obj === "object" && "accountStore" in obj) {
|
||||
console.log("[PAGE-INJECT] Found accountStore in window." + key);
|
||||
const store = obj.accountStore;
|
||||
if (store && !hookedObjects.has(store)) {
|
||||
Object.keys(propertyHooks).forEach(prop => {
|
||||
try {
|
||||
const desc = Object.getOwnPropertyDescriptor(store, prop);
|
||||
if (desc && desc.configurable && desc.get) {
|
||||
const originalGetter = desc.get;
|
||||
Object.defineProperty(obj, prop, {
|
||||
get: function() {
|
||||
Object.defineProperty(store, prop, {
|
||||
get: function () {
|
||||
const originalValue = originalGetter.call(this);
|
||||
console.log("[PAGE-INJECT] " + prop + " getter intercepted, original=" + originalValue + ", returning=" + JSON.stringify(propertyHooks[prop]));
|
||||
console.log("[PAGE-INJECT] accountStore." + prop + " intercepted, original=" + originalValue + ", returning=" + JSON.stringify(propertyHooks[prop]));
|
||||
return propertyHooks[prop];
|
||||
},
|
||||
set: desc.set,
|
||||
configurable: true,
|
||||
enumerable: desc.enumerable
|
||||
enumerable: desc.enumerable,
|
||||
});
|
||||
} else if (desc.writable) {
|
||||
obj[prop] = propertyHooks[prop];
|
||||
console.log("[PAGE-INJECT] " + prop + " value set to " + JSON.stringify(propertyHooks[prop]));
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignore individual property errors
|
||||
}
|
||||
});
|
||||
|
||||
hookedObjects.add(obj);
|
||||
} catch (e) {
|
||||
// Ignore object access errors
|
||||
}
|
||||
});
|
||||
|
||||
// Also try to find accountStore by scanning window properties
|
||||
try {
|
||||
for (let key in window) {
|
||||
try {
|
||||
const obj = window[key];
|
||||
if (obj && typeof obj === 'object' && 'accountStore' in obj) {
|
||||
console.log("[PAGE-INJECT] Found accountStore in window." + key);
|
||||
const store = obj.accountStore;
|
||||
if (store && !hookedObjects.has(store)) {
|
||||
Object.keys(propertyHooks).forEach(prop => {
|
||||
try {
|
||||
const desc = Object.getOwnPropertyDescriptor(store, prop);
|
||||
if (desc && desc.configurable && desc.get) {
|
||||
const originalGetter = desc.get;
|
||||
Object.defineProperty(store, prop, {
|
||||
get: function() {
|
||||
const originalValue = originalGetter.call(this);
|
||||
console.log("[PAGE-INJECT] accountStore." + prop + " intercepted, original=" + originalValue + ", returning=" + JSON.stringify(propertyHooks[prop]));
|
||||
return propertyHooks[prop];
|
||||
},
|
||||
set: desc.set,
|
||||
configurable: true,
|
||||
enumerable: desc.enumerable
|
||||
});
|
||||
}
|
||||
} catch (e) {}
|
||||
});
|
||||
hookedObjects.add(store);
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
} catch (e) {}
|
||||
});
|
||||
hookedObjects.add(store);
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// Run initial scan
|
||||
scanAndPatch();
|
||||
|
||||
// Scan periodically for late-initialized stores
|
||||
let scanCount = 0;
|
||||
const scanInterval = setInterval(() => {
|
||||
scanCount++;
|
||||
scanAndPatch();
|
||||
|
||||
if (scanCount >= 10) {
|
||||
clearInterval(scanInterval);
|
||||
console.log("[PAGE-INJECT] Stopped periodic scanning after 10 attempts");
|
||||
}
|
||||
}, 100);
|
||||
|
||||
console.log("[PAGE-INJECT] Hooks installed successfully");
|
||||
})();
|
||||
`;
|
||||
|
||||
function injectScript() {
|
||||
try {
|
||||
const script = document.createElement('script');
|
||||
script.textContent = injectionCode;
|
||||
(document.head || document.documentElement).appendChild(script);
|
||||
script.remove(); // Clean up the script tag
|
||||
console.log("[PRELOAD] Injected page context hooks");
|
||||
} catch (e) {
|
||||
console.error("[PRELOAD] Failed to inject hooks:", e);
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// Try to inject immediately if DOM is ready, otherwise wait
|
||||
if (document.documentElement) {
|
||||
injectScript();
|
||||
} else {
|
||||
// Wait for document to be created
|
||||
const observer = new MutationObserver(() => {
|
||||
if (document.documentElement) {
|
||||
observer.disconnect();
|
||||
injectScript();
|
||||
}
|
||||
});
|
||||
observer.observe(document, { childList: true, subtree: true });
|
||||
|
||||
// Also try on DOMContentLoaded as backup
|
||||
if (document.addEventListener) {
|
||||
document.addEventListener('DOMContentLoaded', injectScript, { once: true });
|
||||
|
||||
// Run initial scan
|
||||
scanAndPatch();
|
||||
|
||||
// Scan periodically for late-initialized stores
|
||||
let scanCount = 0;
|
||||
const scanInterval = setInterval(() => {
|
||||
scanCount++;
|
||||
scanAndPatch();
|
||||
|
||||
if (scanCount >= 50) {
|
||||
clearInterval(scanInterval);
|
||||
console.log("[PAGE-INJECT] Stopped periodic scanning after 10 attempts");
|
||||
}
|
||||
}
|
||||
})();
|
||||
}, 100);
|
||||
|
||||
console.log("[PAGE-INJECT] Hooks installed successfully");
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user