-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathserver.js
More file actions
135 lines (121 loc) · 3.86 KB
/
server.js
File metadata and controls
135 lines (121 loc) · 3.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
const proxy = require('http-proxy');
const https = require('https');
const http = require('http');
const { URL } = require('url');
if (!process.env.ACCESS_KEY || !process.env.ALLOWED_HOSTS) {
throw new Error('Configuration error! Make sure ACCESS_KEY and ALLOWED_HOSTS are both defined in your process environment.');
}
const getHosts = (hosts) => {
let parsed = [];
hosts = hosts.split(',');
for (let i = 0; i < hosts.length; i++) {
const iHost = hosts[i];
const split = iHost.split(':');
if (split.length !== 2) {
throw new Error(`Configuration error! Invalid protocol:host pair on item ${iHost}`);
}
const proto = split[0];
if (proto !== 'http' && proto !== 'https') {
throw new Error(`Configuration error! Invalid protocol ${proto}. Only these protocols are allowed: http, https`);
}
const host = split[1];
try {
(() => new URL(`${proto}://${host}`))();
} catch (e) {
throw new Error(`Configuration error! Invalid host domain on item ${iHost}`);
}
parsed.push({
proto: proto,
host: host
});
}
return parsed;
};
const PORT = process.env.PORT || 80;
const ACCESS_KEY = process.env.ACCESS_KEY;
const ALLOWED_HOSTS = getHosts(process.env.ALLOWED_HOSTS);
const server = http.createServer();
const httpsProxy = proxy.createProxyServer({
agent: new https.Agent({
checkServerIdentity: (host, cert) => {
return undefined;
}
}),
changeOrigin: true
});
const httpProxy = proxy.createProxyServer({
changeOrigin: true
});
const onProxyError = (err, req, res) => {
console.error(err);
res.writeHead(500, {'Content-Type': 'text/plain'});
res.end('Proxying failed.');
};
const onProxyReq = (proxyReq, req, res, options) => {
proxyReq.setHeader('User-Agent', 'Mozilla');
proxyReq.removeHeader('roblox-id');
proxyReq.removeHeader('proxy-access-key');
proxyReq.removeHeader('proxy-target');
};
httpsProxy.on('error', onProxyError);
httpsProxy.on('proxyReq', onProxyReq);
httpProxy.on('error', onProxyError);
httpProxy.on('proxyReq', onProxyReq);
const doProxy = (target, proto, req, res) => {
var options = {
target: proto + '://' + target.host
};
if (proto === 'https') {
httpsProxy.web(req, res, options);
} else if (proto === 'http') {
httpProxy.web(req, res, options);
} else {
throw new Error(`Do proxy error: Invalid protocol ${proto}`);
}
};
server.on('request', (req, res) => {
if (req.headers['proxy-access-key'] && req.headers['proxy-target']) {
req.on('error', (err) => {
console.error(`Request error: ${err}`);
});
if (req.headers['proxy-access-key'] === ACCESS_KEY) {
const requestedTarget = req.headers['proxy-target'];
if (requestedTarget) {
let parsedTarget;
try {
parsedTarget = new URL(`https://${requestedTarget}`);
} catch (e) {
res.writeHead(400, {'Content-Type': 'text/plain'});
res.end('Invalid target');
return;
}
const requestedHost = parsedTarget.host;
for (let i = 0; i < ALLOWED_HOSTS.length; i++) {
const iHost = ALLOWED_HOSTS[i];
if (requestedHost === iHost.host) {
doProxy(parsedTarget, iHost.proto, req, res);
return;
}
}
res.writeHead(400, {'Content-Type': 'text/plain'});
res.end('Host not whitelisted');
} else {
res.writeHead(400, {'Content-Type': 'text/plain'});
res.end('Target is required');
}
} else {
res.writeHead(403, {'Content-Type': 'text/plain'});
res.end('Invalid access key');
}
} else {
res.writeHead(400, {'Content-Type': 'text/plain'});
res.end('proxy-access-key and proxy-target headers are both required');
}
});
server.listen(PORT, (err) => {
if (err) {
console.error(`Server listening error: ${err}`);
return;
}
console.log(`Server started on port ${PORT}`);
});