Skip to content

Commit edeaa90

Browse files
committed
README.md udpates
1 parent d19b4b9 commit edeaa90

10 files changed

+602
-0
lines changed

.editorconfig

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
indent_style: 'space',
3+
indent_size: 2,
4+
charset: 'utf-8',
5+
trim_trailing_whitespace: true,
6+
insert_final_newline: true,
7+
tab_width: 2
8+
}

.gitignore

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
node_modules
2+
dist
3+
src/renderer/pages/.umi
4+
src/renderer/pages/.umi-production
5+
release
6+
yarn-error.log
7+
yarn.lock
8+
.history
9+
.vscode
10+
.umirc.local.js
11+
.now

Proxy.js

+234
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
var express = require('express');
2+
var proxy = require('http-proxy-middleware');
3+
const https = require('https')
4+
const zlib = require("zlib")
5+
const cookiejar = require('cookiejar')
6+
const iconv = require('iconv-lite')
7+
const {CookieAccessInfo, CookieJar, Cookie} = cookiejar
8+
9+
function countUtf8Bytes(s) {
10+
var b = 0, i = 0, c
11+
for(;c=s.charCodeAt(i++);b+=c>>11?3:c>>7?2:1);
12+
return b
13+
}
14+
15+
var enableCors = function(req, res) {
16+
if (req.headers['access-control-request-method']) {
17+
res.setHeader('access-control-allow-methods', req.headers['access-control-request-method']);
18+
}
19+
20+
if (req.headers['access-control-request-headers']) {
21+
res.setHeader('access-control-allow-headers', req.headers['access-control-request-headers']);
22+
}
23+
24+
if (req.headers.origin) {
25+
res.setHeader('access-control-allow-origin', req.headers.origin);
26+
res.setHeader('access-control-allow-credentials', 'true');
27+
}
28+
};
29+
30+
// only support https for now.
31+
let router = (req) => { //return target
32+
let {host, httpType} = getHostFromReq(req)
33+
let target = `${httpType}://${host}`
34+
console.log(`router, target:${target}, req.url:${req.url}`)
35+
return target
36+
}
37+
38+
let getHostFromReq = (req) => { //return target
39+
// url: http://127.0.0.1:8011/https/www.youtube.com/xxx/xxx/...
40+
let https_prefix = '/https/'
41+
let http_prefix = '/http/'
42+
let host = ''
43+
let httpType = 'https'
44+
if (req.url.startsWith(https_prefix)) {
45+
host = req.url.slice(https_prefix.length, req.url.length)
46+
if (host.indexOf('/') !== -1) {
47+
host = host.slice(0, host.indexOf('/'))
48+
}
49+
} else if (req.url.startsWith(http_prefix)) {
50+
host = req.url.slice(http_prefix.length, req.url.length)
51+
if (host.indexOf('/') !== -1) {
52+
host = host.slice(0, host.indexOf('/'))
53+
}
54+
httpType = 'http'
55+
} else if (req.headers['referer'] && req.headers['referer'].indexOf('https/') !== -1) {
56+
let start = req.headers['referer'].indexOf('https/') + 6
57+
host = req.headers['referer'].slice(start, req.headers['referer'].length)
58+
let end = host.indexOf('/')
59+
if (end === -1) {
60+
end = host.length
61+
}
62+
host = host.slice(0, end)
63+
console.log(`============= host:${host}, req referer:${req.headers['referer']}`)
64+
} else if (req.headers['referer'] && req.headers['referer'].indexOf('http/') !== -1) {
65+
let start = req.headers['referer'].indexOf('http/') + 5
66+
host = req.headers['referer'].slice(start, req.headers['referer'].length)
67+
let end = host.indexOf('/')
68+
if (end === -1) {
69+
end = host.length
70+
}
71+
host = host.slice(0, end)
72+
httpType = 'http'
73+
console.log(`============= host:${host}, req referer:${req.headers['referer']}`)
74+
}
75+
console.log(`getHostFromReq, req.url:${req.url}, referer:${req.headers['referer']}`)
76+
return {host, httpType}
77+
}
78+
79+
80+
let Proxy = ({cookieDomainRewrite, locationReplaceMap302, regReplaceMap, siteSpecificReplace, pathReplace}) => {
81+
let handleRespond = ({req, res, body, gbFlag}) => {
82+
// console.log("res from proxied server:", body);
83+
/*
84+
var myRe = new RegExp(`https://`, 'g') // support maximum 300 characters for web site name, like: www.google.com
85+
body = body.replace(myRe, `http://127.0.0.1:${port}/https/`)
86+
myRe = new RegExp(`https%3A%2F%2F`, 'g')
87+
body = body.replace(myRe, `https%3A%2F%2Fround-lake.dustinice.workers.dev%3A443%2Fhttps%2F127.0.0.1%3A${port}%2F`)
88+
*/
89+
let myRe
90+
let {host, httpType} = getHostFromReq(req)
91+
let location = res.getHeaders()['location']
92+
if (res.statusCode == '302' || res.statusCode == '301') {
93+
for(key in locationReplaceMap302) {
94+
myRe = new RegExp(key, 'g') // match group
95+
location = location.replace(myRe, locationReplaceMap302[key])
96+
}
97+
res.setHeader('location', location)
98+
}
99+
// console.log(`HandleRespond(), req.url:${req.url}, req.headers:${JSON.stringify(req.headers)}`)
100+
for(key in regReplaceMap) {
101+
myRe = new RegExp(key, 'g') // match group
102+
body = body.replace(myRe, regReplaceMap[key])
103+
}
104+
Object.keys(siteSpecificReplace).forEach( (site) => {
105+
if (req.url.indexOf(site) !== -1 || req.headers['referer'].indexOf(site) !== -1) {
106+
keys = Object.keys(siteSpecificReplace[site])
107+
keys.forEach( key => {
108+
myRe = new RegExp(key, 'g') // match group
109+
body = body.replace(myRe, siteSpecificReplace[site][key])
110+
})
111+
}
112+
})
113+
if (host) {
114+
body = pathReplace({host, httpType, body})
115+
}
116+
117+
if (gbFlag) {
118+
body = iconv.encode(body, 'gbk')
119+
}
120+
body = zlib.gzipSync(body)
121+
res.setHeader('content-encoding', 'gzip');
122+
console.log(`handleRespond: res.headers:${JSON.stringify(res.getHeaders())}`)
123+
res.end(body);
124+
}
125+
let p = proxy({
126+
target: `https://www.google.com`,
127+
router,
128+
/*
129+
pathRewrite: (path, req) => {
130+
let {host, httpType} = getHostFromReq(req)
131+
let newpath = path.replace(`/https/${host}`, '') || '/'
132+
console.log(`newpath:${newpath}`)
133+
return newpath
134+
},
135+
*/
136+
hostRewrite: true,
137+
// autoRewrite: true,
138+
protocolRewrite: true,
139+
// followRedirects: true,
140+
cookieDomainRewrite,
141+
secure: false,
142+
changeOrigin: true,
143+
debug:true,
144+
onError: (err, req, res) => {
145+
console.log(`onerror: ${err}`)
146+
},
147+
selfHandleResponse: true, // so that the onProxyRes takes care of sending the response
148+
onProxyRes: (proxyRes, req, res) => {
149+
let {host, httpType} = getHostFromReq(req)
150+
console.log(`proxyRes.status:${proxyRes.statusCode} proxyRes.headers:${JSON.stringify(proxyRes.headers)}`)
151+
var body = Buffer.from('');
152+
proxyRes.on('data', function(data) {
153+
body = Buffer.concat([body, data]);
154+
})
155+
proxyRes.on('end', function() {
156+
let gbFlag = false
157+
if (proxyRes.headers["content-encoding"] === 'gzip') {
158+
zlib.gunzip(body,function(er,gunzipped){
159+
console.log(`zlib.gunzip...`)
160+
if (proxyRes.headers["content-type"].indexOf('text/') !== -1) {
161+
if (!gunzipped) {
162+
res.status(404).send()
163+
return
164+
}
165+
console.log(`utf-8 text...`)
166+
body = gunzipped.toString('utf-8');
167+
if (body.indexOf('content="text/html; charset=gb2312') !== -1) {
168+
body = iconv.decode(gunzipped, 'gbk')
169+
gbFlag = true
170+
}
171+
handleRespond({req, res, body, gbFlag})
172+
} else {
173+
res.end(body)
174+
}
175+
});
176+
} else if (proxyRes.headers["content-type"] && proxyRes.headers["content-type"].indexOf('text/') !== -1) {
177+
console.log(`utf-8 text...`)
178+
body = body.toString('utf-8');
179+
handleRespond({req, res, body, gbFlag})
180+
} else {
181+
res.end(body)
182+
}
183+
})
184+
const setCookieHeaders = proxyRes.headers['set-cookie'] || []
185+
const modifiedSetCookieHeaders = setCookieHeaders
186+
.map(str => new cookiejar.Cookie(str))
187+
.map(cookie => {
188+
console.log(`cookie:${JSON.stringify(cookie)}`)
189+
if (cookie.path && cookie.path[0] === '/') {
190+
cookie.domain = `127.0.0.1`
191+
cookie.path = `${req.url}`
192+
}
193+
cookie.secure = false
194+
return cookie
195+
})
196+
.map(cookie => cookie.toString())
197+
proxyRes.headers['set-cookie'] = modifiedSetCookieHeaders
198+
Object.keys(proxyRes.headers).forEach(function (key) {
199+
if (key === 'content-encoding' ||
200+
(key === 'content-length' && proxyRes.headers["content-type"] && proxyRes.headers["content-type"].indexOf('text/') !== -1)) {
201+
console.log(`skip header:${key}`)
202+
return
203+
}
204+
// res.append(key, proxyRes.headers[key]);
205+
res.setHeader(key, proxyRes.headers[key]);
206+
});
207+
res.statusCode = proxyRes.statusCode
208+
console.log(`res.status:${res.statusCode} res.url:${res.url}, res.headers:${JSON.stringify(res.getHeaders())}`)
209+
},
210+
onProxyReq: (proxyReq, req, res) => {
211+
let {host, httpType} = getHostFromReq(req)
212+
req.headers['host'] = host
213+
req.headers['referer'] = host
214+
let newpath = req.url.replace(`/${httpType}/${host}`, '') || '/'
215+
console.log(`httpType:${httpType}, host:${host}, req.url:${req.url}, req.headers:${JSON.stringify(req.headers)}`)
216+
Object.keys(req.headers).forEach(function (key) {
217+
proxyReq.setHeader(key, req.headers[key]);
218+
});
219+
proxyReq.setHeader('Accept-Encoding', 'gzip')
220+
proxyReq.setHeader('referer', host)
221+
proxyReq.path = newpath
222+
console.log(`req host:${host}, req.url:${req.url}, proxyReq.path:${proxyReq.path}, proxyReq.url:${proxyReq.url} proxyReq headers:${JSON.stringify(proxyReq.getHeaders())}`)
223+
if(host === '' || !host) {
224+
console.log(`------------------ sending status 404`)
225+
res.status(404).send()
226+
res.end()
227+
}
228+
229+
},
230+
})
231+
return p
232+
}
233+
234+
module.exports = Proxy

README.md

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# siteproxy
2+
pure web page proxy, zero configuration from client side. Reverse proxy to all internet. 一键部署,翻墙利器。
3+
4+
```
5+
+----> google
6+
+----------------+ |
7+
| | |
8+
user browser +-------------->+ siteproxy +-------> wikipedia
9+
| | |
10+
+----------------+ |
11+
+----> chinese forums
12+
```
13+
14+
## features
15+
- enter siteproxy's address, and go surf on internet without censorship.
16+
- no proxy setting from client side is needed. zero configuration from client browser.
17+
- easy deployment to now.sh
18+
19+
## Mechanism
20+
```
21+
1. user browser url: https://siteproxy.now.sh/https/www.google.com
22+
2. siteproxy.now.sh received the url and request www.google.com, and get response from www.google.com
23+
3. siteproxy replace all returned strings in javascript/html:
24+
https://www.google.com => https://siteproxy.now.sh/https/www.google.com
25+
url(/https/github.com/xxx) => url(/https/github.com/https/www.google.com/xxx)
26+
https://xxx => https://siteproxy.now.sh/https/xxx
27+
etc.
28+
4. send back the modified html/javascript to user browser.
29+
```
30+
31+
## supported websites
32+
```
33+
1. www.google.com, and search action
34+
2. zh.wikipedia.org, and search action
35+
3. other websites.
36+
```
37+
38+
## installation/deployment
39+
```
40+
1. register one now.sh account from https://zeit.co/home
41+
2. npm install -g now
42+
3. git clone https://github.com/netptop/siteproxy.git
43+
4. cd siteproxy
44+
5. now
45+
6. find your domain name from now cli, then replace serverName in 'index.js', like:
46+
serverName: 'siteproxy.now.sh' ====> 'your-domain-name.now.sh'
47+
7. now --prod
48+
8. done
49+
```
50+
51+
## issues
52+
- 部分网站加载有问题;
53+
- 暂时无法看视频网站;
54+
- twitter访问有问题;
55+
- recaptcha验证码有问题;

bg-gr-v.png

150 Bytes
Loading

index.html

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<meta charset="utf-8"/>
2+
<link rel="stylesheet" href="/style.css"/>
3+
<header class="header-banner">
4+
<kiv class="container-width">
5+
<div class="logo-container">
6+
<div class="logo">
7+
siteproxy
8+
</div>
9+
</div>
10+
<br />
11+
<div class="lead-title"> 从这里开始,不再被训戒. 建议您从浏览器打开网页,避免被微信窃听!
12+
</div>
13+
<form class="lead-title" action=>
14+
<input class="lead-title" type="button" onclick="window.location.href='/https/www.google.com'" value="Google"/>
15+
<input class="lead-title" type="button" onclick="window.location.href='/https/zh.wikipedia.org'" value="维基百科"/>
16+
<input class="lead-title" type="button" onclick="window.location.href='/https/www.wenxuecity.com'" value="文学城"/>
17+
<input class="lead-title" type="button" onclick="window.location.href='/https/www.bbc.com/zhongwen/simp'" value="BBC新闻"/>
18+
<input class="lead-title" type="button" onclick="window.location.href='/https/cn.nytimes.com'" value="纽约时报"/>
19+
</form>
20+
21+
</kiv>
22+
<div class="container-width">
23+
<div class="logo-container">
24+
</div>
25+
<div class="c9130">
26+
<br/>
27+
<br/>
28+
<div class="clearfix">
29+
</div>
30+
<br/>
31+
<br/>
32+
</div>
33+
</div>
34+
</header>

0 commit comments

Comments
 (0)