Skip to content

Commit

Permalink
support self-signed cert #22
Browse files Browse the repository at this point in the history
  • Loading branch information
nondanee committed Mar 29, 2019
1 parent 227998e commit fa48f90
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 61 deletions.
20 changes: 14 additions & 6 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ const config = require('./cli.js')
.option(['-h', '--help'], {action: 'help'})
.parse(process.argv)

if(config.port && (isNaN(config.port) || config.port < 1 || config.port > 65535)){
config.port = (config.port || '8080').split(':').map(string => parseInt(string))
const invalid = value => (isNaN(value) || value < 1 || value > 65535)
if(config.port.some(invalid)){
console.log('Port must be a number higher than 0 and lower than 65535.')
process.exit(1)
}
Expand All @@ -26,14 +28,14 @@ if(config.forceHost && !/\d+\.\d+\.\d+\.\d+/.test(config.forceHost)){
process.exit(1)
}
if(config.matchOrder){
const provider = ['qq', 'xiami', 'baidu', 'kugou', 'kuwo', 'migu', 'joox']
const provider = ['netease', 'qq', 'xiami', 'baidu', 'kugou', 'kuwo', 'migu', 'joox']
const candidate = config.matchOrder
if(candidate.some((key, index) => index != candidate.indexOf(key))){
console.log('Please check the duplication in match order.')
process.exit(1)
}
else if(candidate.some(key => !provider.includes(key))){
console.log('Please check the validation of match order.')
console.log('Please check the availability of match sources.')
process.exit(1)
}
global.source = candidate
Expand All @@ -46,8 +48,8 @@ if(config.token && !/\S+:\S+/.test(config.token)){
const parse = require('url').parse
const hook = require('./hook')
const server = require('./server')
const port = config.port || 8080

global.port = config.port
global.proxy = config.proxyUrl ? parse(config.proxyUrl) : null
global.hosts = {}, hook.target.host.forEach(host => global.hosts[host] = config.forceHost)
config.strict ? server.whitelist = ['music.163.com', 'music.126.net', 'vod.126.net'] : server.blanklist = []
Expand All @@ -62,7 +64,13 @@ Promise.all([httpdns(hook.target.host[0])].concat(hook.target.host.map(host => d
result.forEach(set => extra = extra.concat(set))
extra = Array.from(new Set(extra))
hook.target.host = hook.target.host.concat(extra)
server.listen(port)
console.log(`Server running @ http://0.0.0.0:${port}`)
if(port[0]){
server.http.listen(port[0])
console.log(`HTTP Server running @ http://0.0.0.0:${port[0]}`)
}
if(port[1]){
server.https.listen(port[1])
console.log(`HTTPS Server running @ http://0.0.0.0:${port[1]}`)
}
})
.catch(error => console.log(error))
20 changes: 20 additions & 0 deletions ca.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDOzCCAiOgAwIBAgIJAPHnSZ8Dn3N/MA0GCSqGSIb3DQEBCwUAMDQxCzAJBgNV
BAYTAkNOMSUwIwYDVQQKDBxVbmJsb2NrTmV0ZWFzZU11c2ljIFByb3h5IENBMB4X
DTE5MDMyODE4MDIwNloXDTI0MDMyNjE4MDIwNlowNDELMAkGA1UEBhMCQ04xJTAj
BgNVBAoMHFVuYmxvY2tOZXRlYXNlTXVzaWMgUHJveHkgQ0EwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQD23K6Ti2TfLJToCmpCAVgEXb8+qTMfrifCpnKl
J+hrL+4KI1j4vSqTOOatqmxGSXZdF/j2kJuI40YThaokcgYxGFcPcEftSCYGWy8o
20u2hzTkkW3KW9wlsDRIXICFXVIsHeSDwz+aVSudkyJHjfaSaLNb5pPovE7MRj8t
Dbp55scaSqhEcOe3m1ZlwlCeeXvD7RLKr3xhBKbGEqlJAjFqRNGzuqylqyJVBLSc
NHC7Lcf4n6pKr1yPGOeLePOUrIwtj0ynHUcBfeMuCVCsIKL8vy/oNwlDrZaAMfu5
QQslzEf87KY1QgtI6Ppii+tzbmVx1ZxnlaCKqiuwlgBoi/5rAgMBAAGjUDBOMB0G
A1UdDgQWBBRDhbGjnXEUouE9wNFS2k9PtgYYjDAfBgNVHSMEGDAWgBRDhbGjnXEU
ouE9wNFS2k9PtgYYjDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB0
oJhGJyQRQzqNF91CEauQSmru5FPPi0jNFzY1oEzb+KFx2xGEctB81bBl0z0/x6v8
gZEaAeF8eHnukex1QCb5JD0fIXeNvsgLSt/4NDPTdQ9MUAazAAWPqnB7PL3oKN7h
hxaldhzYf9n0yQs+ICHvToNWg2fAQ9F5KkDABgNk4GUYYLdno+WiAQV+owa+A8SP
d46DvyqQzLUJQgAqDxasSNeTbs5M/pTPvH/BiR01nLCvdw0DtPoDi0hyZ0qWWtLl
ZGs8Zxh0GQgzKul0iQP69jXUlQLVZxCpIZmj0hVsf/7+lMYULULJdpCBZ6Ft2zG3
wH78wAwAjMLZ4fUv1sjk
-----END CERTIFICATE-----
14 changes: 7 additions & 7 deletions hook.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ const request = require('./request')
const match = require('./provider/match')

const hook = {
http: {
request: {
before: () => {},
after: () => {},
},
https: {
connect: {
before: () => {}
},
target: {
Expand Down Expand Up @@ -50,9 +50,9 @@ hook.target.path = [
'/api/playlist/v4/detail'
]

hook.http.before = ctx => {
hook.request.before = ctx => {
const req = ctx.req
req.url = (req.url.startsWith('http://') ? '' : 'http://music.163.com') + req.url
req.url = (req.url.startsWith('http://') ? '' : (req.socket.encrypted ? 'https:' : 'http:') + '//music.163.com') + req.url
const url = parse(req.url)
const netease = {}
if((hook.target.host.includes(url.hostname)) && req.method == 'POST' && (url.path == '/api/linux/forward' || url.path.startsWith('/eapi/'))){
Expand Down Expand Up @@ -103,7 +103,7 @@ hook.http.before = ctx => {
}
}

hook.http.after = ctx => {
hook.request.after = ctx => {
const netease = ctx.netease
const package = ctx.package
const proxyRes = ctx.proxyRes
Expand Down Expand Up @@ -163,10 +163,10 @@ hook.http.after = ctx => {
}
}

hook.https.before = ctx => {
hook.connect.before = ctx => {
let url = parse('https://' + ctx.req.url)
if(hook.target.host.includes(url.hostname)){
ctx.decision = 'blank'
global.port[1] ? ctx.req.url = `localhost:${global.port[1]}` : ctx.decision = 'blank'
}
}

Expand Down
2 changes: 1 addition & 1 deletion provider/joox.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const track = id => {
return request('GET', url, headers)
.then(response => response.jsonp())
.then(jsonBody => {
let songUrl = jsonBody.r320Url || jsonBody.r192Url || jsonBody.mp3Url || jsonBody.m4aUrl
let songUrl = (jsonBody.r320Url || jsonBody.r192Url || jsonBody.mp3Url || jsonBody.m4aUrl).replace(/M\d00([\w]+).mp3/, 'M800$1.mp3')
if(songUrl)
return songUrl
else
Expand Down
21 changes: 21 additions & 0 deletions server.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDXzCCAkegAwIBAgIJAMHcLaEO36PDMA0GCSqGSIb3DQEBCwUAMDQxCzAJBgNV
BAYTAkNOMSUwIwYDVQQKDBxVbmJsb2NrTmV0ZWFzZU11c2ljIFByb3h5IENBMB4X
DTE5MDMyODE4MzUxMloXDTIwMDMyNzE4MzUxMlowezELMAkGA1UEBhMCQ04xETAP
BgNVBAcMCEhhbmd6aG91MSwwKgYDVQQKDCNOZXRFYXNlIChIYW5nemhvdSkgTmV0
d29yayBDby4sIEx0ZDERMA8GA1UECwwISVQgRGVwdC4xGDAWBgNVBAMMDyoubXVz
aWMuMTYzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALobECyp
wEoe8VqM/FJvBRR3p2T+ZWdiMSPrwfiRJr5p7OMtWBlLveCBV85+R3feidYbQTXl
vVTdToY+GN6mFE1x6zG2dvLDs4UuRnipmvGcFYhIRTX8J4AJiN8VMtW0TNXscRMu
dpz/FAVtsRrggRaThYg4f/rIoAPMqKMsS4JoYhxs9ED6E6/tpj3XmSg1ekaXhgac
YSYHeyxizZwoOFVCLH3TG5sFsD6CYNnukYol8bR+VRpvHftIYss5Yz+DyyhYEAMJ
m1CfQo+xoGR3D0ozbT3hUnzmfEoOhmSp3sALrFVE4iJSuajoh2/3xhmcyi3xZdWy
q4F8hpb+URyaoW0CAwEAAaMtMCswKQYDVR0RBCIwIIINbXVzaWMuMTYzLmNvbYIP
Ki5tdXNpYy4xNjMuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQB/RIWAXnOiru5dW8Wp
9anLOMPAl8jO6H+S3NDsqMAOkTbuyKFa04QziTZvIHB2nId96WxsfGilbVX+AHxt
7EY9jV54pEkusBdxz2UuE30aTvTUwZuBep/tGMS7tVAgfcbOS9BYhHsYo4hcH5bJ
lbYAKEj/ZO3IjkE/6CxNDebrhVEqmH+0GAZKI6vN4s06m+ksiwqwXcpR0+dZgC7+
LZULhgslYDUIG8yDbR8xd0BPxbe3Oej0zzpNecow2R+euDEVNuokM9aGLU7bYiZx
t50aPX3C1NVwzsoRNp5VXxUbz6WAozFB01nSR2L/emcF5z7NeHgFuvZhhRORQMMN
i9Aj
-----END CERTIFICATE-----
104 changes: 57 additions & 47 deletions server.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,51 @@
const http = require('http')
const fs = require('fs')
const net = require('net')
const parse = require('url').parse

const hook = require('./hook')
const request = require('./request')

const server = http.createServer()
.on('request', (req, res) => {
if(req.url == '/proxy.pac'){
let url = parse('http://' + req.headers.host)
res.writeHead(200, {'Content-Type': 'application/x-ns-proxy-autoconfig'})
res.end(`
function FindProxyForURL(url, host) {
if (${hook.target.host.map(host => (`host == '${host}'`)).join(' || ')}) {
return 'PROXY ${url.hostname}:${url.port || 80}'
}
return 'DIRECT'
}
`)
}
else{
const ctx = {res, req}
Promise.resolve()
.then(() => proxy.authenticate(ctx))
.then(() => hook.http.before(ctx))
.then(() => proxy.filter(ctx))
.then(() => proxy.log(ctx))
.then(() => proxy.mitm.send(ctx))
.then(() => hook.http.after(ctx))
.then(() => proxy.mitm.receive(ctx))
.catch(() => proxy.mitm.close(ctx))
}
})
.on('connect', (req, socket, head) => {
const ctx = {req, socket, head}
Promise.resolve()
.then(() => proxy.authenticate(ctx))
.then(() => hook.https.before(ctx))
.then(() => proxy.filter(ctx))
.then(() => proxy.log(ctx))
.then(() => proxy.tunnel.connect(ctx))
.then(() => proxy.tunnel.handshake(ctx))
.then(() => proxy.tunnel.pipe(ctx))
.catch(() => proxy.tunnel.close(ctx))
})

server.whitelist = ['.*']
server.blacklist = ['.*']
server.authentication = null

const proxy = {
core: {
mitm: (req, res) => {
if(req.url == '/proxy.pac'){
let url = parse('http://' + req.headers.host)
res.writeHead(200, {'Content-Type': 'application/x-ns-proxy-autoconfig'})
res.end(`
function FindProxyForURL(url, host) {
if (${hook.target.host.map(host => (`host == '${host}'`)).join(' || ')}) {
return 'PROXY ${url.hostname}:${url.port || 80}'
}
return 'DIRECT'
}
`)
}
else{
const ctx = {res, req}
Promise.resolve()
.then(() => proxy.authenticate(ctx))
.then(() => hook.request.before(ctx))
.then(() => proxy.filter(ctx))
.then(() => proxy.log(ctx))
.then(() => proxy.mitm.request(ctx))
.then(() => hook.request.after(ctx))
.then(() => proxy.mitm.response(ctx))
.catch(() => proxy.mitm.close(ctx))
}
},
tunnel: (req, socket, head) => {
const ctx = {req, socket, head}
Promise.resolve()
.then(() => proxy.authenticate(ctx))
.then(() => hook.connect.before(ctx))
.then(() => proxy.filter(ctx))
.then(() => proxy.log(ctx))
.then(() => proxy.tunnel.connect(ctx))
.then(() => proxy.tunnel.handshake(ctx))
.then(() => proxy.tunnel.pipe(ctx))
.catch(() => proxy.tunnel.close(ctx))
}
},
log: ctx => {
const mark = {close: '|', blank: '-', proxy: '>'}[ctx.decision] || '>'
if(ctx.socket)
Expand Down Expand Up @@ -88,7 +84,7 @@ const proxy = {
}
},
mitm: {
send: ctx => new Promise((resolve, reject) => {
request: ctx => new Promise((resolve, reject) => {
if(ctx.decision === 'close') return reject(ctx.error = ctx.decision)
const req = ctx.req
const url = parse(req.url)
Expand All @@ -102,7 +98,7 @@ const proxy = {
})
req.readable ? req.pipe(ctx.proxyReq) : ctx.proxyReq.end(req.body)
}),
receive: ctx => {
response: ctx => {
const res = ctx.res
const proxyRes = ctx.proxyRes
res.writeHead(proxyRes.statusCode, proxyRes.headers)
Expand Down Expand Up @@ -163,4 +159,18 @@ const proxy = {
}
}

const options = {
key: fs.readFileSync('./server.key'),
cert: fs.readFileSync('./server.crt')
}

const server = {
http: require('http').createServer().on('request', proxy.core.mitm).on('connect', proxy.core.tunnel),
https: require('https').createServer(options).on('request', proxy.core.mitm).on('connect', proxy.core.tunnel)
}

server.whitelist = ['.*']
server.blacklist = ['.*']
server.authentication = null

module.exports = server
27 changes: 27 additions & 0 deletions server.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAuhsQLKnASh7xWoz8Um8FFHenZP5lZ2IxI+vB+JEmvmns4y1Y
GUu94IFXzn5Hd96J1htBNeW9VN1Ohj4Y3qYUTXHrMbZ28sOzhS5GeKma8ZwViEhF
NfwngAmI3xUy1bRM1exxEy52nP8UBW2xGuCBFpOFiDh/+sigA8yooyxLgmhiHGz0
QPoTr+2mPdeZKDV6RpeGBpxhJgd7LGLNnCg4VUIsfdMbmwWwPoJg2e6RiiXxtH5V
Gm8d+0hiyzljP4PLKFgQAwmbUJ9Cj7GgZHcPSjNtPeFSfOZ8Sg6GZKnewAusVUTi
IlK5qOiHb/fGGZzKLfFl1bKrgXyGlv5RHJqhbQIDAQABAoIBAEmAvtalBMlBh1mY
LV/xcTQwPfDpeOtoILhrOOUPjxnNhD4FfrIe9BNjgmaQAXIadp4VjZ/X6PtHnOfw
RqpJNeOQhq/PvRMMsC59pF+rvQKH/wkgYhV8Ta2IFoLlQHqfB2nGRLKquzYumJ28
QSK4YMOl6CtxBTrrWiemAUTRDdGm8tARiipJH1SEJrS6d/NoRoJx2vixFgD2eS6X
bjnhGjIzvX/w5FWjctqj+SFITP1UI62b6DyWsPOkoosKNteK+Ulz+K6ZFvOx7day
XgUoTcVpwCVr2dVGhJtOrbKPcl1jYCYHJAHwzUZND4x4yftm1mnnsi3bthYqbtHQ
vxLE9YECgYEA9hiZxwiVvLjSe1xT/D75HbB8S1XSnwzpMmqgzStguxCQ0Qg5yiLI
UKRDY8UZvEDV4i2bQGy7mk8lFvX1q2z7Q30+dtT9r2N9a6ujMk5RMfo2BZg/poI6
yDWe2tKUg9cTwfgni4TutLOYkpz3VDPIQHs3k2mpNh7f+8X4RIybDqkCgYEAwZhp
uWMV38Bb0WytswHXL1dRuwBskKqALUBY61dtXkyBuocj8AuRRxfxfZpgJRrHFxDX
O9bQ2nxpVlwKsR6DJDUdxU3+kvwyPfseU5XUBey8WdkuAKD7cKZOHMhFVWccks0U
YJzykNrxB+rGTiwVKa0MOhipuJ7boerwwaN2SyUCgYBP9Ow5o4tq9q3EUNoksZ0k
zUuE+oxlCr/VlplKL9bM0HQMxlxoVWa59LTEfKyA4pvbUbAIfYtydlZ5oE5CdTUp
105tM4R88Jk2W1y5ooJ093OH29CKW/OXSvyi4hpIv592vRa0GOupoFRpBkDBhdWB
RcdnyMOmht+FIOwp8XkLiQKBgAUK3j4Y6ZnxXbLfvMp70soF4TgYs7s05a/IDEjc
9xlMrthX6sS22GrcocqeucBdqS/dnW2Ok9QNB4VbUl/4pnvL8mGQPYBAl2Jr5wdQ
ULxyxRkmAf+8MbBmdIRlZwDpdaIRO2Wk0OCbA0osgEvK9CYovrfIqqsHYDsgbnLs
ugkNAoGBAJok06BN05caPXXLQ2pMwI/7mjcZFjcOMxSloYi7LFkxlyvoTqReAeSa
yOb6W/7obS1X8ms/EAkqiyzJuPtNZJCW/nvV0iCoZ/NxLuyHnFaO344GBAweol+S
Jx0MY8KuDCyeGErc2xdz/yr3ld2PSTq71dhBluGyba2YX+peJ2Yv
-----END RSA PRIVATE KEY-----

0 comments on commit fa48f90

Please sign in to comment.