-
Notifications
You must be signed in to change notification settings - Fork 303
/
cors-proxy.js
95 lines (87 loc) · 3.3 KB
/
cors-proxy.js
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
/* eslint-disable node/no-deprecated-api */
module.exports = addCorsProxyHandler
const { createProxyMiddleware } = require('http-proxy-middleware')
const cors = require('cors')
const debug = require('../debug')
const url = require('url')
const dns = require('dns')
const isIp = require('is-ip')
const ipRange = require('ip-range-check')
const validUrl = require('valid-url')
const CORS_SETTINGS = {
methods: 'GET',
exposedHeaders: 'Authorization, User, Location, Link, Vary, Last-Modified, Content-Length, Content-Location, MS-Author-Via, X-Powered-By',
maxAge: 1728000,
origin: true
}
const PROXY_SETTINGS = {
target: 'dynamic',
logLevel: 'silent',
changeOrigin: true,
followRedirects: true,
proxyTimeout: 10000,
router: req => req.destination.target,
pathRewrite: (path, req) => req.destination.path
}
// https://en.wikipedia.org/wiki/Reserved_IP_addresses
const RESERVED_IP_RANGES = [
'127.0.0.0/8', // loopback
'::1/128', // loopback
'0.0.0.0/8', // current network (only valid as source address)
'169.254.0.0/16', // link-local
'10.0.0.0/8', // private network
'100.64.0.0/10', // Shared Address Space
'172.16.0.0/12', // private network
'192.0.0.0/24', // IETF Protocol Assignments
'192.0.2.0/24', // TEST-NET-1, documentation and examples
'192.88.99.0/24', // IPv6 to IPv4 relay (includes 2002::/16)
'192.168.0.0/16', // private network
'198.18.0.0/15', // network benchmark tests
'198.51.100.0/24', // TEST-NET-2, documentation and examples
'203.0.113.0/24', // TEST-NET-3, documentation and examples
'224.0.0.0/4', // IP multicast (former Class D network)
'240.0.0.0/4', // reserved (former Class E network)
'255.255.255.255', // broadcast
'64:ff9b::/96', // IPv4/IPv6 translation (RFC 6052)
'100::/64', // discard prefix (RFC 6666)
'2001::/32', // Teredo tunneling
'2001:10::/28', // deprecated (previously ORCHID
'2001:20::/28', // ORCHIDv2
'2001:db8::/32', // documentation and example source code
'2002::/16', // 6to4
'fc00::/7', // unique local address
'fe80::/10', // link-local address
'ff00::/8' // multicast
]
// Adds a CORS proxy handler to the application on the given path
function addCorsProxyHandler (app, path) {
const corsHandler = cors(CORS_SETTINGS)
const proxyHandler = createProxyMiddleware(PROXY_SETTINGS)
debug.settings(`CORS proxy listening at ${path}?uri={uri}`)
app.get(path, extractProxyConfig, corsHandler, proxyHandler)
}
// Extracts proxy configuration parameters from the request
function extractProxyConfig (req, res, next) {
// Retrieve and validate the destination URL
const uri = req.query.uri
debug.settings(`Proxy request for ${uri}`)
if (!validUrl.isUri(uri)) {
return res.status(400).send(`Invalid URL passed: ${uri || '(none)'}`)
}
// Parse the URL and retrieve its host's IP address
const { protocol, host, hostname, path } = url.parse(uri)
if (isIp(hostname)) {
addProxyConfig(null, hostname)
} else {
dns.lookup(hostname, addProxyConfig)
}
// Verifies and adds the proxy configuration to the request
function addProxyConfig (error, hostAddress) {
// Ensure the host is not a local IP
if (error || RESERVED_IP_RANGES.some(r => ipRange(hostAddress, r))) {
return res.status(400).send(`Cannot proxy ${uri}`)
}
req.destination = { path, target: `${protocol}//${host}` }
next()
}
}