Skip to content

Commit 476b3e2

Browse files
authored
feat: allow injecting an authorization middleware (#6)
1 parent fc07a28 commit 476b3e2

File tree

2 files changed

+95
-6
lines changed

2 files changed

+95
-6
lines changed

README.md

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,73 @@ Kill the process with the PID specified in `$PWD/cors-proxy.pid`:
3939
cors-proxy stop
4040
```
4141

42-
## Configuration
42+
### CLI configuration
4343

4444
Environment variables:
4545
- `PORT` the port to listen to (if run with `npm start`)
4646
- `ALLOW_ORIGIN` the value for the 'Access-Control-Allow-Origin' CORS header
4747
- `INSECURE_HTTP_ORIGINS` comma separated list of origins for which HTTP should be used instead of HTTPS (added to make developing against locally running git servers easier)
4848

49+
50+
## Middleware usage
51+
52+
You can also use the `cors-proxy` as a middleware in your own server.
53+
54+
```js
55+
const express = require('express')
56+
const corsProxy = require('@isomorphic-git/cors-proxy/middleware.js')
57+
58+
const app = express()
59+
const options = {}
60+
61+
app.use(corsProxy(options))
62+
63+
```
64+
65+
### Middleware configuration
66+
67+
*The middleware doesn't use the environment variables.* The options object supports the following properties:
68+
69+
- `origin`: _string_. The value for the 'Access-Control-Allow-Origin' CORS header
70+
- `insecure_origins`: _string[]_. Array of origins for which HTTP should be used instead of HTTPS (added to make developing against locally running git servers easier)
71+
- `authorization`: _(req, res, next) => void_. A middleware function you can use to handle custom authorization. Is run after filtering for git-like requests and handling CORS but before the request is proxied.
72+
73+
_Example:_
74+
```ts
75+
app.use(
76+
corsProxy({
77+
authorization: (req: Request, res: Response, next: NextFunction) => {
78+
// proxied git HTTP requests already use the Authorization header for git credentials,
79+
// so their [Company] credentials are inserted in the X-Authorization header instead.
80+
if (getAuthorizedUser(req, 'X-Authorization')) {
81+
return next();
82+
} else {
83+
return res.status(401).send("Unable to authenticate you with [Company]'s git proxy");
84+
}
85+
},
86+
})
87+
);
88+
89+
// Only requests with a valid JSON Web Token will be proxied
90+
function getAuthorizedUser(req: Request, header: string = 'Authorization') {
91+
const Authorization = req.get(header);
92+
93+
if (Authorization) {
94+
const token = Authorization.replace('Bearer ', '');
95+
try {
96+
const verifiedToken = verify(token, env.APP_SECRET) as IToken;
97+
if (verifiedToken) {
98+
return {
99+
id: verifiedToken.userId,
100+
};
101+
}
102+
} catch (e) {
103+
// noop
104+
}
105+
}
106+
}
107+
```
108+
49109
## License
50110

51111
This work is released under [The MIT License](https://opensource.org/licenses/MIT)

middleware.js

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const allowHeaders = [
1919
'range',
2020
'referer',
2121
'user-agent',
22+
'x-authorization',
2223
'x-http-method-override',
2324
'x-requested-with',
2425
]
@@ -58,19 +59,47 @@ const filter = (predicate, middleware) => {
5859
return corsProxyMiddleware
5960
}
6061

61-
module.exports = ({ origin, insecure_origins = [] } = {}) => {
62+
const compose = (...handlers) => {
63+
const composeTwo = (handler1, handler2) => {
64+
function composed (req, res, next) {
65+
handler1(req, res, (err) => {
66+
if (err) {
67+
return next(err)
68+
} else {
69+
return handler2(req, res, next)
70+
}
71+
})
72+
}
73+
return composed
74+
}
75+
let result = handlers.pop()
76+
while(handlers.length) {
77+
result = composeTwo(handlers.pop(), result)
78+
}
79+
return result
80+
}
81+
82+
function noop (_req, _res, next) {
83+
next()
84+
}
85+
86+
module.exports = ({ origin, insecure_origins = [], authorization = noop } = {}) => {
6287
function predicate (req) {
6388
let u = url.parse(req.url, true)
6489
// Not a git request, skip
6590
return allow(req, u)
6691
}
67-
function middleware (req, res) {
68-
let u = url.parse(req.url, true)
69-
92+
function sendCorsOK (req, res, next) {
7093
// Handle CORS preflight request
7194
if (req.method === 'OPTIONS') {
7295
return send(res, 200, '')
96+
} else {
97+
next()
7398
}
99+
}
100+
function middleware (req, res) {
101+
let u = url.parse(req.url, true)
102+
74103

75104
let headers = {}
76105
for (let h of allowHeaders) {
@@ -110,5 +139,5 @@ module.exports = ({ origin, insecure_origins = [] } = {}) => {
110139
allowCredentials: false,
111140
origin
112141
})
113-
return filter(predicate, cors(middleware))
142+
return filter(predicate, cors(compose(sendCorsOK, authorization, middleware)))
114143
}

0 commit comments

Comments
 (0)