@aikidosec/safe-chain 1.1.6 → 1.1.7
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/package.json
CHANGED
package/src/main.js
CHANGED
|
@@ -11,6 +11,21 @@ export async function main(args) {
|
|
|
11
11
|
const proxy = createSafeChainProxy();
|
|
12
12
|
await proxy.startServer();
|
|
13
13
|
|
|
14
|
+
// Global error handlers to log unhandled errors
|
|
15
|
+
process.on("uncaughtException", (error) => {
|
|
16
|
+
ui.writeError(`Safe-chain: Uncaught exception: ${error.message}`);
|
|
17
|
+
ui.writeVerbose(`Stack trace: ${error.stack}`);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
process.on("unhandledRejection", (reason) => {
|
|
22
|
+
ui.writeError(`Safe-chain: Unhandled promise rejection: ${reason}`);
|
|
23
|
+
if (reason instanceof Error) {
|
|
24
|
+
ui.writeVerbose(`Stack trace: ${reason.stack}`);
|
|
25
|
+
}
|
|
26
|
+
process.exit(1);
|
|
27
|
+
});
|
|
28
|
+
|
|
14
29
|
try {
|
|
15
30
|
// This parses all the --safe-chain arguments and removes them from the args array
|
|
16
31
|
args = initializeCliArguments(args);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import https from "https";
|
|
2
2
|
import { generateCertForHost } from "./certUtils.js";
|
|
3
3
|
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
4
|
+
import { ui } from "../environment/userInteraction.js";
|
|
4
5
|
|
|
5
6
|
export function mitmConnect(req, clientSocket, isAllowed) {
|
|
6
7
|
const { hostname } = new URL(`http://${req.url}`);
|
|
@@ -13,6 +14,15 @@ export function mitmConnect(req, clientSocket, isAllowed) {
|
|
|
13
14
|
|
|
14
15
|
const server = createHttpsServer(hostname, isAllowed);
|
|
15
16
|
|
|
17
|
+
server.on("error", (err) => {
|
|
18
|
+
ui.writeError(`Safe-chain: HTTPS server error: ${err.message}`);
|
|
19
|
+
if (!clientSocket.headersSent) {
|
|
20
|
+
clientSocket.end("HTTP/1.1 502 Bad Gateway\r\n\r\n");
|
|
21
|
+
} else if (clientSocket.writable) {
|
|
22
|
+
clientSocket.end();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
16
26
|
// Establish the connection
|
|
17
27
|
clientSocket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
|
|
18
28
|
|
|
@@ -37,13 +47,15 @@ function createHttpsServer(hostname, isAllowed) {
|
|
|
37
47
|
forwardRequest(req, hostname, res);
|
|
38
48
|
}
|
|
39
49
|
|
|
40
|
-
|
|
50
|
+
const server = https.createServer(
|
|
41
51
|
{
|
|
42
52
|
key: cert.privateKey,
|
|
43
53
|
cert: cert.certificate,
|
|
44
54
|
},
|
|
45
55
|
handleRequest
|
|
46
56
|
);
|
|
57
|
+
|
|
58
|
+
return server;
|
|
47
59
|
}
|
|
48
60
|
|
|
49
61
|
function getRequestPathAndQuery(url) {
|
|
@@ -62,6 +74,11 @@ function forwardRequest(req, hostname, res) {
|
|
|
62
74
|
res.end("Bad Gateway");
|
|
63
75
|
});
|
|
64
76
|
|
|
77
|
+
req.on("error", (err) => {
|
|
78
|
+
ui.writeError(`Safe-chain: Error reading client request: ${err.message}`);
|
|
79
|
+
proxyReq.destroy();
|
|
80
|
+
});
|
|
81
|
+
|
|
65
82
|
req.on("data", (chunk) => {
|
|
66
83
|
proxyReq.write(chunk);
|
|
67
84
|
});
|
|
@@ -88,6 +105,16 @@ function createProxyRequest(hostname, req, res) {
|
|
|
88
105
|
}
|
|
89
106
|
|
|
90
107
|
const proxyReq = https.request(options, (proxyRes) => {
|
|
108
|
+
proxyRes.on("error", (err) => {
|
|
109
|
+
ui.writeError(
|
|
110
|
+
`Safe-chain: Error reading upstream response: ${err.message}`
|
|
111
|
+
);
|
|
112
|
+
if (!res.headersSent) {
|
|
113
|
+
res.writeHead(502);
|
|
114
|
+
res.end("Bad Gateway");
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
91
118
|
res.writeHead(proxyRes.statusCode, proxyRes.headers);
|
|
92
119
|
proxyRes.pipe(res);
|
|
93
120
|
});
|
|
@@ -43,8 +43,13 @@ export function handleHttpProxyRequest(req, res) {
|
|
|
43
43
|
}
|
|
44
44
|
)
|
|
45
45
|
.on("error", (err) => {
|
|
46
|
-
res.
|
|
47
|
-
|
|
46
|
+
if (!res.headersSent) {
|
|
47
|
+
res.writeHead(502);
|
|
48
|
+
res.end(`Bad Gateway: ${err.message}`);
|
|
49
|
+
} else {
|
|
50
|
+
// Headers already sent, just destroy the response
|
|
51
|
+
res.destroy();
|
|
52
|
+
}
|
|
48
53
|
});
|
|
49
54
|
|
|
50
55
|
req.on("error", () => {
|
|
@@ -24,12 +24,6 @@ export function tunnelRequest(req, clientSocket, head) {
|
|
|
24
24
|
function tunnelRequestToDestination(req, clientSocket, head) {
|
|
25
25
|
const { port, hostname } = new URL(`http://${req.url}`);
|
|
26
26
|
|
|
27
|
-
clientSocket.on("error", () => {
|
|
28
|
-
// NO-OP
|
|
29
|
-
// This can happen if the client TCP socket sends RST instead of FIN.
|
|
30
|
-
// Not subscribing to 'close' event will cause node to throw and crash.
|
|
31
|
-
});
|
|
32
|
-
|
|
33
27
|
const serverSocket = net.connect(port || 443, hostname, () => {
|
|
34
28
|
clientSocket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
|
|
35
29
|
serverSocket.write(head);
|
|
@@ -37,6 +31,14 @@ function tunnelRequestToDestination(req, clientSocket, head) {
|
|
|
37
31
|
clientSocket.pipe(serverSocket);
|
|
38
32
|
});
|
|
39
33
|
|
|
34
|
+
clientSocket.on("error", () => {
|
|
35
|
+
// This can happen if the client TCP socket sends RST instead of FIN.
|
|
36
|
+
// Not subscribing to 'error' event will cause node to throw and crash.
|
|
37
|
+
if (serverSocket.writable) {
|
|
38
|
+
serverSocket.end();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
40
42
|
serverSocket.on("error", (err) => {
|
|
41
43
|
ui.writeError(
|
|
42
44
|
`Safe-chain: error connecting to ${hostname}:${port} - ${err.message}`
|
|
@@ -103,6 +105,13 @@ function tunnelRequestViaProxy(req, clientSocket, head, proxyUrl) {
|
|
|
103
105
|
if (clientSocket.writable) {
|
|
104
106
|
clientSocket.end("HTTP/1.1 502 Bad Gateway\r\n\r\n");
|
|
105
107
|
}
|
|
108
|
+
} else {
|
|
109
|
+
ui.writeError(
|
|
110
|
+
`Safe-chain: proxy socket error after connection - ${err.message}`
|
|
111
|
+
);
|
|
112
|
+
if (clientSocket.writable) {
|
|
113
|
+
clientSocket.end();
|
|
114
|
+
}
|
|
106
115
|
}
|
|
107
116
|
});
|
|
108
117
|
|