diff options
Diffstat (limited to 'lib/server.js')
-rw-r--r-- | lib/server.js | 49 |
1 files changed, 43 insertions, 6 deletions
diff --git a/lib/server.js b/lib/server.js index 0dcce21..ef3ea4c 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1,4 +1,5 @@ const arrayRemove = require('unordered-array-remove') +const escapeHtml = require('escape-html') const http = require('http') const mime = require('mime') const pump = require('pump') @@ -90,6 +91,9 @@ function Server (torrent, opts = {}) { // Prevent browser mime-type sniffing res.setHeader('X-Content-Type-Options', 'nosniff') + // Defense-in-depth: Set a strict Content Security Policy to mitigate XSS + res.setHeader('Content-Security-Policy', "base-uri 'none'; default-src 'none'; frame-ancestors 'none'; object-src 'none';") + // Allow CORS requests to specify arbitrary headers, e.g. 'Range', // by responding to the OPTIONS preflight request with the specified // origin and requested headers. @@ -147,11 +151,26 @@ function Server (torrent, opts = {}) { res.statusCode = 200 res.setHeader('Content-Type', 'text/html') - const listHtml = torrent.files.map((file, i) => `<li><a download="${file.name}" href="/${i}/${file.name}">${file.path}</a> (${file.length} bytes)</li>`).join('<br>') + const listHtml = torrent.files + .map((file, i) => ( + `<li> + <a + download="${escapeHtml(file.name)}" + href="/${escapeHtml(i)}/${escapeHtml(file.name)}" + > + ${escapeHtml(file.path)} + </a> + (${escapeHtml(file.length)} bytes) + </li>` + )) + .join('<br>') const html = getPageHTML( - `${torrent.name} - WebTorrent`, - `<h1>${torrent.name}</h1><ol>${listHtml}</ol>` + `${escapeHtml(torrent.name)} - WebTorrent`, + ` + <h1>${escapeHtml(torrent.name)}</h1> + <ol>${listHtml}</ol> + ` ) res.end(html) } @@ -160,7 +179,10 @@ function Server (torrent, opts = {}) { res.statusCode = 404 res.setHeader('Content-Type', 'text/html') - const html = getPageHTML('404 - Not Found', '<h1>404 - Not Found</h1>') + const html = getPageHTML( + '404 - Not Found', + '<h1>404 - Not Found</h1>' + ) res.end(html) } @@ -214,7 +236,10 @@ function Server (torrent, opts = {}) { function serveMethodNotAllowed () { res.statusCode = 405 res.setHeader('Content-Type', 'text/html') - const html = getPageHTML('405 - Method Not Allowed', '<h1>405 - Method Not Allowed</h1>') + const html = getPageHTML( + '405 - Method Not Allowed', + '<h1>405 - Method Not Allowed</h1>' + ) res.end(html) } } @@ -222,8 +247,20 @@ function Server (torrent, opts = {}) { return server } +// NOTE: Arguments must already be HTML-escaped function getPageHTML (title, pageHtml) { - return `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>${title}</title></head><body>${pageHtml}</body></html>` + return ` + <!DOCTYPE html> + <html lang="en"> + <head> + <meta charset="utf-8"> + <title>${title}</title> + </head> + <body> + ${pageHtml} + </body> + </html> + ` } // From https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent |