git ssb

30+

cel / git-ssb-web



Commit 8fbdc0d4ddc18ce405cf50944702c26c42885bce

Restrict private requests by Host and Referer

cel committed on 4/10/2020, 8:12:43 PM
Parent: d0d23d8d9e03d38b5f6a89d3ab680cd659544746

Files changed

index.jschanged
index.jsView
@@ -38,11 +38,11 @@
3838
3939 function parseAddr(str, def) {
4040 if (!str) return def
4141 var i = str.lastIndexOf(':')
42- if (~i) return {host: str.substr(0, i), port: str.substr(i+1)}
42 + if (~i) return {host: str.substr(0, i), port: Number(str.substr(i+1))}
4343 if (isNaN(str)) return {host: str, port: def.port}
44- return {host: def.host, port: str}
44 + return {host: def.host, port: Number(str)}
4545 }
4646
4747 function tryDecodeURIComponent(str) {
4848 if (!str || (str[0] == '%' && ref.isBlobId(str)))
@@ -138,10 +138,12 @@
138138 this.serveAcmeChallenge = require('./lib/acme-challenge')(ssb)
139139
140140 var addr = parseAddr(config.listenAddr, {
141141 host: webConfig.host || 'localhost',
142- port: webConfig.port || 7718
142 + port: Number(webConfig.port) || 7718
143143 })
144 + this.listenHost = addr.host
145 + this.listenPort = addr.port
144146 this.listen(addr.host, addr.port)
145147
146148 this.monitorSsbClient()
147149 }
@@ -213,8 +215,14 @@
213215 if (req.url.startsWith('/.well-known/acme-challenge'))
214216 return this.serveAcmeChallenge(req, res)
215217
216218 req._u = url.parse(req.url, true)
219 +
220 + if (!this.isHostAllowed(req.headers.host)) {
221 + res.writeHead(403)
222 + return res.end('403 Forbidden')
223 + }
224 +
217225 var locale = req._u.query.locale ||
218226 (/locale=([^;]*)/.exec(req.headers.cookie) || [])[1]
219227 var reqLocales = req.headers['accept-language']
220228 var locales = reqLocales ? reqLocales.split(/, */).map(function (item) {
@@ -228,8 +236,35 @@
228236 pull(this.handleRequest(req), serve(req, res))
229237 }.bind(this))
230238 }
231239
240 +G.isHostAllowed = function (hostname) {
241 + if (this.isPublic) return true
242 + if (!hostname) return false
243 + var addr = parseAddr(hostname, {port: 80})
244 + if (addr.port !== this.listenPort) return false
245 + var host = addr.host
246 + return host === 'localhost' ||
247 + host === '[::1]' ||
248 + host === '127.0.0.1' ||
249 + host === this.listenHost
250 +}
251 +
252 +var unsafePathRegex = /^\/(?:&|%26)|^%[^\/]+\/raw\//
253 +
254 +G.isRefererAllowed = function (referer) {
255 + if (this.isPublic) return true
256 + if (!referer) return false
257 + var u = url.parse(referer)
258 + return u.protocol === 'http:'
259 + && (Number(u.port) || 80) === this.listenPort
260 + && (u.hostname === this.listenHost
261 + || u.hostname === 'localhost'
262 + || u.hostname === '::1'
263 + || u.hostname === '127.0.0.1')
264 + && u.pathname && !unsafePathRegex.test(u.pathname)
265 +}
266 +
232267 G.handleRequest = function (req) {
233268 var path = req._u.pathname.slice(1)
234269 var dirs = ref.isLink(path) ? [path] :
235270 path.split(/\/+/).map(tryDecodeURIComponent)
@@ -263,8 +298,13 @@
263298 G.handlePOST = function (req, dir) {
264299 var self = this
265300 if (self.isPublic)
266301 return self.serveBuffer(405, req._t('error.POSTNotAllowed'))
302 +
303 + if (!self.isRefererAllowed(req.headers.referer)) {
304 + return this.serveBuffer(403, 'Referer not allowed')
305 + }
306 +
267307 return u.readNext(function (cb) {
268308 readReqForm(req, function (err, data) {
269309 if (err) return cb(null, self.serveError(req, err, 400))
270310 if (!data) return cb(null, self.serveError(req,

Built with git-ssb-web