preflite 1.1.3 → 1.1.6

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.
@@ -1,156 +0,0 @@
1
- import { NetworkMockServer } from "./NetworkMockServer.js";
2
- import { configureDeviceProxy, removeDeviceProxy, proxyHostForPlatform } from "./device-proxy.js";
3
- import { createServer } from "node:http";
4
- import { execSync } from "node:child_process";
5
- export class NetworkMockService {
6
- server = new NetworkMockServer();
7
- activeConfig = null;
8
- certServer = null;
9
- certServerPort = 0;
10
- qrPng = null;
11
- async start(config) {
12
- if (this.server.getPort() > 0) {
13
- await this.stop();
14
- }
15
- const port = await this.server.start(config.rules, "0.0.0.0", config.preferredPort ?? 0);
16
- const proxyHost = proxyHostForPlatform(config.platform);
17
- configureDeviceProxy({
18
- platform: config.platform,
19
- deviceId: config.deviceId,
20
- proxyHost,
21
- proxyPort: port,
22
- });
23
- this.activeConfig = { platform: config.platform, deviceId: config.deviceId };
24
- this.startCertServer(proxyHost, port);
25
- return this.server.getStats();
26
- }
27
- async stop() {
28
- if (this.activeConfig) {
29
- try {
30
- removeDeviceProxy(this.activeConfig.platform, this.activeConfig.deviceId);
31
- }
32
- catch {
33
- // best-effort cleanup
34
- }
35
- this.activeConfig = null;
36
- }
37
- this.stopCertServer();
38
- await this.server.stop();
39
- return this.server.getStats();
40
- }
41
- getCertServerUrl() {
42
- if (!this.certServer || this.certServerPort === 0)
43
- return null;
44
- const host = proxyHostForPlatform(this.activeConfig?.platform ?? "ios");
45
- return `http://${host}:${this.certServerPort}`;
46
- }
47
- startCertServer(proxyHost, proxyPort) {
48
- this.stopCertServer();
49
- const caCert = this.server.getRootCACert();
50
- const mobileConfig = this.server.generateMobileConfig(proxyHost, proxyPort);
51
- // Generate QR PNG using Python qrcode library
52
- const qrUrl = `http://${proxyHost}:0/preflight.mobileconfig`; // port placeholder
53
- this.qrPng = this.generateQrPng(qrUrl);
54
- const qrPng = this.qrPng;
55
- const html = this.buildCertPage(proxyHost, proxyPort);
56
- this.certServer = createServer((req, res) => {
57
- const url = req.url ?? "/";
58
- if (url === "/" || url === "/index.html") {
59
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
60
- res.end(html);
61
- }
62
- else if (url === "/preflight-ca.pem" && caCert) {
63
- res.writeHead(200, { "Content-Type": "application/x-pem-file" });
64
- res.end(caCert);
65
- }
66
- else if (url === "/preflight.mobileconfig" && mobileConfig) {
67
- res.writeHead(200, { "Content-Type": "application/x-apple-aspen-config" });
68
- res.end(mobileConfig);
69
- }
70
- else if (url === "/qr.png" && qrPng) {
71
- res.writeHead(200, { "Content-Type": "image/png" });
72
- res.end(qrPng);
73
- }
74
- else {
75
- res.writeHead(404);
76
- res.end("Not found");
77
- }
78
- });
79
- this.certServer.listen(0, "0.0.0.0", () => {
80
- const addr = this.certServer.address();
81
- this.certServerPort = addr && typeof addr !== "string" ? addr.port : 0;
82
- // Re-generate QR with the actual port
83
- const actualUrl = `http://${proxyHost}:${this.certServerPort}/preflight.mobileconfig`;
84
- this.qrPng = this.generateQrPng(actualUrl);
85
- });
86
- }
87
- stopCertServer() {
88
- if (this.certServer) {
89
- this.certServer.close();
90
- this.certServer = null;
91
- this.certServerPort = 0;
92
- this.qrPng = null;
93
- }
94
- }
95
- generateQrPng(url) {
96
- try {
97
- const script = `import qrcode,sys;qrcode.make(sys.argv[1]).save('/dev/stdout')`;
98
- return execSync(`python3 -c "${script}" "${url}"`, { maxBuffer: 100_000, timeout: 5000 });
99
- }
100
- catch {
101
- return null;
102
- }
103
- }
104
- buildCertPage(proxyHost, proxyPort) {
105
- return `<!DOCTYPE html>
106
- <html><head><meta charset="utf-8"><title>Preflight Mock</title>
107
- <style>
108
- body { font-family: -apple-system, sans-serif; text-align: center; padding: 20px; background: #f5f5f7; }
109
- .card { background: white; border-radius: 16px; padding: 24px; max-width: 400px; margin: 0 auto; box-shadow: 0 2px 12px rgba(0,0,0,0.08); }
110
- h1 { font-size: 20px; margin-bottom: 4px; }
111
- .sub { color: #666; font-size: 13px; margin-bottom: 16px; }
112
- .qr { margin: 16px 0; }
113
- .btn { display: inline-block; background: #007aff; color: white; padding: 10px 24px; border-radius: 8px;
114
- text-decoration: none; font-weight: 600; margin: 6px; font-size: 14px; }
115
- .steps { text-align: left; font-size: 12px; color: #888; margin-top: 20px; line-height: 1.8; }
116
- </style></head><body>
117
- <div class="card">
118
- <h1>Preflight Network Mock</h1>
119
- <p class="sub">Proxy ${proxyHost}:${proxyPort}</p>
120
- <div class="qr"><img src="qr.png" width="200" alt="QR Code"></div>
121
- <a class="btn" href="preflight-ca.pem">CA 证书 (PEM)</a>
122
- <a class="btn" href="preflight.mobileconfig">.mobileconfig</a>
123
- <div class="steps">
124
- <b>iOS:</b> 扫描二维码 或下载 .mobileconfig → 安装 →<br>
125
- Settings > General > About > Certificate Trust Settings<br>
126
- → 开启 <b>Preflight Mock CA</b><br>
127
- <b>Android:</b> 下载 PEM → Settings > Security →<br>
128
- Install certificate > CA certificate
129
- </div>
130
- </div>
131
- </body></html>`;
132
- }
133
- isRunning() {
134
- return this.server.getPort() > 0;
135
- }
136
- getStats() {
137
- return this.server.getStats();
138
- }
139
- updateRules(rules) {
140
- this.server.updateRules(rules);
141
- }
142
- getRootCACert() {
143
- return this.server.getRootCACert();
144
- }
145
- generateMobileConfig(proxyHost, proxyPort) {
146
- return this.server.generateMobileConfig(proxyHost, proxyPort);
147
- }
148
- setRecording(enabled) { this.server.setRecording(enabled); }
149
- isRecording() { return this.server.isRecording(); }
150
- getRecordedCount() { return this.server.getRecordedCount(); }
151
- exportRecordedRules() {
152
- const rules = this.server.exportRecordedRules();
153
- this.server.clearRecording();
154
- return rules;
155
- }
156
- }
@@ -1,31 +0,0 @@
1
- import { execSync } from "node:child_process";
2
- export function configureAndroidEmulatorProxy(config) {
3
- const { deviceId, proxyHost, proxyPort } = config;
4
- const proxy = `${proxyHost}:${proxyPort}`;
5
- execSync(`adb -s ${deviceId} shell settings put global http_proxy ${proxy}`, {
6
- stdio: "pipe",
7
- timeout: 10_000,
8
- });
9
- }
10
- export function removeAndroidEmulatorProxy(serial) {
11
- execSync(`adb -s ${serial} shell settings put global http_proxy :0`, {
12
- stdio: "pipe",
13
- timeout: 10_000,
14
- });
15
- }
16
- export function configureDeviceProxy(config) {
17
- if (config.platform === "android") {
18
- configureAndroidEmulatorProxy(config);
19
- }
20
- // iOS simulator proxy deferred to phase 2
21
- }
22
- export function removeDeviceProxy(platform, deviceId) {
23
- if (platform === "android") {
24
- removeAndroidEmulatorProxy(deviceId);
25
- }
26
- // iOS simulator proxy deferred to phase 2
27
- }
28
- /** Android emulator reaches the host at 10.0.2.2; iOS simulator uses loopback. */
29
- export function proxyHostForPlatform(platform) {
30
- return platform === "android" ? "10.0.2.2" : "127.0.0.1";
31
- }
@@ -1,3 +0,0 @@
1
- export { NetworkMockServer } from "./NetworkMockServer.js";
2
- export { NetworkMockService } from "./NetworkMockService.js";
3
- export { configureDeviceProxy, removeDeviceProxy, proxyHostForPlatform } from "./device-proxy.js";
@@ -1 +0,0 @@
1
- export {};