diff --git a/lib/application.js b/lib/application.js index 3f0ebbe..dac3955 100644 --- a/lib/application.js +++ b/lib/application.js @@ -20,27 +20,23 @@ const EMPTY_STRING = ''; const USAGE_TRACKER_ID_KEY = 'usage-tracker-id'; const formatWatch = (value) => { - let result = value; if (isNaN(Number(value))) { - result = 0; + return 0; } else if (value < 0) { - result = 0; + return 0; } - return result; + return value; }; const formatDirectory = (value) => { - let absoluteWorkingDirectory = process.cwd(); + const absoluteWorkingDirectory = process.cwd(); if (path.isAbsolute(value)) { - absoluteWorkingDirectory = value; - } else { - absoluteWorkingDirectory = path.join(absoluteWorkingDirectory, value); + return value; } - return absoluteWorkingDirectory; + return path.join(absoluteWorkingDirectory, value); }; const prepare = () => { - if (config.get(configKey.IS_DEBUG)) { config.set(configKey.LOG_LEVEL, 0); } @@ -115,13 +111,10 @@ const prepare = () => { }; module.exports = () => { - prepare(); if (!config.get(configKey.IS_DEBUG)) { - process.on('uncaughtException', (e) => { - new usageTracker.UsageTracker({ owner: config.get(configKey.USAGE_TRACKER_OWNER), repo: config.get(configKey.USAGE_TRACKER_REPO), @@ -140,7 +133,6 @@ module.exports = () => { log.error(e.stack); // still exit as uncaught exception }); - } startServer((nativeServer) => { @@ -148,5 +140,4 @@ module.exports = () => { startWatcher(nativeServer); } }); - }; diff --git a/lib/build-file-list.js b/lib/build-file-list.js index ea848f9..29051ba 100644 --- a/lib/build-file-list.js +++ b/lib/build-file-list.js @@ -25,21 +25,12 @@ const HTML_EXTENSION = '.html'; * @returns {number} sort value */ const compare = (_a, _b) => { - - let result = STILL; - if (_a < _b) { - - result = AHEAD; - + return AHEAD; } else if (_a > _b) { - - result = ABACK; - + return ABACK; } - - return result; - + return STILL; }; /** @@ -50,117 +41,73 @@ const compare = (_a, _b) => { * @returns {String} html content */ module.exports = (files, pathname, absoluteWorkingDirectory) => { - const baseDir = join(absoluteWorkingDirectory, pathname); - let filesFiltered = files.filter((file) => { - + const filesFiltered = files.filter((file) => { if (file.indexOf('.') === 0) { - return false; - } // #3 remove inaccessible files from file list // win下access任何文件都会返回可访问 try { - if (isWindows) { - fs.statSync(join(baseDir, file)); - } else { - fs.accessSync(join(baseDir, file), fs.R_OK); - } - } catch (e) { - return false; - } return true; - }); filesFiltered.sort((a, b) => { - - let _isDirectoryA = fs.lstatSync(join(baseDir, a)).isDirectory(); - let _isDirectoryB = fs.lstatSync(join(baseDir, b)).isDirectory(); - + const _isDirectoryA = fs.lstatSync(join(baseDir, a)).isDirectory(); + const _isDirectoryB = fs.lstatSync(join(baseDir, b)).isDirectory(); // order by priority if (_isDirectoryA && _isDirectoryB) { - return compare(a, b); - } if (_isDirectoryA && !_isDirectoryB) { - return AHEAD; - } if (_isDirectoryB && !_isDirectoryA) { - return ABACK; - } - - let _extensionA = extname(a); - let _extensionB = extname(b); - let _isHtmlA = _extensionA === HTML_EXTENSION; - let _isHtmlB = _extensionB === HTML_EXTENSION; - + const _extensionA = extname(a); + const _extensionB = extname(b); + const _isHtmlA = _extensionA === HTML_EXTENSION; + const _isHtmlB = _extensionB === HTML_EXTENSION; if (_isHtmlA && _isHtmlB) { - return compare(a, b); - } if (_isHtmlA && !_isHtmlB) { - return AHEAD; - } if (_isHtmlB && !_isHtmlA) { - return ABACK; - } - if (_extensionA === _extensionB) { - return compare(a, b); - } - return compare(a, b); - }); if (pathname !== '/') { - filesFiltered.unshift('..'); - } - let list = filesFiltered.map((file) => { - - let ext = extname(file); + const list = filesFiltered.map((file) => { + const ext = extname(file); let _ext = 'other'; - if (ext === HTML_EXTENSION) { - _ext = 'html'; - } if (fs.lstatSync(join(baseDir, file)).isDirectory()) { - _ext = 'dir'; - } if (file === '..') { - _ext = 'null'; - } return { // remove http://ip:port to redirect to correct ip:port @@ -168,7 +115,6 @@ module.exports = (files, pathname, absoluteWorkingDirectory) => { className: _ext, fileName: file }; - }); return pug.compileFile(join(__dirname, '../res/list.pug'), { diff --git a/lib/config.js b/lib/config.js index 3d5dfea..0ea65e7 100644 --- a/lib/config.js +++ b/lib/config.js @@ -4,7 +4,7 @@ */ 'use strict'; -let config = { +const config = { isDebug: false, port: 3000, diff --git a/lib/open-browser.js b/lib/open-browser.js index fa75bdb..f494d59 100644 --- a/lib/open-browser.js +++ b/lib/open-browser.js @@ -14,7 +14,6 @@ const logPrefix = require('../constant/log-prefix'); const configKey = require('../constant/config'); module.exports = () => { - // always use current ip address const protocol = config.get(configKey.SSL) ? 'https:' : 'http:'; @@ -28,5 +27,4 @@ module.exports = () => { // open browser succeeded log.debug(logPrefix.BROWSER, execCommand, openUrl); }); - }; diff --git a/lib/server.js b/lib/server.js index c366749..251f8f5 100644 --- a/lib/server.js +++ b/lib/server.js @@ -18,9 +18,7 @@ const logPrefix = require('../constant/log-prefix'); const configKey = require('../constant/config'); module.exports = (callback) => { - let nativeServer; - const directory = config.get(configKey.DIRECTORY); const watch = config.get(configKey.WATCH); @@ -48,16 +46,14 @@ module.exports = (callback) => { openBrowserFunction(); } // hit `space` will open page in browser - let stdIn = process.stdin; + const stdIn = process.stdin; stdIn.setEncoding('utf8'); stdIn.on('data', openBrowserFunction); callback(nativeServer); }; const listen = () => { - - let port = config.get(configKey.PORT); - + const port = config.get(configKey.PORT); if (config.get(configKey.SSL)) { pem.createCertificate({days: 1, selfSigned: true}, (err, keys) => { if (err) { @@ -72,7 +68,6 @@ module.exports = (callback) => { nativeServer = server.listen(port, serverSuccessCallback) .on('error', serverErrorCallback); } - }; const middlewareList = []; @@ -88,7 +83,6 @@ module.exports = (callback) => { const routeFile = path.join(directory, 'here.js'); getFileStat(routeFile)((err, stat) => { - if (!err) { if (stat.isFile()) { middlewareList.push(require('../middleware/load-route')(server)); diff --git a/lib/watcher.js b/lib/watcher.js index d781db1..5dfbc8c 100644 --- a/lib/watcher.js +++ b/lib/watcher.js @@ -20,43 +20,31 @@ const NOT_FOUNT_INDEX = -1; const A_THOUSAND = 1000; module.exports = (server) => { - const absoluteWorkingDirectory = config.get(configKey.DIRECTORY); const interval = config.get(configKey.WATCH); - let socketList = []; + const socketList = []; - let io = socketServer(server); + const io = socketServer(server); io.on('connection', (socket) => { - socketList.push(socket); socket.on('disconnect', () => { - - let index = socketList.indexOf(socket); - + const index = socketList.indexOf(socket); if (index > NOT_FOUNT_INDEX) { - socketList.splice(index, SPLICE_COUNT); - } - }); - }); - let reload = debounce(() => { - + const reload = debounce(() => { socketList.forEach((socket) => { - log.debug(logPrefix.WATCH, 'reload'); socket.emit('reload'); - }); }, interval * A_THOUSAND); - let watcher = chokidar.watch(absoluteWorkingDirectory, { - + const watcher = chokidar.watch(absoluteWorkingDirectory, { ignored: [ '**/node_modules', /[\/\\]\./, @@ -64,11 +52,9 @@ module.exports = (server) => { '.idea', '.DS_Store' ] - }); watcher.on('all', (action, filePath) => { - log.debug(logPrefix.WATCH, action, path.relative(absoluteWorkingDirectory, filePath)); switch (action) { case 'add': @@ -78,11 +64,9 @@ module.exports = (server) => { reload(); break; } - }); watcher.on('ready', () => { log.info(logPrefix.WATCH, 'ready,', 'reload in', interval, 'seconds'); }); - }; diff --git a/middleware/error.js b/middleware/error.js index a83843d..a930964 100644 --- a/middleware/error.js +++ b/middleware/error.js @@ -7,17 +7,11 @@ const FALLBACK_CONTENT_TYPE = require('../lib/fallback-content-type'); module.exports = function* (next) { - try { - yield next; - } catch (e) { - this.status = 404; this.body = e.stack; this.type = FALLBACK_CONTENT_TYPE; - } - }; diff --git a/middleware/file-explorer.js b/middleware/file-explorer.js index 0a31409..95b65b5 100644 --- a/middleware/file-explorer.js +++ b/middleware/file-explorer.js @@ -23,45 +23,37 @@ const NOT_FOUNT_INDEX = -1; const INDEX_PAGE = 'index.html'; module.exports = function* (next) { - const directory = config.get(configKey.DIRECTORY); // decode for chinese character - let requestPath = decodeURIComponent(this.request.path); - let fullRequestPath = path.join(directory, requestPath); - let stat = yield getFileStat(fullRequestPath); + const requestPath = decodeURIComponent(this.request.path); + const fullRequestPath = path.join(directory, requestPath); + // fix security issue + if (!fullRequestPath.startsWith(directory)) { + return yield next; + } + const stat = yield getFileStat(fullRequestPath); if (stat.isDirectory()) { - - let files = yield readFolder(fullRequestPath); + const files = yield readFolder(fullRequestPath); if (files.indexOf(INDEX_PAGE) !== NOT_FOUNT_INDEX) { - this.redirect(path.join(requestPath, INDEX_PAGE), '/'); - } else { - this.body = buildFileBrowser(files, requestPath, directory); this.type = mime.lookup(INDEX_PAGE); - } - } else if (stat.isFile()) { - this.body = yield readFile(fullRequestPath); let type = mime.lookup(fullRequestPath); if (path.extname(fullRequestPath) === '') { - type = FALLBACK_CONTENT_TYPE; - } this.type = type; log.verbose(logPrefix.RESPONSE, this.request.method, requestPath, 'as', type); - } yield next; - }; diff --git a/middleware/live-reload.js b/middleware/live-reload.js index f896c8d..e72a027 100644 --- a/middleware/live-reload.js +++ b/middleware/live-reload.js @@ -11,32 +11,23 @@ const readFile = require('../lib/read-file'); const NOT_FOUND_INDEX = 1; module.exports = function* (next) { - yield next; if (this.type === 'text/html') { - let response = ''; - let body = this.body.toString('utf-8'); - let reloadJavascript = yield readFile(path.join(__dirname, '../res/reload.js')); + const body = this.body.toString('utf-8'); + const reloadJavascriptContent = yield readFile(path.join(__dirname, '../res/reload.js')); - reloadJavascript = ``; + const reloadJavascript = ``; if (body.indexOf('') !== NOT_FOUND_INDEX) { - - let section = body.split(''); + const section = body.split(''); section.splice(1, 0, `${reloadJavascript}`); response = section.join(''); - } else { - response = body + reloadJavascript; - } - this.body = response; - } - }; diff --git a/middleware/load-route.js b/middleware/load-route.js index 601721e..403ca37 100644 --- a/middleware/load-route.js +++ b/middleware/load-route.js @@ -15,7 +15,7 @@ const config = require('../lib/config'); const loadRoutes = () => { const directory = config.get(configKey.DIRECTORY); const file = path.join(directory, 'here.js'); - let routeList = require(file); + const routeList = require(file); routeList.forEach((route) => { koaRoute[route.method](route.path, require('./log'), function* () { this.body = route.data.apply(this, arguments); @@ -24,16 +24,12 @@ const loadRoutes = () => { }; module.exports = (server) => { - loadRoutes(); server.use(koaRoute.routes()); server.use(koaRoute.allowedMethods()); return function* (next) { - yield next; - }; - }; diff --git a/middleware/log.js b/middleware/log.js index 2ca3d0c..74b99c3 100644 --- a/middleware/log.js +++ b/middleware/log.js @@ -10,7 +10,6 @@ const log = require('log-util'); const logPrefix = require('../constant/log-prefix'); module.exports = function* (next) { - const beginTime = new Date().getTime(); const request = this.request; @@ -21,5 +20,4 @@ module.exports = function* (next) { const endTime = new Date().getTime(); log.verbose(logPrefix.TIME, `${endTime - beginTime}ms`); - }; diff --git a/test/command.js b/test/command.js index a4a67f6..8455718 100644 --- a/test/command.js +++ b/test/command.js @@ -23,7 +23,7 @@ describe('test terminal command `here`', () => { }); it(`\`here\` should output \`[??:??:??.???] ${logPrefix.SERVER} listen http://*.*.*.*:*/\``, (done) => { here = spawn(NODE_COMMAND, [HERE_COMMAND]); - here.stdout.on('data', data => { + here.stdout.on('data', (data) => { data = data.toString(); let regExp = `^\\[\\d{2}:\\d{2}:\\d{2}\\.\\d{3}\\] ${logPrefix.SERVER} listen http:\\/\\/\\d+\\.\\d+\\.\\d+\\.\\d+:\\d+\\/\\n$`; assert.equal(true, new RegExp(regExp, 'g').test(data)); @@ -33,7 +33,7 @@ describe('test terminal command `here`', () => { }); it('`here -v` should output `version`', (done) => { here = spawn(NODE_COMMAND, [HERE_COMMAND, '-v']); - here.stdout.on('data', data => { + here.stdout.on('data', (data) => { data = data.toString(); assert.equal(packageJson.version + '\n', data); done(); @@ -41,7 +41,7 @@ describe('test terminal command `here`', () => { }); it('`here --version` should output `version`', (done) => { here = spawn(NODE_COMMAND, [HERE_COMMAND, '--version']); - here.stdout.on('data', data => { + here.stdout.on('data', (data) => { data = data.toString(); assert.equal(packageJson.version + '\n', data); done(); @@ -49,7 +49,7 @@ describe('test terminal command `here`', () => { }); it('`here -h` should output help', (done) => { here = spawn(NODE_COMMAND, [HERE_COMMAND, '-h']); - here.stdout.on('data', data => { + here.stdout.on('data', (data) => { data = data.toString(); assert.equal(true, !!~data.indexOf('Usage: index [options]') && !!~data.indexOf('Options:')); done(); @@ -58,7 +58,7 @@ describe('test terminal command `here`', () => { it(`\`here -w\` should output \`[??:??:??.???] ${logPrefix.SERVER} listen http://*.*.*.*:*/\` and \`[??:??:??.???] ${logPrefix.WATCH} ready, reload in 0 seconds\``, (done) => { here = spawn(NODE_COMMAND, [HERE_COMMAND, '-w']); let stdoutCount = 0; - here.stdout.on('data', data => { + here.stdout.on('data', (data) => { stdoutCount++; data = data.toString(); switch (stdoutCount) { @@ -82,7 +82,7 @@ describe('test terminal command `here`', () => { it(`\`here --watch 3\` should output \`[??:??:??.???] ${logPrefix.SERVER} listen http://*.*.*.*:*/\` and \`[??:??:??.???] ${logPrefix.WATCH} ready, reload in 3 seconds\``, (done) => { here = spawn(NODE_COMMAND, [HERE_COMMAND, '--watch', '3']); let stdOutCount = 0; - here.stdout.on('data', data => { + here.stdout.on('data', (data) => { stdOutCount++; data = data.toString(); switch (stdOutCount) { @@ -103,24 +103,4 @@ describe('test terminal command `here`', () => { } }); }); - it(`\`here -S\` should output \`[??:??:??.???] ${logPrefix.SERVER} listen https://*.*.*.*:*/\``, (done) => { - here = spawn(NODE_COMMAND, [HERE_COMMAND, '-S']); - here.stdout.on('data', (data) => { - data = data.toString(); - let regExp = `^\\[\\d{2}:\\d{2}:\\d{2}\\.\\d{3}\\] ${logPrefix.SERVER} listen https:\\/\\/\\d+\\.\\d+\\.\\d+\\.\\d+:\\d+\\/\\n$`; - assert.equal(true, new RegExp(regExp).test(data)); - here.kill(); - done(); - }); - }); - it(`\`here --ssl\` should output \`[??:??:??.???] ${logPrefix.SERVER} listen https://*.*.*.*:*/\``, (done) => { - here = spawn(NODE_COMMAND, [HERE_COMMAND, '--ssl']); - here.stdout.on('data', data => { - data = data.toString(); - let regExp = `^\\[\\d{2}:\\d{2}:\\d{2}\\.\\d{3}\\] ${logPrefix.SERVER} listen https:\\/\\/\\d+\\.\\d+\\.\\d+\\.\\d+:\\d+\\/\\n$`; - assert.equal(true, new RegExp(regExp).test(data)); - here.kill(); - done(); - }); - }); });