http-mitm-proxy-ui 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +359 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +213 -0
- package/dist/index.js.map +1 -0
- package/dist/proxy/RequestStore.d.ts +31 -0
- package/dist/proxy/RequestStore.d.ts.map +1 -0
- package/dist/proxy/RequestStore.js +163 -0
- package/dist/proxy/RequestStore.js.map +1 -0
- package/dist/proxy/index.d.ts +56 -0
- package/dist/proxy/index.d.ts.map +1 -0
- package/dist/proxy/index.js +135 -0
- package/dist/proxy/index.js.map +1 -0
- package/dist/public/assets/index-BFoa2rnZ.js +3 -0
- package/dist/public/assets/index-DxoSovY1.css +1 -0
- package/dist/public/favicon.svg +1 -0
- package/dist/public/icons.svg +24 -0
- package/dist/public/index.html +14 -0
- package/dist/ui/server.d.ts +28 -0
- package/dist/ui/server.d.ts.map +1 -0
- package/dist/ui/server.js +319 -0
- package/dist/ui/server.js.map +1 -0
- package/package.json +55 -0
- package/patches/http-mitm-proxy+1.1.0.patch +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# http-mitm-proxy-ui
|
|
2
|
+
|
|
3
|
+
A self-contained Node.js package that bundles `http-mitm-proxy` with a modern web-based UI for inspecting HTTP/HTTPS traffic in real time.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Real-time Traffic Inspection**: Live stream of HTTP/HTTPS requests and responses with WebSocket updates
|
|
10
|
+
- **Complete Request/Response Details**: Headers, bodies, cookies, query parameters with syntax highlighting
|
|
11
|
+
- **Advanced Filtering & Search**: Filter by domain, method, status code, content type with full-text search
|
|
12
|
+
- **Export Data**: Export traffic as JSON or CSV for offline analysis and sharing
|
|
13
|
+
- **HTTPS Interception**: Auto-generates and manages SSL certificates with easy CA download
|
|
14
|
+
- **Standalone CLI**: Single command to start both proxy and UI with configurable options
|
|
15
|
+
- **REST API**: Programmatic access to traffic data and configuration
|
|
16
|
+
- **Material Design UI**: Clean, responsive interface with red/black on white theme
|
|
17
|
+
|
|
18
|
+
## Guides
|
|
19
|
+
|
|
20
|
+
- 📖 **[User Guide](docs/guides/USER-GUIDE.md)** — Complete documentation with screenshots
|
|
21
|
+
- 🔍 **[Qwen Code Use Cases](docs/guides/use-cases-qwen-code.md)** — Inspect Qwen Code API traffic with examples
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install http-mitm-proxy-ui
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
### CLI Usage
|
|
32
|
+
|
|
33
|
+
Start with default ports (proxy: 8080, UI: 3000):
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx http-mitm-proxy-ui
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Custom configuration:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
http-mitm-proxy-ui --proxy-port 9090 --ui-port 4000 --ssl-ca-dir ./my-certs
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Available options:
|
|
46
|
+
- `-p, --proxy-port <port>`: MITM proxy server port (default: 8080)
|
|
47
|
+
- `-u, --ui-port <port>`: Web UI server port (default: 3000)
|
|
48
|
+
- `-H, --headless`: Run in proxy-only mode (no UI)
|
|
49
|
+
- `-c, --config <path>`: Path to JSON config file
|
|
50
|
+
- `--ssl-ca-dir <path>`: Directory for SSL CA certificates
|
|
51
|
+
- `--ca-cert <path>`: Path to custom CA certificate file (.pem)
|
|
52
|
+
- `--ca-key <path>`: Path to custom CA private key file (.pem)
|
|
53
|
+
- `--max-requests <count>`: Max requests to keep in memory (default: 1000)
|
|
54
|
+
- `-h, --help`: Display help
|
|
55
|
+
|
|
56
|
+
### Using Custom CA Certificates
|
|
57
|
+
|
|
58
|
+
If you already have a CA certificate and key (e.g., from a corporate PKI or a previous proxy setup), you can use them instead of auto-generating:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
http-mitm-proxy-ui --ca-cert /path/to/ca.pem --ca-key /path/to/ca.key
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Both `--ca-cert` and `--ca-key` must be provided together. The files are copied into the `--ssl-ca-dir` (default: `~/.http-mitm-proxy-ui/ca`) in the format expected by the proxy. When omitted, a new CA is auto-generated on first run.
|
|
65
|
+
|
|
66
|
+
You can also set these in a JSON config file:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"caCertPath": "/path/to/ca.pem",
|
|
71
|
+
"caKeyPath": "/path/to/ca.key"
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Programmatic Usage
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { createProxyUI } from 'http-mitm-proxy-ui';
|
|
79
|
+
|
|
80
|
+
const proxy = createProxyUI({
|
|
81
|
+
proxyPort: 8080,
|
|
82
|
+
uiPort: 3000,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
proxy.on('request', (req) => {
|
|
86
|
+
console.log('Request:', req.method, req.url);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
proxy.on('response', (req) => {
|
|
90
|
+
console.log('Response:', req.response?.statusCode);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
await proxy.start();
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Architecture
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
┌─────────────────────────────────────────────┐
|
|
100
|
+
│ http-mitm-proxy-ui │
|
|
101
|
+
├──────────────────┬──────────────────────────┤
|
|
102
|
+
│ MITM Proxy │ Web UI Server │
|
|
103
|
+
│ (http-mitm- │ (Express + Vue 3) │
|
|
104
|
+
│ proxy core) │ │
|
|
105
|
+
│ - Intercept │ - WebSocket for │
|
|
106
|
+
│ HTTP/HTTPS │ real-time updates │
|
|
107
|
+
│ - Capture & │ - REST API for │
|
|
108
|
+
│ emit events │ history/query │
|
|
109
|
+
│ │ - Static file serving │
|
|
110
|
+
└────────┬─────────┴────────────┬─────────────┘
|
|
111
|
+
│ │
|
|
112
|
+
▼ ▼
|
|
113
|
+
Network Traffic Browser (localhost:3000)
|
|
114
|
+
(localhost:8080)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## API Endpoints
|
|
118
|
+
|
|
119
|
+
When the UI server is running (not headless):
|
|
120
|
+
|
|
121
|
+
- `GET /api/health` - Health check
|
|
122
|
+
- `GET /api/requests` - List requests with filtering/pagination
|
|
123
|
+
- `GET /api/requests/:id` - Get specific request details
|
|
124
|
+
- `DELETE /api/requests` - Clear request history
|
|
125
|
+
- `GET /api/config` - Get current configuration
|
|
126
|
+
- `GET /api/ca-cert` - Download CA certificate for trust installation
|
|
127
|
+
- `GET /*` - Serves the Vue SPA (all other routes)
|
|
128
|
+
|
|
129
|
+
## WebSocket Events
|
|
130
|
+
|
|
131
|
+
Connect to `ws://localhost:3000/ws` for real-time updates:
|
|
132
|
+
|
|
133
|
+
- `{ type: 'init', data: [...] }` - Initial state on connection
|
|
134
|
+
- `{ type: 'request', data: RequestRecord }` - New request captured
|
|
135
|
+
- `{ type: 'response', data: RequestRecord }` - Response received
|
|
136
|
+
- `{ type: 'error', data: { message: string } }` - Error occurred
|
|
137
|
+
- `{ type: 'clear', data: {} }` - History cleared
|
|
138
|
+
|
|
139
|
+
## Configuration
|
|
140
|
+
|
|
141
|
+
Create a `proxy-config.json` file:
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"proxyPort": 8080,
|
|
146
|
+
"uiPort": 3000,
|
|
147
|
+
"sslCaDir": "./certs",
|
|
148
|
+
"maxRequests": 1000,
|
|
149
|
+
"headless": false
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Then start with: `http-mitm-proxy-ui --config ./proxy-config.json`
|
|
154
|
+
|
|
155
|
+
## Development
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# Install dependencies
|
|
159
|
+
npm install
|
|
160
|
+
|
|
161
|
+
# Build the package
|
|
162
|
+
npm run build
|
|
163
|
+
|
|
164
|
+
# Start in development mode (watches for changes)
|
|
165
|
+
npm run dev
|
|
166
|
+
|
|
167
|
+
# Run tests
|
|
168
|
+
npm test
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Use Cases
|
|
172
|
+
|
|
173
|
+
### Debugging API Calls
|
|
174
|
+
1. Start the proxy: `http-mitm-proxy-ui`
|
|
175
|
+
2. Configure your application to use `localhost:8080` as HTTP/HTTPS proxy
|
|
176
|
+
3. Visit `http://localhost:3000` to see live traffic
|
|
177
|
+
4. Use filtering to isolate specific endpoints
|
|
178
|
+
5. Inspect full request/response details including headers, bodies, and timing
|
|
179
|
+
|
|
180
|
+
### Mobile App Testing
|
|
181
|
+
1. Start the proxy on your development machine
|
|
182
|
+
2. Configure your mobile device to use your machine's IP:8080 as proxy
|
|
183
|
+
3. Install the CA certificate on your device (download from `http://YOUR_IP:3000/api/ca-cert`)
|
|
184
|
+
4. Inspect mobile app network calls with full visibility
|
|
185
|
+
|
|
186
|
+
### Security Testing
|
|
187
|
+
1. Capture and inspect all traffic for unexpected requests or data leaks
|
|
188
|
+
2. Verify authorization headers and sensitive data in transit
|
|
189
|
+
3. Export captured traffic as JSON or CSV for team analysis
|
|
190
|
+
|
|
191
|
+
## Configuring Existing Applications to Use the Proxy
|
|
192
|
+
|
|
193
|
+
The primary purpose of this tool is to **intercept and inspect traffic from existing applications without modifying their code**. You do this by setting proxy environment variables or command-line flags.
|
|
194
|
+
|
|
195
|
+
### Step 1: Install the CA Certificate (for HTTPS)
|
|
196
|
+
|
|
197
|
+
Before intercepting HTTPS traffic, you must trust the proxy's CA certificate:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
# Start the proxy once to generate the CA
|
|
201
|
+
http-mitm-proxy-ui
|
|
202
|
+
|
|
203
|
+
# Download the CA certificate
|
|
204
|
+
curl http://localhost:3000/api/ca-cert -o http-mitm-proxy-ca.pem
|
|
205
|
+
|
|
206
|
+
# On macOS, add to Keychain and trust it:
|
|
207
|
+
security add-trusted-cert -d -r trustRoot -k ~/Library/Keychains/login.keychain http-mitm-proxy-ca.pem
|
|
208
|
+
|
|
209
|
+
# On Linux (Debian/Ubuntu):
|
|
210
|
+
sudo cp http-mitm-proxy-ca.pem /usr/local/share/ca-certificates/
|
|
211
|
+
sudo update-ca-certificates
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Step 2: Configure Your Application
|
|
215
|
+
|
|
216
|
+
#### Node.js Applications
|
|
217
|
+
|
|
218
|
+
Node.js respects standard proxy environment variables. Start your app with:
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
# For HTTP and HTTPS traffic
|
|
222
|
+
HTTP_PROXY=http://localhost:8080 HTTPS_PROXY=http://localhost:8080 node your-app.js
|
|
223
|
+
|
|
224
|
+
# Or if using npm scripts
|
|
225
|
+
HTTP_PROXY=http://localhost:8080 HTTPS_PROXY=http://localhost:8080 npm start
|
|
226
|
+
|
|
227
|
+
# For apps that use the `proxy` env var (some libraries)
|
|
228
|
+
proxy=http://localhost:8080 node your-app.js
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Note**: Some HTTP clients in Node.js (like `axios`, `node-fetch`) don't automatically respect env vars. For those, you may need to pass an `agent` with proxy support, or use `global-agent`:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
# Force all Node.js HTTP clients through the proxy
|
|
235
|
+
npx global-agent bootstrap -- node your-app.js
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### curl / wget
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
# curl with proxy
|
|
242
|
+
curl --proxy http://localhost:8080 https://api.example.com/data
|
|
243
|
+
|
|
244
|
+
# curl with explicit HTTPS proxy (for HTTPS targets)
|
|
245
|
+
curl --proxy http://localhost:8080 --proxy-insecure https://api.example.com/data
|
|
246
|
+
|
|
247
|
+
# wget with proxy
|
|
248
|
+
export http_proxy=http://localhost:8080
|
|
249
|
+
export https_proxy=http://localhost:8080
|
|
250
|
+
wget https://api.example.com/data
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### Java Applications
|
|
254
|
+
|
|
255
|
+
Java uses system properties for proxy configuration. Pass them via `-D` flags:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Basic HTTP proxy
|
|
259
|
+
java -Dhttp.proxyHost=localhost -Dhttp.proxyPort=8080 \
|
|
260
|
+
-Dhttps.proxyHost=localhost -Dhttps.proxyPort=8080 \
|
|
261
|
+
-jar your-app.jar
|
|
262
|
+
|
|
263
|
+
# For Spring Boot apps
|
|
264
|
+
java -Dhttp.proxyHost=localhost -Dhttp.proxyPort=8080 \
|
|
265
|
+
-Dhttps.proxyHost=localhost -Dhttps.proxyPort=8080 \
|
|
266
|
+
-Dhttp.nonProxyHosts="localhost|127.0.0.1" \
|
|
267
|
+
-jar your-app.jar
|
|
268
|
+
|
|
269
|
+
# For Maven-based apps
|
|
270
|
+
mvn -Dhttp.proxyHost=localhost -Dhttp.proxyPort=8080 \
|
|
271
|
+
-Dhttps.proxyHost=localhost -Dhttps.proxyPort=8080 \
|
|
272
|
+
spring-boot:run
|
|
273
|
+
|
|
274
|
+
# For Gradle-based apps
|
|
275
|
+
gradle -Dorg.gradle.jvmargs="-Dhttp.proxyHost=localhost -Dhttp.proxyPort=8080 -Dhttps.proxyHost=localhost -Dhttps.proxyPort=8080" bootRun
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**Note**: Java's default HTTP client may not intercept all traffic (e.g., OkHttp, Apache HttpClient may need separate proxy config). See [Java-specific notes below](#java-specific-http-clients).
|
|
279
|
+
|
|
280
|
+
#### Python Applications
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
# Standard library (urllib, requests with env var support)
|
|
284
|
+
HTTP_PROXY=http://localhost:8080 HTTPS_PROXY=http://localhost:8080 python your-app.py
|
|
285
|
+
|
|
286
|
+
# For pip itself (debugging package installs)
|
|
287
|
+
HTTP_PROXY=http://localhost:8080 HTTPS_PROXY=http://localhost:8080 pip install requests
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
#### Docker Containers
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
# Pass proxy env vars to container
|
|
294
|
+
docker run -e HTTP_PROXY=http://host.docker.internal:8080 \
|
|
295
|
+
-e HTTPS_PROXY=http://host.docker.internal:8080 \
|
|
296
|
+
your-image
|
|
297
|
+
|
|
298
|
+
# Or in docker-compose.yml:
|
|
299
|
+
# services:
|
|
300
|
+
# app:
|
|
301
|
+
# environment:
|
|
302
|
+
# - HTTP_PROXY=http://host.docker.internal:8080
|
|
303
|
+
# - HTTPS_PROXY=http://host.docker.internal:8080
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Note**: On macOS/Windows, use `host.docker.internal` instead of `localhost` to reach the host machine from inside a container.
|
|
307
|
+
|
|
308
|
+
#### React / Angular / Vue Dev Servers
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
# React (Create React App)
|
|
312
|
+
HTTP_PROXY=http://localhost:8080 npm start
|
|
313
|
+
|
|
314
|
+
# Angular
|
|
315
|
+
HTTP_PROXY=http://localhost:8080 ng serve
|
|
316
|
+
|
|
317
|
+
# Vite
|
|
318
|
+
HTTP_PROXY=http://localhost:8080 npm run dev
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Java-Specific HTTP Clients
|
|
322
|
+
|
|
323
|
+
Some Java HTTP libraries don't respect the `-D` system properties above. Configure them individually:
|
|
324
|
+
|
|
325
|
+
**OkHttp:**
|
|
326
|
+
```java
|
|
327
|
+
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", 8080));
|
|
328
|
+
OkHttpClient client = new OkHttpClient.Builder()
|
|
329
|
+
.proxy(proxy)
|
|
330
|
+
.build();
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Apache HttpClient:**
|
|
334
|
+
```java
|
|
335
|
+
HttpHost proxy = new HttpHost("localhost", 8080, "http");
|
|
336
|
+
RequestConfig config = RequestConfig.custom()
|
|
337
|
+
.setProxy(proxy)
|
|
338
|
+
.build();
|
|
339
|
+
CloseableHttpClient client = HttpClients.custom()
|
|
340
|
+
.setDefaultRequestConfig(config)
|
|
341
|
+
.build();
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
**Java 11+ HttpClient:**
|
|
345
|
+
```java
|
|
346
|
+
HttpClient client = HttpClient.newBuilder()
|
|
347
|
+
.proxy(ProxySelector.of(new InetSocketAddress("localhost", 8080)))
|
|
348
|
+
.build();
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## License
|
|
352
|
+
|
|
353
|
+
ISC
|
|
354
|
+
|
|
355
|
+
## Author & Credits
|
|
356
|
+
|
|
357
|
+
- **Dung Tran** ([dungviettran89](https://github.com/dungviettran89))
|
|
358
|
+
- Built with [OpenClaw](https://github.com/dungviettran89/openclaw) — an AI agent framework for autonomous development
|
|
359
|
+
- Code written with assistance from [Qwen Coder](https://qwenlm.github.io/) — an AI coding assistant
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
const commander_1 = require("commander");
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const proxy_1 = require("./proxy");
|
|
42
|
+
const server_1 = require("./ui/server");
|
|
43
|
+
// node-forge has no @types, but it's already a dependency and we only use it for public key extraction
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-explicit-any
|
|
45
|
+
const nodeForge = require('node-forge');
|
|
46
|
+
const DEFAULT_PROXY_PORT = 8080;
|
|
47
|
+
const DEFAULT_UI_PORT = 3000;
|
|
48
|
+
const DEFAULT_SSL_CA_DIR = path.join(os.homedir(), '.http-mitm-proxy-ui', 'ca');
|
|
49
|
+
const DEFAULT_MAX_REQUESTS = 1000;
|
|
50
|
+
async function loadConfigFile(configPath) {
|
|
51
|
+
if (!configPath)
|
|
52
|
+
return {};
|
|
53
|
+
try {
|
|
54
|
+
const { default: fs } = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
55
|
+
const raw = fs.readFileSync(configPath, 'utf-8');
|
|
56
|
+
return JSON.parse(raw);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
console.error(`Warning: Could not load config file "${configPath}": ${err.message}`);
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* If custom CA cert/key are provided, copy them to the expected locations
|
|
65
|
+
* in sslCaDir so http-mitm-proxy's CA class loads them instead of generating.
|
|
66
|
+
* The CA class expects three files: certs/ca.pem, keys/ca.private.key, keys/ca.public.key
|
|
67
|
+
*/
|
|
68
|
+
async function setupCaFiles(caCertPath, caKeyPath, sslCaDir) {
|
|
69
|
+
const certsDir = path.join(sslCaDir, 'certs');
|
|
70
|
+
const keysDir = path.join(sslCaDir, 'keys');
|
|
71
|
+
// Ensure directories exist
|
|
72
|
+
fs.mkdirSync(certsDir, { recursive: true });
|
|
73
|
+
fs.mkdirSync(keysDir, { recursive: true });
|
|
74
|
+
// Copy cert and private key to expected locations
|
|
75
|
+
const destCert = path.join(certsDir, 'ca.pem');
|
|
76
|
+
const destPrivateKey = path.join(keysDir, 'ca.private.key');
|
|
77
|
+
const destPublicKey = path.join(keysDir, 'ca.public.key');
|
|
78
|
+
fs.copyFileSync(caCertPath, destCert);
|
|
79
|
+
fs.copyFileSync(caKeyPath, destPrivateKey);
|
|
80
|
+
// Extract public key from the private key using node-forge (already a dependency)
|
|
81
|
+
const pki = nodeForge.pki;
|
|
82
|
+
const privateKey = pki.privateKeyFromPem(fs.readFileSync(caKeyPath, 'utf-8'));
|
|
83
|
+
const publicKey = pki.setRsaPublicKey(privateKey.n, privateKey.e);
|
|
84
|
+
fs.writeFileSync(destPublicKey, pki.publicKeyToPem(publicKey));
|
|
85
|
+
console.log(` CA cert: ${caCertPath} → ${destCert}`);
|
|
86
|
+
console.log(` CA key: ${caKeyPath} → ${destPrivateKey}`);
|
|
87
|
+
console.log(` CA pub: (derived) → ${destPublicKey}`);
|
|
88
|
+
}
|
|
89
|
+
async function main() {
|
|
90
|
+
const program = new commander_1.Command();
|
|
91
|
+
program
|
|
92
|
+
.name('http-mitm-proxy-ui')
|
|
93
|
+
.description('HTTP MITM Proxy with a web-based UI for inspecting and modifying traffic')
|
|
94
|
+
.version('1.0.0')
|
|
95
|
+
.option('-p, --proxy-port <port>', 'Port for the MITM proxy server', String(DEFAULT_PROXY_PORT))
|
|
96
|
+
.option('-u, --ui-port <port>', 'Port for the web UI server', String(DEFAULT_UI_PORT))
|
|
97
|
+
.option('-H, --headless', 'Run in headless mode (proxy only, no UI)', false)
|
|
98
|
+
.option('-c, --config <path>', 'Path to a JSON config file')
|
|
99
|
+
.option('--ssl-ca-dir <path>', 'Directory for storing CA certificates')
|
|
100
|
+
.option('--max-requests <count>', 'Maximum number of requests to keep in memory', String(DEFAULT_MAX_REQUESTS))
|
|
101
|
+
.option('--no-modification', 'Disable request/response modification features')
|
|
102
|
+
.option('--ca-cert <path>', 'Path to custom CA certificate file (.pem)')
|
|
103
|
+
.option('--ca-key <path>', 'Path to custom CA private key file (.pem)')
|
|
104
|
+
.parse(process.argv);
|
|
105
|
+
const opts = program.opts();
|
|
106
|
+
// Load config file if provided
|
|
107
|
+
const fileConfig = await loadConfigFile(opts.config);
|
|
108
|
+
// Merge: defaults < file config < CLI flags
|
|
109
|
+
const config = {
|
|
110
|
+
proxyPort: parseInt(fileConfig.proxyPort != null ? String(fileConfig.proxyPort) : opts.proxyPort, 10),
|
|
111
|
+
uiPort: parseInt(fileConfig.uiPort != null ? String(fileConfig.uiPort) : opts.uiPort, 10),
|
|
112
|
+
headless: fileConfig.headless != null ? Boolean(fileConfig.headless) : Boolean(opts.headless),
|
|
113
|
+
sslCaDir: fileConfig.sslCaDir || opts.sslCaDir || DEFAULT_SSL_CA_DIR,
|
|
114
|
+
maxRequests: parseInt(fileConfig.maxRequests != null ? String(fileConfig.maxRequests) : opts.maxRequests, 10),
|
|
115
|
+
enableModification: fileConfig.enableModification != null
|
|
116
|
+
? Boolean(fileConfig.enableModification)
|
|
117
|
+
: opts.enableModification !== false,
|
|
118
|
+
caCertPath: fileConfig.caCertPath || opts.caCert,
|
|
119
|
+
caKeyPath: fileConfig.caKeyPath || opts.caKey,
|
|
120
|
+
};
|
|
121
|
+
// Validate CA cert/key: both or neither must be provided
|
|
122
|
+
if ((config.caCertPath && !config.caKeyPath) || (!config.caCertPath && config.caKeyPath)) {
|
|
123
|
+
console.error('Error: --ca-cert and --ca-key must be provided together.');
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
// Validate CA cert/key files exist
|
|
127
|
+
if (config.caCertPath && !fs.existsSync(config.caCertPath)) {
|
|
128
|
+
console.error(`Error: CA certificate file not found: ${config.caCertPath}`);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
if (config.caKeyPath && !fs.existsSync(config.caKeyPath)) {
|
|
132
|
+
console.error(`Error: CA private key file not found: ${config.caKeyPath}`);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
// Validate ports
|
|
136
|
+
if (config.proxyPort < 1 || config.proxyPort > 65535) {
|
|
137
|
+
console.error(`Error: Invalid proxy port ${config.proxyPort}. Must be between 1 and 65535.`);
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
if (config.uiPort < 1 || config.uiPort > 65535) {
|
|
141
|
+
console.error(`Error: Invalid UI port ${config.uiPort}. Must be between 1 and 65535.`);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
if (config.proxyPort === config.uiPort) {
|
|
145
|
+
console.error('Error: Proxy port and UI port must be different.');
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
const proxyConfig = {
|
|
149
|
+
proxyPort: config.proxyPort,
|
|
150
|
+
uiPort: config.uiPort,
|
|
151
|
+
sslCaDir: config.sslCaDir,
|
|
152
|
+
maxRequests: config.maxRequests,
|
|
153
|
+
enableModification: config.enableModification,
|
|
154
|
+
headless: config.headless,
|
|
155
|
+
caCertPath: config.caCertPath,
|
|
156
|
+
caKeyPath: config.caKeyPath,
|
|
157
|
+
};
|
|
158
|
+
console.log('Starting http-mitm-proxy-ui...');
|
|
159
|
+
console.log(` Proxy: localhost:${config.proxyPort}`);
|
|
160
|
+
if (!config.headless) {
|
|
161
|
+
console.log(` UI: http://localhost:${config.uiPort}`);
|
|
162
|
+
}
|
|
163
|
+
console.log(` Headless: ${config.headless}`);
|
|
164
|
+
if (config.caCertPath && config.caKeyPath) {
|
|
165
|
+
console.log(` Custom CA: yes`);
|
|
166
|
+
await setupCaFiles(config.caCertPath, config.caKeyPath, config.sslCaDir);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
console.log(` Custom CA: no (auto-generate)`);
|
|
170
|
+
}
|
|
171
|
+
console.log('');
|
|
172
|
+
// Start the proxy
|
|
173
|
+
const proxy = new proxy_1.MitmProxy(proxyConfig);
|
|
174
|
+
proxy.on('error', (err) => {
|
|
175
|
+
console.error('Proxy error:', err.message);
|
|
176
|
+
});
|
|
177
|
+
try {
|
|
178
|
+
await proxy.start();
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
console.error(`Failed to start proxy: ${err.message}`);
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
// Start the UI (unless in headless mode)
|
|
185
|
+
let uiServer = null;
|
|
186
|
+
if (!config.headless) {
|
|
187
|
+
uiServer = new server_1.UIServer(proxy, proxyConfig);
|
|
188
|
+
try {
|
|
189
|
+
await uiServer.start();
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
console.error(`Failed to start UI server: ${err.message}`);
|
|
193
|
+
proxy.stop();
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Graceful shutdown
|
|
198
|
+
const shutdown = (signal) => {
|
|
199
|
+
console.log(`\nReceived ${signal}. Shutting down...`);
|
|
200
|
+
if (uiServer) {
|
|
201
|
+
uiServer.stop();
|
|
202
|
+
}
|
|
203
|
+
proxy.stop();
|
|
204
|
+
process.exit(0);
|
|
205
|
+
};
|
|
206
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
207
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
208
|
+
}
|
|
209
|
+
main().catch((err) => {
|
|
210
|
+
console.error('Fatal error:', err);
|
|
211
|
+
process.exit(1);
|
|
212
|
+
});
|
|
213
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { RequestRecord } from '.';
|
|
2
|
+
/**
|
|
3
|
+
* Persistent request store backed by a local JSON file via lowdb.
|
|
4
|
+
*/
|
|
5
|
+
export declare class RequestStore {
|
|
6
|
+
private db;
|
|
7
|
+
private filePath;
|
|
8
|
+
constructor(dbPath?: string);
|
|
9
|
+
init(): Promise<this>;
|
|
10
|
+
/**
|
|
11
|
+
* Add a new request record to the store.
|
|
12
|
+
*/
|
|
13
|
+
add(req: RequestRecord): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Update an existing request record (merge by id).
|
|
16
|
+
*/
|
|
17
|
+
update(req: RequestRecord): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Get all requests, converted back to live form.
|
|
20
|
+
*/
|
|
21
|
+
getAll(): RequestRecord[];
|
|
22
|
+
/**
|
|
23
|
+
* Get a single request by id.
|
|
24
|
+
*/
|
|
25
|
+
getById(id: string): RequestRecord | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Clear all stored requests.
|
|
28
|
+
*/
|
|
29
|
+
clear(): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=RequestStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RequestStore.d.ts","sourceRoot":"","sources":["../../src/proxy/RequestStore.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAkB,MAAM,GAAG,CAAA;AA+GtD;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,EAAE,CAAuD;IACjE,OAAO,CAAC,QAAQ,CAAQ;gBAEZ,MAAM,CAAC,EAAE,MAAM;IAIrB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B;;OAEG;IACG,GAAG,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAO5C;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAU/C;;OAEG;IACH,MAAM,IAAI,aAAa,EAAE;IAIzB;;OAEG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAK9C;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B"}
|