diff --git a/packages/proxy/bin/server.ts b/packages/proxy/bin/server.ts index defd48431..bb50efc8b 100644 --- a/packages/proxy/bin/server.ts +++ b/packages/proxy/bin/server.ts @@ -1,5 +1,6 @@ import * as http from 'http' import * as httpProxy from 'http-proxy' +import * as path from 'path' const proxy = httpProxy.createProxyServer({ secure: true, @@ -13,6 +14,26 @@ proxy.on('error', (error, req, res) => { res.end(`Proxying failed for URL: ${req.url} Error: ${error.message}`) }) +// 10 MB in bytes +const MAX_IMAGE_SIZE = 10 * 1024 * 1024 + +proxy.on('proxyRes', (proxyRes, _req, res) => { + const contentLength = parseInt(proxyRes.headers['content-length'] as string) + if (contentLength > MAX_IMAGE_SIZE) { + res.writeHead(413, { 'Content-Type': 'text/plain' }) + res.end(`Image size exceeds the limit of ${MAX_IMAGE_SIZE} bytes.`) + return + } + + // validate response content type to be image + const contentType = proxyRes.headers['content-type'] as string + if (!contentType.startsWith('image/')) { + res.writeHead(400, { 'Content-Type': 'text/plain' }) + res.end(`Invalid content type: ${contentType}`) + return + } +}) + http .createServer((req, res) => { res.setHeader('Access-Control-Allow-Origin', '*') @@ -36,9 +57,27 @@ http delete req.headers['x-auth-token'] delete req.headers['x-auth-offline-token'] - const target = (req.url as string).slice(1) + /** Remove / or // prefixes */ + const target = (req.url as string).replace(/^\/+/, '') + try { const url = new URL(target) + + if (url.protocol !== 'http:' && url.protocol !== 'https:') { + throw new Error('Invalid URL protocol') + } + + if (url.hostname === '') { + throw new Error('Invalid URL hostname') + } + + const ext = path.extname(url.pathname) + if (!['.jpg', '.jpeg', '.png', '.gif'].includes(ext)) { + res.writeHead(400) + res.end('Only image files can be proxied') + return + } + req.url = url.href proxy.web(req, res, { target: target, @@ -47,6 +86,7 @@ http toProxy: true, }) } catch (error) { + res.writeHead(500) res.end(`Invalid URL: ${target}`) } })