mirror of
https://github.com/xenos1337/httptoolkit-patcher.git
synced 2026-07-16 00:24:24 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbc7918678 | ||
|
|
68f7e1c1c0 | ||
|
|
0685a1e727 | ||
|
|
fa9dcf5361 | ||
|
|
efcc89bab4 | ||
|
|
8215f4348b | ||
|
|
359b707b44 | ||
|
|
7537b33593 | ||
|
|
fe97c803f5 | ||
|
|
61b3bdeb5e | ||
|
|
91333c1a3e | ||
|
|
d1a64774da | ||
|
|
fe7cae9dd9 | ||
|
|
cb8fd663b7 |
@@ -20,10 +20,6 @@ The patcher intercepts HTTP Toolkit's authentication functions:
|
||||
|
||||
By hooking these functions, we bypass the subscription checks entirely.
|
||||
|
||||
### Can They Fix It?
|
||||
|
||||
Yes, but they most likely won't. Fixing this would require changing their entire codebase architecture. And if they do? I'll just update the patcher.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Install Node.js (if not already installed)
|
||||
|
||||
@@ -23,6 +23,18 @@ const __filename = (() => {
|
||||
return fileURLToPath(import.meta.url);
|
||||
})();
|
||||
|
||||
// Version info - read from package.json
|
||||
const GITHUB_REPO = "xenos1337/httptoolkit-patcher";
|
||||
const LOCAL_VERSION = (() => {
|
||||
try {
|
||||
const packageJsonPath = path.join(path.dirname(__filename), "package.json");
|
||||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
||||
return packageJson.version || "0.0.0";
|
||||
} catch {
|
||||
return "0.0.0";
|
||||
}
|
||||
})();
|
||||
|
||||
// Check if running with elevated privileges
|
||||
function isElevated() {
|
||||
if (isWin) {
|
||||
@@ -51,19 +63,79 @@ function prompt(question) {
|
||||
});
|
||||
}
|
||||
|
||||
// Helper function to fetch content from URL
|
||||
function fetchUrl(url) {
|
||||
/**
|
||||
* Fetch JSON from a URL
|
||||
* @param {string} url
|
||||
* @returns {Promise<Array<{name: string}>>}
|
||||
*/
|
||||
function fetchJson(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const options = {
|
||||
headers: {
|
||||
"User-Agent": "httptoolkit-patcher",
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
},
|
||||
};
|
||||
https
|
||||
.get(url, res => {
|
||||
.get(url, options, res => {
|
||||
if (res.statusCode !== 200) {
|
||||
reject(new Error(`HTTP ${res.statusCode}`));
|
||||
return;
|
||||
}
|
||||
let data = "";
|
||||
res.on("data", chunk => (data += chunk));
|
||||
res.on("end", () => resolve(data));
|
||||
res.on("end", () => {
|
||||
try {
|
||||
resolve(JSON.parse(data));
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
})
|
||||
.on("error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
function compareVersions(v1, v2) {
|
||||
const normalize = (/** @type {string} */ v) => v.replace(/^v/, "").split(".").map(Number);
|
||||
const parts1 = normalize(v1);
|
||||
const parts2 = normalize(v2);
|
||||
|
||||
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
||||
const num1 = parts1[i] || 0;
|
||||
const num2 = parts2[i] || 0;
|
||||
if (num1 > num2) return 1;
|
||||
if (num1 < num2) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for updates from GitHub
|
||||
*/
|
||||
async function checkForUpdates() {
|
||||
try {
|
||||
const tags = await fetchJson(`https://api.github.com/repos/${GITHUB_REPO}/tags`);
|
||||
|
||||
if (!tags || tags.length === 0) {
|
||||
return; // No tags found, skip update check
|
||||
}
|
||||
|
||||
// Tags are returned in order, first one is the latest
|
||||
const latestTag = tags[0].name;
|
||||
const latestVersion = latestTag.replace(/^v/, "");
|
||||
|
||||
if (compareVersions(latestVersion, LOCAL_VERSION) > 0) {
|
||||
console.log(chalk.yellowBright`\n╔════════════════════════════════════════════════════════════╗`);
|
||||
console.log(chalk.yellowBright`║` + chalk.white` A new version is available: ` + chalk.greenBright`v${latestVersion}` + chalk.white` (current: ` + chalk.gray`v${LOCAL_VERSION}` + chalk.white`) ` + chalk.yellowBright` ║`);
|
||||
console.log(chalk.yellowBright`║` + chalk.white` Update: ` + chalk.cyanBright`https://github.com/${GITHUB_REPO}` + chalk.white` ` + chalk.yellowBright`║`);
|
||||
console.log(chalk.yellowBright`╚════════════════════════════════════════════════════════════╝\n`);
|
||||
}
|
||||
} catch (e) {
|
||||
// Silently ignore update check errors (network issues, etc.)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to remove directory recursively
|
||||
function rm(dirPath) {
|
||||
if (!fs.existsSync(dirPath)) return;
|
||||
@@ -78,7 +150,11 @@ function rm(dirPath) {
|
||||
|
||||
// Find HTTP Toolkit installation path
|
||||
async function findAppPath() {
|
||||
const possiblePaths = isWin ? [path.join("C:", "Program Files", "HTTP Toolkit", "resources"), path.join("C:", "Program Files (x86)", "HTTP Toolkit", "resources")] : isMac ? ["/Applications/HTTP Toolkit.app/Contents/Resources"] : ["/opt/HTTP Toolkit/resources", "/opt/httptoolkit/resources"];
|
||||
const possiblePaths = isWin
|
||||
? [path.join("C:", "Program Files", "HTTP Toolkit", "resources"), path.join("C:", "Program Files (x86)", "HTTP Toolkit", "resources"), path.join(process.env.LOCALAPPDATA || path.join(process.env.USERPROFILE || "", "AppData", "Local"), "Programs", "HTTP Toolkit", "resources")]
|
||||
: isMac
|
||||
? ["/Applications/HTTP Toolkit.app/Contents/Resources"]
|
||||
: ["/opt/HTTP Toolkit/resources", "/opt/httptoolkit/resources"];
|
||||
|
||||
for (const p of possiblePaths) {
|
||||
if (fs.existsSync(path.join(p, "app.asar"))) {
|
||||
@@ -172,7 +248,7 @@ function checkPermissions(filePath) {
|
||||
try {
|
||||
// Check write access to the file/directory
|
||||
fs.accessSync(filePath, fs.constants.W_OK);
|
||||
|
||||
|
||||
// Check if we can create directories
|
||||
const testDirPath = path.join(path.dirname(filePath), `.test_${Date.now()}`);
|
||||
try {
|
||||
@@ -182,7 +258,7 @@ function checkPermissions(filePath) {
|
||||
console.error(chalk.redBright`[-] Cannot create directories in ${path.dirname(filePath)}: ${dirError.message}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
console.log(chalk.greenBright`[+] Permissions check passed for ${filePath}`);
|
||||
return true;
|
||||
} catch (e) {
|
||||
@@ -237,18 +313,130 @@ async function killHttpToolkit() {
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the base installation directory (without the trailing resources folder)
|
||||
function getBinaryBasePath(resourcesPath) {
|
||||
const normalized = resourcesPath.replace(/[\\/]+$/, "");
|
||||
if (normalized.toLowerCase().endsWith("resources")) {
|
||||
return path.dirname(normalized);
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
// Determine the executable path for HTTP Toolkit based on platform
|
||||
function getExecutablePath(resourcesPath) {
|
||||
const basePath = getBinaryBasePath(resourcesPath);
|
||||
const candidates = isWin ? [path.join(basePath, "HTTP Toolkit.exe"), path.join(basePath, "httptoolkit.exe")] : isMac ? [path.join(basePath, "MacOS", "HTTP Toolkit"), path.join(basePath, "MacOS", "HTTP Toolkit Preview")] : [path.join(basePath, "httptoolkit"), path.join(basePath, "HTTP Toolkit")];
|
||||
|
||||
for (const candidate of candidates) {
|
||||
if (fs.existsSync(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Could not locate HTTP Toolkit executable near ${resourcesPath}`);
|
||||
}
|
||||
|
||||
// Extract hashes from integrity check output
|
||||
function extractIntegrityHashes(output) {
|
||||
const regex = /Integrity check failed for asar archive[\s\S]*?\(\s*([0-9a-f]{64})\s*vs\s*([0-9a-f]{64})\s*\)/i;
|
||||
const match = output.match(regex);
|
||||
if (!match) return null;
|
||||
return {
|
||||
originalHash: match[1],
|
||||
newHash: match[2],
|
||||
};
|
||||
}
|
||||
|
||||
// Launch the app once to grab integrity hashes from its crash output
|
||||
async function captureIntegrityHashes(executablePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let output = "";
|
||||
let finished = false;
|
||||
const child = spawn(executablePath, {
|
||||
cwd: path.dirname(executablePath),
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
windowsHide: true,
|
||||
});
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
if (!finished) {
|
||||
finished = true;
|
||||
child.kill();
|
||||
reject(new Error("Timed out waiting for integrity check output"));
|
||||
}
|
||||
}, 20000);
|
||||
|
||||
const handleData = data => {
|
||||
output += data.toString();
|
||||
const hashes = extractIntegrityHashes(output);
|
||||
if (hashes && !finished) {
|
||||
finished = true;
|
||||
clearTimeout(timeout);
|
||||
child.kill();
|
||||
resolve(hashes);
|
||||
}
|
||||
};
|
||||
|
||||
child.stdout.on("data", handleData);
|
||||
child.stderr.on("data", handleData);
|
||||
|
||||
child.on("error", err => {
|
||||
if (!finished) {
|
||||
finished = true;
|
||||
clearTimeout(timeout);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
|
||||
child.on("exit", () => {
|
||||
if (!finished) {
|
||||
clearTimeout(timeout);
|
||||
const hashes = extractIntegrityHashes(output);
|
||||
if (hashes) {
|
||||
resolve(hashes);
|
||||
} else {
|
||||
reject(new Error("Could not find integrity hashes in HTTP Toolkit output"));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Replace all occurrences of the original hash with the new hash inside the binary
|
||||
function patchExecutableHash(executablePath, originalHash, newHash) {
|
||||
if (originalHash.length !== newHash.length) {
|
||||
throw new Error("Hash lengths do not match; cannot safely patch binary");
|
||||
}
|
||||
|
||||
const binary = fs.readFileSync(executablePath);
|
||||
const originalBuf = Buffer.from(originalHash, "utf-8");
|
||||
const newBuf = Buffer.from(newHash, "utf-8");
|
||||
|
||||
let occurrences = 0;
|
||||
let idx = binary.indexOf(originalBuf);
|
||||
while (idx !== -1) {
|
||||
newBuf.copy(binary, idx);
|
||||
occurrences += 1;
|
||||
idx = binary.indexOf(originalBuf, idx + originalBuf.length);
|
||||
}
|
||||
|
||||
if (occurrences === 0) {
|
||||
throw new Error("Original hash not found in binary");
|
||||
}
|
||||
|
||||
fs.writeFileSync(executablePath, binary);
|
||||
return occurrences;
|
||||
}
|
||||
|
||||
// Unpatch/restore function
|
||||
async function unpatchApp() {
|
||||
console.log(chalk.blueBright`[+] HTTP Toolkit Unpatcher Started`);
|
||||
|
||||
// Step 1: Find app path
|
||||
const appPath = await findAppPath();
|
||||
console.log(chalk.greenBright`[+] HTTP Toolkit found at ${appPath}`);
|
||||
|
||||
// Step 2: Kill HTTP Toolkit if running
|
||||
await killHttpToolkit();
|
||||
|
||||
// Step 3: Check permissions
|
||||
const asarPath = path.join(appPath, "app.asar");
|
||||
const backupPath = path.join(appPath, "app.asar.bak");
|
||||
const extractPath = path.join(appPath, "app.asar_extracted");
|
||||
@@ -268,14 +456,12 @@ async function unpatchApp() {
|
||||
await requestElevation();
|
||||
}
|
||||
|
||||
// Step 4: Check if backup exists
|
||||
if (!fs.existsSync(backupPath)) {
|
||||
console.error(chalk.redBright`[-] Backup file not found at ${backupPath}`);
|
||||
console.error(chalk.redBright`[-] Cannot unpatch without backup file`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Step 5: Restore from backup
|
||||
console.log(chalk.yellowBright`[+] Restoring from backup...`);
|
||||
try {
|
||||
fs.copyFileSync(backupPath, asarPath);
|
||||
@@ -285,14 +471,12 @@ async function unpatchApp() {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Step 6: Clean up extracted files if they exist
|
||||
if (fs.existsSync(extractPath)) {
|
||||
console.log(chalk.yellowBright`[+] Removing extracted files...`);
|
||||
rm(extractPath);
|
||||
console.log(chalk.greenBright`[+] Cleaned up extracted files`);
|
||||
}
|
||||
|
||||
// Step 7: Optionally remove backup
|
||||
const removeBackup = await prompt("Do you want to remove the backup file? (y/n): ");
|
||||
if (removeBackup.toLowerCase() === "y" || removeBackup.toLowerCase() === "yes") {
|
||||
fs.rmSync(backupPath, { force: true });
|
||||
@@ -306,14 +490,11 @@ async function unpatchApp() {
|
||||
async function patchApp() {
|
||||
console.log(chalk.blueBright`[+] HTTP Toolkit Patcher Started`);
|
||||
|
||||
// Step 1: Find app path
|
||||
const appPath = await findAppPath();
|
||||
console.log(chalk.greenBright`[+] HTTP Toolkit found at ${appPath}`);
|
||||
|
||||
// Step 2: Kill HTTP Toolkit if running
|
||||
await killHttpToolkit();
|
||||
|
||||
// Step 3: Check permissions
|
||||
const asarPath = path.join(appPath, "app.asar");
|
||||
|
||||
// Check if we have write permissions on both the directory and the file
|
||||
@@ -331,7 +512,6 @@ async function patchApp() {
|
||||
await requestElevation();
|
||||
}
|
||||
|
||||
// Step 4: Backup app.asar
|
||||
const backupPath = path.join(appPath, "app.asar.bak");
|
||||
if (!fs.existsSync(backupPath)) {
|
||||
console.log(chalk.yellowBright`[+] Creating backup...`);
|
||||
@@ -339,44 +519,77 @@ async function patchApp() {
|
||||
console.log(chalk.greenBright`[+] Backup created at ${backupPath}`);
|
||||
}
|
||||
|
||||
// Step 5: Extract app.asar
|
||||
const extractPath = path.join(appPath, "app.asar_extracted");
|
||||
console.log(chalk.yellowBright`[+] Extracting app.asar...`);
|
||||
rm(extractPath);
|
||||
asar.extractAll(asarPath, extractPath);
|
||||
console.log(chalk.greenBright`[+] Extracted to ${extractPath}`);
|
||||
|
||||
// Step 6: Check if preload.cjs or preload.js exists
|
||||
let preloadPath = path.join(extractPath, "build", "preload.cjs");
|
||||
const preloadPath = path.join(extractPath, "build", "preload.cjs");
|
||||
if (!fs.existsSync(preloadPath)) {
|
||||
console.log(chalk.yellowBright`[!] preload.cjs not found, checking for preload.js...`);
|
||||
preloadPath = path.join(extractPath, "build", "preload.js");
|
||||
if (!fs.existsSync(preloadPath)) {
|
||||
console.error(chalk.redBright`[-] Neither preload.cjs nor preload.js found in ${path.join(extractPath, "build")}`);
|
||||
rm(extractPath);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(chalk.greenBright`[+] Found preload.js`);
|
||||
} else {
|
||||
console.log(chalk.greenBright`[+] Found preload.cjs`);
|
||||
}
|
||||
|
||||
// Step 7: Fetch inject.js from GitHub
|
||||
console.log(chalk.yellowBright`[+] Fetching inject code from GitHub...`);
|
||||
const injectCode = await fetchUrl("https://raw.githubusercontent.com/xenos1337/httptoolkit-patcher/refs/heads/master/inject.js");
|
||||
if (!injectCode || !injectCode.includes("injectPageContextHooks")) {
|
||||
console.error(chalk.redBright`[-] Failed to fetch inject.js from GitHub`);
|
||||
console.error(chalk.redBright`[-] preload.cjs not found in ${path.join(extractPath, "build")}`);
|
||||
console.error(chalk.yellowBright`[!] Please download the latest version of HTTP Toolkit from https://httptoolkit.com/`);
|
||||
rm(extractPath);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(chalk.greenBright`[+] Inject code fetched successfully`);
|
||||
console.log(chalk.greenBright`[+] Found preload.cjs`);
|
||||
|
||||
console.log(chalk.yellowBright`[+] Reading inject code from local file...`);
|
||||
const injectJsPath = path.join(path.dirname(__filename), "inject.js");
|
||||
if (!fs.existsSync(injectJsPath)) {
|
||||
console.error(chalk.redBright`[-] inject.js not found at ${injectJsPath}`);
|
||||
rm(extractPath);
|
||||
process.exit(1);
|
||||
}
|
||||
const injectCode = fs.readFileSync(injectJsPath, "utf-8");
|
||||
if (!injectCode || !injectCode.includes("PAGE-INJECT")) {
|
||||
console.error(chalk.redBright`[-] Invalid inject.js file`);
|
||||
rm(extractPath);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(chalk.greenBright`[+] Inject code loaded successfully`);
|
||||
|
||||
// Step 8: Read preload file and check if already patched
|
||||
let preloadContent = fs.readFileSync(preloadPath, "utf-8");
|
||||
const isPatched = preloadContent.includes("injectPageContextHooks");
|
||||
|
||||
if (isPatched) {
|
||||
console.log(chalk.yellowBright`[!] File already patched`);
|
||||
const electronVarName = preloadContent.includes("electron_1") ? "electron_1" : "electron";
|
||||
console.log(chalk.greenBright`[+] Detected electron variable: ${electronVarName}`);
|
||||
|
||||
const preloadPatchCode = `
|
||||
(function loadInjectScript() {
|
||||
const injectCode = ${JSON.stringify(injectCode)};
|
||||
|
||||
function injectViaWebFrame() {
|
||||
try {
|
||||
const { webFrame } = ${electronVarName};
|
||||
if (webFrame && webFrame.executeJavaScript) {
|
||||
webFrame.executeJavaScript(injectCode).then(() => console.log("[PRELOAD] Injected via webFrame.executeJavaScript")).catch(err => console.error("[PRELOAD] webFrame injection failed:", err));
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[PRELOAD] webFrame not available:", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!injectViaWebFrame()) {
|
||||
const tryInject = () => {
|
||||
if (!injectViaWebFrame()) {
|
||||
console.error("[PRELOAD] All injection methods failed");
|
||||
}
|
||||
};
|
||||
|
||||
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||
tryInject();
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', tryInject, { once: true });
|
||||
}
|
||||
}
|
||||
})();
|
||||
`;
|
||||
const isPreloadPatched = preloadContent.includes("loadInjectScript");
|
||||
|
||||
if (isPreloadPatched) {
|
||||
console.log(chalk.yellowBright`[!] Files already patched`);
|
||||
const answer = await prompt("Do you want to repatch? (y/n): ");
|
||||
|
||||
if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
|
||||
@@ -385,65 +598,88 @@ async function patchApp() {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Replace the existing injectPageContextHooks function
|
||||
console.log(chalk.yellowBright`[+] Replacing existing patch...`);
|
||||
const functionRegex = /\(function injectPageContextHooks\(\) \{[\s\S]*?\}\)\(\);/;
|
||||
preloadContent = preloadContent.replace(functionRegex, injectCode);
|
||||
} else {
|
||||
// Find line with electron_1 and insert inject code below it
|
||||
console.log(chalk.yellowBright`[+] Applying patch...`);
|
||||
const lines = preloadContent.split("\n");
|
||||
let insertIndex = -1;
|
||||
// Remove existing patches
|
||||
console.log(chalk.yellowBright`[+] Replacing existing patches...`);
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (lines[i].includes("electron_1")) {
|
||||
insertIndex = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (insertIndex === -1) {
|
||||
console.error(chalk.redBright`[-] Could not find insertion point (electron_1) in ${path.basename(preloadPath)}`);
|
||||
rm(extractPath);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
lines.splice(insertIndex, 0, injectCode);
|
||||
preloadContent = lines.join("\n");
|
||||
// Remove preload patch
|
||||
const preloadPatchRegex = /\n?\(function loadInjectScript\(\) \{[\s\S]*?\}\)\(\);/;
|
||||
preloadContent = preloadContent.replace(preloadPatchRegex, "");
|
||||
}
|
||||
|
||||
// Step 9: Write patched preload file
|
||||
console.log(chalk.yellowBright`[+] Applying preload patch...`);
|
||||
const preloadLines = preloadContent.split("\n");
|
||||
let preloadInsertIndex = -1;
|
||||
|
||||
for (let i = 0; i < preloadLines.length; i++) {
|
||||
const line = preloadLines[i];
|
||||
if (line.includes('require("electron")') || line.includes("require('electron')") || line.includes("electron_1")) {
|
||||
preloadInsertIndex = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (preloadInsertIndex === -1) {
|
||||
console.error(chalk.redBright`[-] Could not find insertion point (electron import) in ${path.basename(preloadPath)}`);
|
||||
rm(extractPath);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
preloadLines.splice(preloadInsertIndex, 0, preloadPatchCode);
|
||||
preloadContent = preloadLines.join("\n");
|
||||
|
||||
// Write patched preload file
|
||||
fs.writeFileSync(preloadPath, preloadContent, "utf-8");
|
||||
console.log(chalk.greenBright`[+] ${path.basename(preloadPath)} patched successfully`);
|
||||
|
||||
// Step 10: Repackage app.asar
|
||||
console.log(chalk.yellowBright`[+] Repackaging app.asar...`);
|
||||
await asar.createPackage(extractPath, asarPath);
|
||||
console.log(chalk.greenBright`[+] app.asar repackaged successfully`);
|
||||
|
||||
// Step 11: Clean up
|
||||
let executablePath;
|
||||
try {
|
||||
executablePath = getExecutablePath(appPath);
|
||||
} catch (e) {
|
||||
rm(extractPath);
|
||||
console.error(chalk.redBright`[-] ${e.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(chalk.yellowBright`[+] Launching HTTP Toolkit to read integrity hashes...`);
|
||||
let hashes;
|
||||
try {
|
||||
hashes = await captureIntegrityHashes(executablePath);
|
||||
} catch (e) {
|
||||
rm(extractPath);
|
||||
console.error(chalk.redBright`[-] Failed to capture integrity hashes: ${e.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(chalk.greenBright`[+] Integrity hashes captured`);
|
||||
console.log(chalk.white` Original hash: ${hashes.originalHash}`);
|
||||
console.log(chalk.white` New asar hash: ${hashes.newHash}`);
|
||||
|
||||
try {
|
||||
const replacements = patchExecutableHash(executablePath, hashes.originalHash, hashes.newHash);
|
||||
console.log(chalk.greenBright`[+] Patched binary hash (${replacements} replacement${replacements === 1 ? "" : "s"})`);
|
||||
} catch (e) {
|
||||
rm(extractPath);
|
||||
console.error(chalk.redBright`[-] Failed to patch binary hash: ${e.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(chalk.yellowBright`[+] Cleaning up temporary files...`);
|
||||
rm(extractPath);
|
||||
console.log(chalk.greenBright`[+] Successfully patched!`);
|
||||
|
||||
// Step 12: Open HTTP Toolkit as detached process
|
||||
console.log(chalk.blueBright`[+] Opening HTTP Toolkit...`);
|
||||
try {
|
||||
if (isLinux) {
|
||||
// Linux: Cannot auto-launch reliably, show manual instructions
|
||||
console.log(chalk.yellowBright`[!] HTTP Toolkit has been successfully patched`);
|
||||
console.log(chalk.yellowBright`[!] Please manually launch HTTP Toolkit from your applications menu or using the command:`);
|
||||
console.log(chalk.blueBright` httptoolkit`);
|
||||
} else {
|
||||
const command = isWin ? `"${path.resolve(appPath, "..", "HTTP Toolkit.exe")}"` : isMac ? 'open -a "HTTP Toolkit"' : "httptoolkit";
|
||||
const child = spawn(command, {
|
||||
stdio: "ignore",
|
||||
shell: true,
|
||||
detached: true,
|
||||
});
|
||||
child.unref();
|
||||
console.log(chalk.greenBright`[+] HTTP Toolkit launched successfully`);
|
||||
}
|
||||
const child = spawn(executablePath, {
|
||||
stdio: "ignore",
|
||||
shell: false,
|
||||
detached: true,
|
||||
});
|
||||
child.unref();
|
||||
console.log(chalk.greenBright`[+] HTTP Toolkit launched successfully`);
|
||||
} catch (e) {
|
||||
console.error(chalk.yellowBright`[!] Could not auto-start HTTP Toolkit: ${e.message}`);
|
||||
console.log(chalk.blueBright`[+] Please start HTTP Toolkit manually`);
|
||||
@@ -465,6 +701,9 @@ const commandName = (() => {
|
||||
// Run the appropriate command
|
||||
(async () => {
|
||||
try {
|
||||
// Check for updates from GitHub
|
||||
await checkForUpdates();
|
||||
|
||||
if (command === "unpatch" || command === "restore") {
|
||||
await unpatchApp();
|
||||
} else if (command === "help" || command === "-h" || command === "--help") {
|
||||
|
||||
@@ -1,206 +1,236 @@
|
||||
(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");
|
||||
|
||||
// Properties to hook directly on accountStore (still exist as computed properties)
|
||||
const propertyHooks = {
|
||||
isLoggedIn: true,
|
||||
userEmail: "hi@httptoolkit.com",
|
||||
mightBePaidUser: 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,
|
||||
},
|
||||
};
|
||||
|
||||
// Methods to hook on the user object (moved from accountStore properties to user methods in v3.1.0)
|
||||
const userMethodHooks = {
|
||||
isPaidUser: true,
|
||||
isPastDueUser: false,
|
||||
userHasSubscription: true,
|
||||
};
|
||||
|
||||
const hookedObjects = new WeakSet();
|
||||
const hookedUsers = new WeakSet();
|
||||
|
||||
// Patch user object methods
|
||||
function patchUserObject(user) {
|
||||
if (!user || typeof user !== "object" || hookedUsers.has(user)) return;
|
||||
|
||||
for (const methodName of Object.keys(userMethodHooks)) {
|
||||
if (typeof user[methodName] === "function") {
|
||||
console.log("[PAGE-INJECT] Patching user." + methodName + "()");
|
||||
user[methodName] = function () {
|
||||
return userMethodHooks[methodName];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
hookedUsers.add(user);
|
||||
}
|
||||
|
||||
// Override Object.defineProperty to intercept all property definitions
|
||||
const originalDefineProperty = Object.defineProperty;
|
||||
Object.defineProperty = function (target, prop, descriptor) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
// Intercept the 'user' property to patch its methods when it's set/accessed
|
||||
if (prop === "user") {
|
||||
console.log("[PAGE-INJECT] Intercepting defineProperty for: user");
|
||||
|
||||
if (descriptor && descriptor.get) {
|
||||
const originalGetter = descriptor.get;
|
||||
descriptor.get = function () {
|
||||
const user = originalGetter.call(this);
|
||||
if (user) patchUserObject(user);
|
||||
return user;
|
||||
};
|
||||
} else if (descriptor && descriptor.value !== undefined && descriptor.value) {
|
||||
patchUserObject(descriptor.value);
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
if (prop === "user") {
|
||||
console.log("[PAGE-INJECT] Intercepting defineProperties for: user");
|
||||
if (props[prop].get) {
|
||||
const originalGetter = props[prop].get;
|
||||
props[prop].get = function () {
|
||||
const user = originalGetter.call(this);
|
||||
if (user) patchUserObject(user);
|
||||
return user;
|
||||
};
|
||||
} else if (props[prop].value !== undefined && props[prop].value) {
|
||||
patchUserObject(props[prop].value);
|
||||
}
|
||||
|
||||
return originalDefineProperty.call(this, target, prop, descriptor);
|
||||
};
|
||||
}
|
||||
}
|
||||
return originalDefineProperties.call(this, target, props);
|
||||
};
|
||||
|
||||
// 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);
|
||||
};
|
||||
// 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];
|
||||
|
||||
// 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;
|
||||
|
||||
searchPaths.forEach((obj, idx) => {
|
||||
if (!obj || hookedObjects.has(obj)) return;
|
||||
|
||||
try {
|
||||
// Patch direct property hooks
|
||||
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;
|
||||
originalDefineProperty(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
|
||||
}
|
||||
});
|
||||
|
||||
// Patch user object if present
|
||||
try {
|
||||
if (obj.user && typeof obj.user === "object") {
|
||||
console.log("[PAGE-INJECT] Found user object on object #" + idx + ", patching methods...");
|
||||
patchUserObject(obj.user);
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
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() {
|
||||
originalDefineProperty(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
|
||||
}
|
||||
});
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
// 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);
|
||||
// Patch user methods on the store
|
||||
try {
|
||||
if (store.user && typeof store.user === "object") {
|
||||
console.log("[PAGE-INJECT] Found user object in accountStore, patching methods...");
|
||||
patchUserObject(store.user);
|
||||
}
|
||||
}
|
||||
} 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 50 attempts");
|
||||
}
|
||||
}
|
||||
})();
|
||||
}, 100);
|
||||
|
||||
console.log("[PAGE-INJECT] Hooks installed successfully");
|
||||
})();
|
||||
|
||||
Generated
+201
-86
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "httptoolkit-patcher",
|
||||
"version": "2.0.5",
|
||||
"version": "2.0.10",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "httptoolkit-patcher",
|
||||
"version": "2.0.5",
|
||||
"version": "2.0.10",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@electron/asar": "^3.2.9",
|
||||
"@electron/asar": "^4.0.1",
|
||||
"chalk": "4"
|
||||
},
|
||||
"bin": {
|
||||
@@ -20,20 +20,29 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/asar": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.4.1.tgz",
|
||||
"integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@electron/asar/-/asar-4.0.1.tgz",
|
||||
"integrity": "sha512-F4Ykm1jiBGY1WV/o8Q8oFW8Nq0u+S2/vPujzNJtdSJ6C4LHC4CiGLn7c17s7SolZ23gcvCebMncmZtNc+MkxPQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"commander": "^5.0.0",
|
||||
"glob": "^7.1.6",
|
||||
"minimatch": "^3.0.4"
|
||||
"commander": "^13.1.0",
|
||||
"glob": "^11.0.1",
|
||||
"minimatch": "^10.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"asar": "bin/asar.js"
|
||||
"asar": "bin/asar.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.12.0"
|
||||
"node": ">=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/cliui": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz",
|
||||
"integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
@@ -62,19 +71,24 @@
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"license": "MIT"
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.3.tgz",
|
||||
"integrity": "sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz",
|
||||
"integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
"balanced-match": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
@@ -112,42 +126,63 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
|
||||
"integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
|
||||
"version": "13.1.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
|
||||
"integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"deprecated": "Glob versions prior to v9 are no longer supported",
|
||||
"license": "ISC",
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.1.1",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
"which": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/foreground-child": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
|
||||
"integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.6",
|
||||
"signal-exit": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz",
|
||||
"integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==",
|
||||
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"foreground-child": "^3.3.1",
|
||||
"jackspeak": "^4.1.1",
|
||||
"minimatch": "^10.1.1",
|
||||
"minipass": "^7.1.2",
|
||||
"package-json-from-dist": "^1.0.0",
|
||||
"path-scurry": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"glob": "dist/esm/bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
@@ -162,51 +197,122 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
||||
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"license": "ISC",
|
||||
"node_modules/jackspeak": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz",
|
||||
"integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
"@isaacs/cliui": "^9.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
"node": "20 || >=22"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"license": "ISC",
|
||||
"node_modules/lru-cache": {
|
||||
"version": "11.2.6",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz",
|
||||
"integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "10.2.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
|
||||
"integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
"brace-expansion": "^5.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "18 || 20 || >=22"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/path-is-absolute": {
|
||||
"node_modules/minipass": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
|
||||
"integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/package-json-from-dist": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
|
||||
"license": "BlueOak-1.0.0"
|
||||
},
|
||||
"node_modules/path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/path-scurry": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
|
||||
"integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"lru-cache": "^11.0.0",
|
||||
"minipass": "^7.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "18 || 20 || >=22"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
@@ -228,11 +334,20 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"license": "ISC"
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"isexe": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"node-which": "bin/node-which"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,10 +1,11 @@
|
||||
{
|
||||
"name": "httptoolkit-patcher",
|
||||
"version": "2.0.5",
|
||||
"version": "2.0.11",
|
||||
"description": "HTTP Toolkit Pro Patcher",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"bin": "index.js",
|
||||
"author": "xenos1337",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"patch": "node index.js patch",
|
||||
@@ -13,7 +14,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@electron/asar": "^3.2.9",
|
||||
"@electron/asar": "^4.0.1",
|
||||
"chalk": "4"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
Reference in New Issue
Block a user