Skip to content

Commit 23cbf6a

Browse files
committed
Limit usefulness to just isomorphic-git requests
1 parent 382c26b commit 23cbf6a

File tree

5 files changed

+409
-483
lines changed

5 files changed

+409
-483
lines changed

README.md

Lines changed: 4 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,11 @@
1-
# cors-buster
2-
When you need a file, but the headers ain't good, who you gonna call? CORS Buster!
1+
# git-cors-proxy
32

43
## What is this?
54

6-
This is the software running on https://cors-buster-tbgktfqyku.now.sh, a free
7-
service for AJAX users struggling to work around the fact that many websites
8-
do not implement CORS headers, even for static content.
5+
This is the software running on https://git-cors-proxy.now.sh, a free
6+
service for users of isomorphic-git so you can clone and push repos in the browser.
97

10-
## What it does
11-
12-
Say you tried to do this AJAX call and got this lovely error:
13-
14-
```
15-
window.fetch('http://nodejs.org/dist/v6.10.2/node-v6.10.2-linux-x64.tar.gz')
16-
17-
Fetch API cannot load http://nodejs.org/dist/v6.10.2/node-v6.10.2-linux-x64.tar.gz. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://example.org' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
18-
Uncaught (in promise) TypeError: Failed to fetch
19-
```
20-
21-
You can do this instead, and now there's no error:
22-
23-
```
24-
window.fetch('https://cors-buster-tbgktfqyku.now.sh/nodejs.org/dist/v6.10.2/node-v6.10.2-linux-x64.tar.gz')
25-
```
26-
27-
## Is this safe?
28-
29-
CORS is designed to prevent a 3rd party (Eve) from doing evil things to Alice
30-
using her browser to make HTTP requests to Bob, essentially impersonating Alice.
31-
Browsers prevent JavaScript from making this kind of Cross-Origin AJAX Request
32-
by default. But if this server is making the request *on behalf* of your
33-
JavaScript, there is no way we could be impersonating Alice. Alice is safe.
34-
Bob was never protected in the first place. Eve has better things to do with
35-
her time.
36-
37-
## But I need to POST/PUT/etc with data?
38-
39-
That works too! Just make an OPTIONS/POST/PUT/DELETE/etc request and it will be forwarded.
40-
If you can only make GET requests, you can provide a `method` query parameter and
41-
the server will make it that kind of request instead.
42-
43-
## Supported headers
44-
45-
If there's a way to whitelist ALL headers, let me know. The one's I've explicitly added
46-
so far are:
47-
48-
#### Request Headers:
49-
50-
- accept-encoding
51-
- accept-language
52-
- accept
53-
- access-control-allow-origin
54-
- authorization
55-
- cache-control
56-
- connection
57-
- content-length
58-
- content-type
59-
- dnt
60-
- pragma
61-
- range
62-
- referer
63-
- user-agent
64-
- x-http-method-override
65-
- x-requested-with
66-
67-
#### Response Headers:
68-
69-
- accept-ranges
70-
- age
71-
- cache-control
72-
- content-length
73-
- content-language
74-
- content-type
75-
- date
76-
- etag
77-
- expires
78-
- last-modified
79-
- pragma
80-
- server
81-
- transfer-encoding
82-
- vary
83-
- x-github-request-id
84-
85-
## That is nice, I want to run my own server
86-
87-
Sure thing, just do:
88-
89-
```
90-
git clone https://github.com/wmhilton/cors-buster
91-
cd cors-buster
92-
npm install
93-
PORT=80 npm start
94-
```
95-
96-
## No, I meant I want to deploy it to zeit.now.sh
97-
98-
Even easier, just do:
99-
100-
```
101-
now wmhilton/cors-buster
102-
```
8+
It is derived from https://github.com/wmhilton/cors-buster with added restrictions to prevent abuse.
1039

10410
## License
10511

allow-request.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const url = require('url')
2+
3+
function isPreflight (req, u) {
4+
return req.method === 'OPTIONS'
5+
}
6+
7+
function isInfoRefs (req, u) {
8+
return req.method === 'GET' && u.pathname.endsWith('/info/refs') && (u.query.service === 'git-upload-pack' || u.query.service === 'git-receive-pack')
9+
}
10+
11+
function isPull (req, u) {
12+
return req.method === 'POST' && req.headers['content-type'] === 'application/x-git-upload-pack-request' && u.pathname.endsWith('git-upload-pack')
13+
}
14+
15+
function isPush (req, u) {
16+
return req.method === 'POST' && req.headers['content-type'] === 'application/x-git-receive-pack-request' && u.pathname.endsWith('git-receive-pack')
17+
}
18+
19+
module.exports = function allow (req, u) {
20+
return (isPreflight(req, u) || isInfoRefs(req, u) || isPull(req, u) || isPush(req, u))
21+
}

index.js

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
const url = require('url')
33
const pkg = require('./package.json')
44
const {send} = require('micro')
5+
const origin = process.env.ALLOW_ORIGIN
56
const allowHeaders = [
67
'accept-encoding',
78
'accept-language',
@@ -37,18 +38,19 @@ const exposeHeaders = [
3738
'vary',
3839
'x-github-request-id',
3940
]
40-
const cors = require('./micro-cors.js')({allowHeaders, exposeHeaders})
4141
const fetch = require('node-fetch')
42+
const cors = require('./micro-cors.js')({allowHeaders, exposeHeaders, origin})
43+
const allow = require('./allow-request.js')
4244

4345
async function service (req, res) {
44-
let p = url.parse(req.url, true).path
45-
let parts = p.match(/\/([^\/]*)\/(.*)/)
46-
if (parts === null) {
46+
let u = url.parse(req.url, true)
47+
48+
if (u.pathname === '/') {
4749
res.setHeader('content-type', 'text/html')
4850
let html = `<!DOCTYPE html>
4951
<html>
50-
<title>cors-buster</title>
51-
<h1>CORS Buster! 👻&#x20E0;</h1>
52+
<title>@isomorphic-git/cors-proxy</title>
53+
<h1>@isomorphic-git/cors-proxy</h1>
5254
<h2>See docs: <a href="https://npmjs.org/package/${pkg.name}">https://npmjs.org/package/${pkg.name}</a></h2>
5355
<h2>Authenticity</h2>
5456
This is a publicly available service. As such you may wonder if it is safe to trust.
@@ -58,42 +60,25 @@ async function service (req, res) {
5860
The cloud hosting provider keeps log of all requests. That log is public and available on this page: <a href="/_logs">/_logs</a>.
5961
It records the URL, origin IP, referer, and user-agent. None of the sensitive HTTP headers (including those used for
6062
HTTP Basic Auth and HTTP Token auth) are ever logged.
61-
<h2>Request API</h2>
62-
${process.env.NOW_URL}/domain/path?query
63-
<ul>
64-
<li>domain - the destination host</li>
65-
<li>path - the rest of the URL</li>
66-
<li>query - optional query parameters</li>
67-
</ul>
68-
Example: ${process.env.NOW_URL}/github.com/wmhilton/cors-buster?service=git-upload-pack
69-
<h2>Supported Protocols</h2>
70-
In order to protect users who might send their usernames and passwords through the proxy,
71-
all requests must be made using HTTPS. Plain old HTTP is insecure and therefore not allowed.
72-
This proxy cannot be used to make requests to HTTP-only sites.
73-
<h2>Supported HTTP Methods</h2>
74-
<ul>
75-
<li>All - OPTIONS, GET, POST, PUT, DELETE, etc</li>
76-
</ul>
77-
<h2>Supported Query Parameters</h2>
78-
<ul>
79-
<li>All URL query parameters are passed on as-is to the destination address.</li>
80-
</ul>
81-
<h2>Supported Headers</h2>
82-
<ul>
83-
${allowHeaders.map(x => `<li>${x}</li>`).join('\n')}
84-
</ul>
8563
</html>
8664
`
8765
return send(res, 400, html)
8866
}
8967

68+
if (!allow(req, u)) {
69+
// Don't waste my precious bandwidth
70+
return send(res, 403, '')
71+
}
72+
9073
let headers = {}
9174
for (let h of allowHeaders) {
9275
if (req.headers[h]) {
9376
headers[h] = req.headers[h]
9477
}
9578
}
9679

80+
let p = u.path
81+
let parts = p.match(/\/([^\/]*)\/(.*)/)
9782
let pathdomain = parts[1]
9883
let remainingpath = parts[2]
9984
console.log(`https://${pathdomain}/${remainingpath}`)

0 commit comments

Comments
 (0)