mirror of
https://github.com/ayyo42069/HTTPToolkit-Patcher-2026.git
synced 2026-07-15 16:20:02 +02:00
Upload
This commit is contained in:
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
@@ -0,0 +1,45 @@
|
||||
# HTTP Toolkit Pro Patcher
|
||||
|
||||
A simple patcher to enable Pro features in HTTP Toolkit.
|
||||
|
||||
**Updated by [kristof.best](https://kristof.best) ([@ayyo42069](https://github.com/ayyo42069))**
|
||||
**Original by ([@XielQ](https://github.com/XielQs))**
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js 15 or higher
|
||||
- HTTP Toolkit installed
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Apply the patch
|
||||
node . patch
|
||||
|
||||
# Start HTTP Toolkit
|
||||
node . start
|
||||
|
||||
# Restore original (if needed)
|
||||
node . restore
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
1. Extracts the app.asar from HTTP Toolkit
|
||||
2. Injects a local proxy server that intercepts UI requests
|
||||
3. Patches the subscription data on-the-fly to enable Pro features
|
||||
4. Flips Electron fuses to bypass ASAR integrity checks
|
||||
5. Repacks the app
|
||||
|
||||
## Notes
|
||||
|
||||
- Creates a backup at `app.asar.bak` before patching
|
||||
- You can set a custom proxy with the `PROXY` environment variable
|
||||
- Works offline after first run (caches UI files locally)
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@@ -0,0 +1,271 @@
|
||||
// @ts-check
|
||||
import { spawn } from 'child_process'
|
||||
import { flipFuses, FuseVersion, FuseV1Options } from '@electron/fuses'
|
||||
import asar from '@electron/asar'
|
||||
import prompts from 'prompts'
|
||||
import yargs from 'yargs'
|
||||
import chalk from 'chalk'
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import os from 'os'
|
||||
|
||||
const argv = await yargs(process.argv.slice(2))
|
||||
.usage(`Usage: ${process.argv0} . <command> [options]`)
|
||||
.command('patch', 'Patch HTTP Toolkit using the specified script')
|
||||
.command('restore', 'Restore HTTP Toolkit files to their original state')
|
||||
.command('start', 'Start HTTP Toolkit')
|
||||
.demandCommand(1, 'You need at least one command before moving on')
|
||||
.alias('h', 'help')
|
||||
.parse()
|
||||
|
||||
const isWin = process.platform === 'win32'
|
||||
const isMac = process.platform === 'darwin'
|
||||
|
||||
// Try to find where HTTP Toolkit is installed
|
||||
const appPath =
|
||||
isWin ? path.join(process.env.LOCALAPPDATA ?? '', 'Programs', 'HTTP Toolkit', 'resources')
|
||||
: isMac ? '/Applications/HTTP Toolkit.app/Contents/Resources'
|
||||
: fs.existsSync('/opt/HTTP Toolkit/resources') ? '/opt/HTTP Toolkit/resources'
|
||||
: '/opt/httptoolkit/resources'
|
||||
|
||||
const exePath =
|
||||
isWin ? path.join(process.env.LOCALAPPDATA ?? '', 'Programs', 'HTTP Toolkit', 'HTTP Toolkit.exe')
|
||||
: isMac ? '/Applications/HTTP Toolkit.app/Contents/MacOS/HTTP Toolkit'
|
||||
: fs.existsSync('/opt/HTTP Toolkit/httptoolkit') ? '/opt/HTTP Toolkit/httptoolkit'
|
||||
: '/opt/httptoolkit/httptoolkit'
|
||||
|
||||
const isSudo = !isWin && (process.getuid || (() => process.env.SUDO_UID ? 0 : null))() === 0
|
||||
|
||||
if (+(process.versions.node.split('.')[0]) < 15) {
|
||||
console.error(chalk.redBright`Node.js version 15 or higher is recommended, you are using version {bold ${process.versions.node}}`)
|
||||
}
|
||||
|
||||
if (!fs.existsSync(path.join(appPath, 'app.asar'))) {
|
||||
console.error(chalk.redBright`Couldn't find HTTP Toolkit! Make sure it's installed.`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log(chalk.blueBright`Found HTTP Toolkit at {bold ${path.dirname(appPath)}}`)
|
||||
|
||||
// Helper to recursively delete directories
|
||||
const rm = dirPath => {
|
||||
if (!fs.existsSync(dirPath)) return
|
||||
if (!fs.lstatSync(dirPath).isDirectory()) return fs.rmSync(dirPath, { force: true })
|
||||
for (const entry of fs.readdirSync(dirPath)) {
|
||||
const entryPath = path.join(dirPath, entry)
|
||||
if (fs.lstatSync(entryPath).isDirectory()) rm(entryPath)
|
||||
else fs.rmSync(entryPath, { force: true })
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {Array<import('child_process').ChildProcess>} */
|
||||
const activeProcesses = []
|
||||
let isCancelled = false
|
||||
|
||||
const cleanUp = async () => {
|
||||
isCancelled = true
|
||||
console.log(chalk.redBright`Cancelled! Cleaning up...`)
|
||||
if (activeProcesses.length) {
|
||||
console.log(chalk.yellowBright`Stopping active processes...`)
|
||||
for (const proc of activeProcesses) {
|
||||
proc.kill('SIGINT')
|
||||
console.log(chalk.yellowBright`Process {bold ${proc.pid ? process.pid + ' ' : ''}}stopped`)
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
}
|
||||
const paths = [
|
||||
path.resolve(os.tmpdir(), 'httptoolkit-patch'),
|
||||
path.resolve(appPath, 'app')
|
||||
]
|
||||
try {
|
||||
for (const p of paths) {
|
||||
if (fs.existsSync(p)) {
|
||||
console.log(chalk.yellowBright`Removing {bold ${p}}`)
|
||||
rm(p)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(chalk.redBright`Error while cleaning up`, e)
|
||||
}
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const patchApp = async () => {
|
||||
const filePath = path.join(appPath, 'app.asar')
|
||||
const tempPath = path.join(appPath, 'app')
|
||||
|
||||
if (fs.readFileSync(filePath).includes('Injected by HTTP Toolkit Patcher')) {
|
||||
console.log(chalk.greenBright`App is already patched!`)
|
||||
return
|
||||
}
|
||||
|
||||
const globalProxy = process.env.PROXY
|
||||
|
||||
console.log(chalk.blueBright`Starting the patch process...`)
|
||||
|
||||
if (globalProxy) {
|
||||
if (!globalProxy.match(/^https?:/)) {
|
||||
console.error(chalk.redBright`Global proxy must start with http:// or https://`)
|
||||
process.exit(1)
|
||||
}
|
||||
console.log(chalk.yellowBright`Using custom proxy: {bold ${globalProxy}}`)
|
||||
}
|
||||
|
||||
console.log(chalk.yellowBright`Extracting app files...`)
|
||||
|
||||
;['SIGINT', 'SIGTERM'].forEach(signal => process.on(signal, cleanUp))
|
||||
|
||||
try {
|
||||
rm(tempPath)
|
||||
asar.extractAll(filePath, tempPath)
|
||||
} catch (e) {
|
||||
if (!isSudo && /** @type {any} */ (e).errno === -13) { // Permission denied
|
||||
console.error(chalk.redBright`Permission denied${!isWin ? ', try running with sudo' : ', try running node as administrator'}`)
|
||||
process.exit(1)
|
||||
}
|
||||
console.error(chalk.redBright`Error extracting app`, e)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const indexPath = path.join(tempPath, 'build', 'index.js')
|
||||
if (!fs.existsSync(indexPath)) {
|
||||
console.error(chalk.redBright`Couldn't find index.js file`)
|
||||
cleanUp()
|
||||
}
|
||||
const data = fs.readFileSync(indexPath, 'utf-8')
|
||||
;['SIGINT', 'SIGTERM'].forEach(signal => process.off(signal, cleanUp))
|
||||
|
||||
const { email } = await prompts({
|
||||
type: 'text',
|
||||
name: 'email',
|
||||
message: 'Enter an email for the pro plan',
|
||||
validate: value => value.includes('@') || 'Invalid email'
|
||||
})
|
||||
|
||||
if (!email || typeof email !== 'string') {
|
||||
console.error(chalk.redBright`No email provided`)
|
||||
cleanUp()
|
||||
}
|
||||
|
||||
;['SIGINT', 'SIGTERM'].forEach(signal => process.on(signal, cleanUp))
|
||||
const patchContent = fs.readFileSync('patch.js', 'utf-8')
|
||||
|
||||
// Separate imports from the rest of the patch code
|
||||
const patchImportsMatch = patchContent.match(/\/\/ --- Patcher Imports[\s\S]*?\/\/ --- End Patcher Imports ---\n?/)
|
||||
const patchImports = patchImportsMatch ? patchImportsMatch[0] : ''
|
||||
const patchCode = patchContent.replace(patchImports, '')
|
||||
|
||||
// Find where to put our imports (right after the last existing import)
|
||||
const lastImportMatch = data.match(/^import .+$/gm)
|
||||
const lastImport = lastImportMatch ? lastImportMatch[lastImportMatch.length - 1] : null
|
||||
|
||||
let patchedData = data
|
||||
|
||||
// Inject imports at the top
|
||||
if (patchImports && lastImport) {
|
||||
patchedData = patchedData.replace(lastImport, `${lastImport}\n// ------- Patcher Imports -------\n${patchImports.trim()}\n// ------- End Patcher Imports -------`)
|
||||
}
|
||||
|
||||
// Inject the main patch code where APP_URL is defined
|
||||
patchedData = patchedData
|
||||
.replace('const APP_URL =', `// ------- Injected by HTTP Toolkit Patcher -------\nconst email = \`${email.replace(/`/g, '\\`')}\`\nconst globalProxy = process.env.PROXY ?? \`${globalProxy ? globalProxy.replace(/`/g, '\\`') : ''}\`\n${patchCode}\n// ------- End patched content -------\nconst APP_URL =`)
|
||||
|
||||
if (data === patchedData || !patchedData) {
|
||||
console.error(chalk.redBright`Patch failed - couldn't find injection point`)
|
||||
cleanUp()
|
||||
}
|
||||
|
||||
fs.writeFileSync(indexPath, patchedData, 'utf-8')
|
||||
console.log(chalk.greenBright`Patched index.js successfully`)
|
||||
console.log(chalk.yellowBright`Installing dependencies...`)
|
||||
|
||||
try {
|
||||
const proc = spawn('npm install express https-proxy-agent', { cwd: tempPath, stdio: 'inherit', shell: true })
|
||||
activeProcesses.push(proc)
|
||||
await new Promise(resolve =>
|
||||
proc.on('close', resolve)
|
||||
)
|
||||
activeProcesses.splice(activeProcesses.indexOf(proc), 1)
|
||||
if (isCancelled) return
|
||||
} catch (e) {
|
||||
console.error(chalk.redBright`Error installing dependencies`, e)
|
||||
cleanUp()
|
||||
}
|
||||
|
||||
rm(path.join(tempPath, 'package-lock.json'))
|
||||
fs.copyFileSync(filePath, `${filePath}.bak`)
|
||||
console.log(chalk.greenBright`Created backup at {bold ${filePath}.bak}`)
|
||||
|
||||
console.log(chalk.yellowBright`Repacking the app...`)
|
||||
await asar.createPackage(tempPath, filePath)
|
||||
rm(tempPath)
|
||||
console.log(chalk.greenBright`App patched!`)
|
||||
|
||||
// Disable ASAR integrity checks so Electron doesn't complain
|
||||
await flipElectronFuses()
|
||||
}
|
||||
|
||||
const flipElectronFuses = async () => {
|
||||
console.log(chalk.yellowBright`Disabling ASAR integrity checks...`)
|
||||
|
||||
if (!fs.existsSync(exePath)) {
|
||||
console.log(chalk.yellowBright`Executable not found at ${exePath}, skipping fuse flipping`)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await flipFuses(exePath, {
|
||||
version: FuseVersion.V1,
|
||||
[FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: false,
|
||||
[FuseV1Options.OnlyLoadAppFromAsar]: false,
|
||||
})
|
||||
console.log(chalk.greenBright`Integrity checks disabled successfully`)
|
||||
} catch (e) {
|
||||
console.error(chalk.yellowBright`Failed to flip fuses (might already be done or not supported): ${/** @type {Error} */ (e).message}`)
|
||||
}
|
||||
}
|
||||
|
||||
switch (argv._[0]) {
|
||||
case 'patch':
|
||||
await patchApp()
|
||||
break
|
||||
case 'restore':
|
||||
try {
|
||||
console.log(chalk.blueBright`Restoring app...`)
|
||||
if (!fs.existsSync(path.join(appPath, 'app.asar.bak')))
|
||||
console.error(chalk.redBright`Backup file not found - maybe the app wasn't patched?`)
|
||||
else {
|
||||
fs.copyFileSync(path.join(appPath, 'app.asar.bak'), path.join(appPath, 'app.asar'))
|
||||
console.log(chalk.greenBright`App restored successfully`)
|
||||
}
|
||||
rm(path.join(os.tmpdir(), 'httptoolkit-patch'))
|
||||
} catch (e) {
|
||||
if (!isSudo && /** @type {any} */ (e).errno === -13) { // Permission denied
|
||||
console.error(chalk.redBright`Permission denied${!isWin ? ', try running with sudo' : ', try running node as administrator'}`)
|
||||
process.exit(1)
|
||||
}
|
||||
console.error(chalk.redBright`Error restoring app`, e)
|
||||
process.exit(1)
|
||||
}
|
||||
break
|
||||
case 'start':
|
||||
console.log(chalk.blueBright`Starting HTTP Toolkit...`)
|
||||
try {
|
||||
const command =
|
||||
isWin ? `"${path.resolve(appPath, '..', 'HTTP Toolkit.exe')}"`
|
||||
: isMac ? 'open -a "HTTP Toolkit"'
|
||||
: 'httptoolkit'
|
||||
const proc = spawn(command, { stdio: 'inherit', shell: true })
|
||||
proc.on('close', code => process.exit(code))
|
||||
} catch (e) {
|
||||
console.error(chalk.redBright`Error starting app`, e)
|
||||
if (isSudo) console.error(chalk.redBright`Try running without sudo`)
|
||||
process.exit(1)
|
||||
}
|
||||
break
|
||||
default:
|
||||
console.error(chalk.redBright`Unknown command`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (!isCancelled) console.log(chalk.greenBright`All done!`)
|
||||
Generated
+514
@@ -0,0 +1,514 @@
|
||||
{
|
||||
"name": "httptoolkit-pro-patcher",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "httptoolkit-pro-patcher",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@electron/asar": "^3.2.9",
|
||||
"@electron/fuses": "^1.8.0",
|
||||
"chalk": "4",
|
||||
"prompts": "^2.4.2",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.14.9",
|
||||
"@types/prompts": "^2.4.9",
|
||||
"@types/yargs": "^17.0.32"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"commander": "^5.0.0",
|
||||
"glob": "^7.1.6",
|
||||
"minimatch": "^3.0.4"
|
||||
},
|
||||
"bin": {
|
||||
"asar": "bin/asar.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/fuses": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@electron/fuses/-/fuses-1.8.0.tgz",
|
||||
"integrity": "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.1",
|
||||
"fs-extra": "^9.0.1",
|
||||
"minimist": "^1.2.5"
|
||||
},
|
||||
"bin": {
|
||||
"electron-fuses": "dist/bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.19.28",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.28.tgz",
|
||||
"integrity": "sha512-VyKBr25BuFDzBFCK5sUM6ZXiWfqgCTwTAOK8qzGV/m9FCirXYDlmczJ+d5dXBAQALGCdRRdbteKYfJ84NGEusw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/prompts": {
|
||||
"version": "2.4.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.4.9.tgz",
|
||||
"integrity": "sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"kleur": "^3.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/yargs": {
|
||||
"version": "17.0.35",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz",
|
||||
"integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/yargs-parser": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/yargs-parser": {
|
||||
"version": "21.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz",
|
||||
"integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/at-least-node": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
||||
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"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==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"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==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"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/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"at-least-node": "^1.0.0",
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"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/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"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"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"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==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonfile": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz",
|
||||
"integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/kleur": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prompts": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
|
||||
"integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"kleur": "^3.0.3",
|
||||
"sisteransi": "^1.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sisteransi": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
|
||||
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"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/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "httptoolkit-patcher",
|
||||
"version": "1.0.0",
|
||||
"description": "Patches HTTP Tool Kit.",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node . patch"
|
||||
},
|
||||
"author": "ayyo42069",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@electron/asar": "^3.2.9",
|
||||
"@electron/fuses": "^1.8.0",
|
||||
"chalk": "4",
|
||||
"prompts": "^2.4.2",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.14.9",
|
||||
"@types/prompts": "^2.4.9",
|
||||
"@types/yargs": "^17.0.32"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
// Patcher imports - need these for ESM compatibility
|
||||
import { createRequire as __patcherCreateRequire } from 'module';
|
||||
import { fileURLToPath as __patcherFileURLToPath } from 'url';
|
||||
import { dirname as __patcherDirname, join as __patcherJoin } from 'path';
|
||||
|
||||
// Load modules using require (works better with the app's setup)
|
||||
const __patcherRequire = __patcherCreateRequire(import.meta.url);
|
||||
const __patcherHttpsProxyAgent = __patcherRequire('https-proxy-agent').HttpsProxyAgent;
|
||||
const __patcherExpress = __patcherRequire('express');
|
||||
const __patcherHttps = __patcherRequire('https');
|
||||
const __patcherFs = __patcherRequire('fs');
|
||||
const __patcherOs = __patcherRequire('os');
|
||||
const __patcherPath = __patcherRequire('path');
|
||||
|
||||
// Simple HTTP request helper with redirect support
|
||||
const __patcherRequest = (method, url, redirectCount = 0) => new Promise((resolve, reject) => {
|
||||
const agent = globalProxy ? new __patcherHttpsProxyAgent(globalProxy.startsWith('http') ? globalProxy.replace(/^http:/, 'https:') : 'https://' + globalProxy) : undefined;
|
||||
|
||||
const req = __patcherHttps.request(url, { method, agent }, res => {
|
||||
let data = Buffer.alloc(0);
|
||||
res.on('data', chunk => data = Buffer.concat([data, chunk]));
|
||||
res.on('end', () => {
|
||||
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
||||
if (redirectCount >= 5) return reject(new Error('Too many redirects'));
|
||||
return resolve(__patcherRequest(method, res.headers.location, redirectCount + 1));
|
||||
}
|
||||
resolve({ data, statusCode: res.statusCode, headers: res.headers });
|
||||
});
|
||||
});
|
||||
req.on('error', reject);
|
||||
req.end();
|
||||
});
|
||||
|
||||
// Quick check if we can reach the HTTP Toolkit servers
|
||||
const __patcherHasInternet = () => __patcherRequest('HEAD', 'https://app.httptoolkit.tech')
|
||||
.then(r => r.statusCode >= 200 && r.statusCode < 400)
|
||||
.catch(() => false);
|
||||
|
||||
const __patcherPort = process.env.PATCHER_PORT || 5067;
|
||||
const __patcherTempPath = __patcherPath.join(__patcherOs.tmpdir(), 'httptoolkit-patch');
|
||||
|
||||
// Point the app to our local server instead of the real one
|
||||
process.env.APP_URL = `http://localhost:${__patcherPort}`;
|
||||
console.log(`[Patcher] Temp path: ${__patcherTempPath}`);
|
||||
|
||||
const __patcherApp = __patcherExpress();
|
||||
__patcherApp.disable('x-powered-by');
|
||||
|
||||
// Catch all requests and proxy them through our server
|
||||
__patcherApp.all(/(.*)/, async (req, res) => {
|
||||
console.log(`[Patcher] ${req.url}`);
|
||||
|
||||
let filePath = __patcherPath.join(__patcherTempPath, new URL(req.url, process.env.APP_URL).pathname === '/' ? 'index.html' : new URL(req.url, process.env.APP_URL).pathname);
|
||||
|
||||
// Some routes need .html extension
|
||||
if (['/view', '/intercept', '/settings', '/mock'].includes(new URL(req.url, process.env.APP_URL).pathname)) {
|
||||
filePath += '.html';
|
||||
}
|
||||
|
||||
// Block service worker - it causes caching headaches
|
||||
if (new URL(req.url, process.env.APP_URL).pathname === '/ui-update-worker.js') {
|
||||
return res.status(404).send('Not found');
|
||||
}
|
||||
|
||||
if (!__patcherFs.existsSync(__patcherTempPath)) {
|
||||
__patcherFs.mkdirSync(__patcherTempPath);
|
||||
}
|
||||
|
||||
// Offline mode - serve from cache if no internet
|
||||
if (!(await __patcherHasInternet())) {
|
||||
if (__patcherFs.existsSync(filePath)) {
|
||||
return res.sendFile(filePath);
|
||||
}
|
||||
return res.status(404).send('No internet and file not cached');
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if we have a cached copy that's still fresh
|
||||
if (__patcherFs.existsSync(filePath)) {
|
||||
try {
|
||||
const remoteDate = await __patcherRequest('HEAD', `https://app.httptoolkit.tech${req.url}`).then(r => new Date(r.headers['last-modified']));
|
||||
if (remoteDate < new Date(__patcherFs.statSync(filePath).mtime)) {
|
||||
return res.sendFile(filePath);
|
||||
}
|
||||
} catch (e) { /* ignore, just redownload */ }
|
||||
}
|
||||
|
||||
// Download from the real server
|
||||
const remoteFile = await __patcherRequest('GET', `https://app.httptoolkit.tech${req.url}`);
|
||||
for (const [key, value] of Object.entries(remoteFile.headers)) res.setHeader(key, value);
|
||||
|
||||
// Create directories if needed
|
||||
const mkdirp = dir => {
|
||||
if (!__patcherFs.existsSync(dir)) {
|
||||
mkdirp(__patcherPath.dirname(dir));
|
||||
__patcherFs.mkdirSync(dir);
|
||||
}
|
||||
};
|
||||
mkdirp(__patcherPath.dirname(filePath));
|
||||
|
||||
let data = remoteFile.data;
|
||||
|
||||
// This is where the magic happens - patch main.js to inject pro subscription
|
||||
if (new URL(req.url, process.env.APP_URL).pathname === '/main.js') {
|
||||
console.log(`[Patcher] Patching main.js...`);
|
||||
res.setHeader('Cache-Control', 'no-store');
|
||||
|
||||
data = data.toString();
|
||||
|
||||
// Find the account store class and module names (they're minified so we gotta search for them)
|
||||
const accStoreName = data.match(/class ([0-9A-Za-z_]+){constructor\(e\){this\.goToSettings=e/)?.[1];
|
||||
const modName = data.match(/([0-9A-Za-z_]+).(getLatestUserData|getLastUserData)/)?.[1];
|
||||
|
||||
if (!accStoreName) console.error(`[Patcher] Couldn't find account store class`);
|
||||
else if (!modName) console.error(`[Patcher] Couldn't find user data module`);
|
||||
else {
|
||||
// Override the user data functions to return our fake pro user
|
||||
let patched = data.replace(
|
||||
`class ${accStoreName}{`,
|
||||
`["getLatestUserData","getLastUserData"].forEach(p=>Object.defineProperty(${modName},p,{value:()=>user}));class ${accStoreName}{`
|
||||
);
|
||||
|
||||
if (patched === data) {
|
||||
console.error(`[Patcher] Patch failed - couldn't find injection point`);
|
||||
} else {
|
||||
// Inject our pro user at the top
|
||||
patched = `const user=${JSON.stringify({
|
||||
email,
|
||||
subscription: {
|
||||
status: 'active',
|
||||
expiry: new Date('6767-06-07').toISOString(),
|
||||
sku: 'pro-annual',
|
||||
},
|
||||
userId: 'patcher',
|
||||
banned: false,
|
||||
featureFlags: [],
|
||||
teamSubscription: null,
|
||||
})};user.subscription.expiry=new Date(user.subscription.expiry);` + patched;
|
||||
|
||||
data = patched;
|
||||
console.log(`[Patcher] main.js patched successfully!`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__patcherFs.writeFileSync(filePath, data);
|
||||
res.sendFile(filePath);
|
||||
} catch (e) {
|
||||
console.error(`[Patcher] Error: ${e.message}`);
|
||||
res.status(500).send('Something went wrong');
|
||||
}
|
||||
});
|
||||
|
||||
__patcherApp.listen(__patcherPort, () => console.log(`[Patcher] Running on port ${__patcherPort}`));
|
||||
|
||||
// Fix CORS so the app can talk to our local server
|
||||
app.on('ready', () => {
|
||||
session.defaultSession.webRequest.onBeforeSendHeaders((details, callback) => {
|
||||
// Block telemetry
|
||||
const blocked = ['events.httptoolkit.tech'];
|
||||
try {
|
||||
const host = new URL(details.url).hostname;
|
||||
if (blocked.includes(host) || details.url?.includes('sentry')) {
|
||||
return callback({ cancel: true });
|
||||
}
|
||||
} catch (e) { }
|
||||
|
||||
details.requestHeaders.Origin = 'https://app.httptoolkit.tech';
|
||||
callback({ requestHeaders: details.requestHeaders });
|
||||
});
|
||||
|
||||
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
|
||||
if (details.responseHeaders) {
|
||||
details.responseHeaders['Access-Control-Allow-Origin'] = [`http://localhost:${__patcherPort}`];
|
||||
delete details.responseHeaders['access-control-allow-origin'];
|
||||
}
|
||||
callback({ responseHeaders: details.responseHeaders });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user