-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathmiddleware.js
115 lines (105 loc) · 3.97 KB
/
middleware.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
var spawn = require('child_process').spawn
var fs = require('fs')
var path = require('path')
var url = require('url')
var auth = require('basic-auth')
var chalk = require('chalk')
var fixturez = require('fixturez')
var backend = require('git-http-backend')
var htpasswd = require('htpasswd-js')
function pad (str) {
return (str + ' ').slice(0, 7)
}
function factory (config) {
if (!config.root) throw new Error('Missing required "gitHttpServer.root" config option')
if (!config.route) throw new Error('Missing required "gitHttpServer.route" config option')
if (!config.route.startsWith('/')) throw new Error('"gitHttpServer.route" must start with a "/"')
// TODO: Make this configurable in karma.conf.js
var f = fixturez(config.root, {root: process.cwd(), glob: config.glob})
function getGitDir (req) {
var u = url.parse(req.url)
if (u.pathname.startsWith(config.route)) {
if (req.method === 'GET' && u.pathname.endsWith('/info/refs')) {
let gitdir = u.pathname.replace(config.route, '').replace(/\/info\/refs$/, '').replace(/^\//, '')
let fixtureName = path.posix.basename(gitdir)
return f.find(fixtureName)
}
if (req.method === 'POST' && req.headers['content-type'] === 'application/x-git-upload-pack-request') {
let gitdir = u.pathname.replace(config.route, '').replace(/\/git-upload-pack$/, '').replace(/^\//, '')
let fixtureName = path.posix.basename(gitdir)
return f.find(fixtureName)
}
if (req.method === 'POST' && req.headers['content-type'] === 'application/x-git-receive-pack-request') {
let gitdir = u.pathname.replace(config.route, '').replace(/\/git-receive-pack$/, '').replace(/^\//, '')
let fixtureName = path.posix.basename(gitdir)
return f.copy(fixtureName)
}
}
return null
}
return async function middleware (req, res, next) {
// handle pre-flight OPTIONS
if (req.method === 'OPTIONS') {
res.statusCode = 204
res.end('')
return
}
if (!next) next = () => void(0)
try {
var gitdir = getGitDir(req)
} catch (err) {
res.statusCode = 404
res.end(err.message + '\n')
return
}
if (gitdir == null) return next()
// Check for a .htaccess file
let data = null
try {
data = fs.readFileSync(path.join(gitdir, '.htpasswd'), 'utf8')
} catch (err) {
// no .htaccess file, proceed without authentication
}
if (data) {
// The previous line would have failed if there wasn't an .htaccess file, so
// we must treat this as protected.
let cred = auth.parse(req.headers['authorization'])
if (cred === undefined) {
res.statusCode = 401
// The default reason phrase used in Node is "Unauthorized", but
// we will use "Authorization Required" to match what Github uses.
res.statusMessage = 'Authorization Required'
res.setHeader('WWW-Authenticate', 'Basic')
res.end('Unauthorized' + '\n')
return
}
let valid = await htpasswd.authenticate({
username: cred.name,
password: cred.pass,
data
})
if (!valid) {
res.statusCode = 401
// The default reason phrase used in Node is "Unauthorized", but
// we will use "Authorization Required" to match what Github uses.
res.statusMessage = 'Authorization Required'
res.setHeader('WWW-Authenticate', 'Basic')
res.end('Bad credentials' + '\n')
return
}
}
req.pipe(backend(req.url, function (err, service) {
if (err) {
res.statusCode = 500
res.end(err + '\n')
return
}
res.setHeader('content-type', service.type)
// console.log('[git-http-server] ' + service.cmd + ' ' + service.args.concat(gitdir).join(' '))
var ps = spawn(service.cmd, service.args.concat(gitdir))
ps.stdout.pipe(service.createStream()).pipe(ps.stdin)
})).pipe(res)
}
}
factory.$inject = ['config.gitHttpServer']
module.exports = factory