Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: upgrade deps * feat: remove serve-static dependency and factory * feat: specify file postion in query parameter * chore: update CI scripts
- Loading branch information
Showing
16 changed files
with
1,881 additions
and
416 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
{ | ||
"extends": "semistandard" | ||
"extends": "standard" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
var middleware = require('./lib/middleware'); | ||
var middleware = require('./lib/middleware') | ||
|
||
module.exports = middleware; | ||
module.exports = middleware |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,131 +1,143 @@ | ||
// @ts-check | ||
|
||
var fs = require('fs'); | ||
var url = require('url'); | ||
var resolveFile = require('./resolve'); | ||
var util = require('./util'); | ||
const fs = require('fs') | ||
const url = require('url') | ||
const resolveFile = require('./resolve') | ||
const util = require('./util') | ||
|
||
var defaultOptions = { | ||
const defaultOptions = { | ||
dotfiles: 'ignore', | ||
editorParam: 'edit', | ||
serveStatic: false | ||
}; | ||
editorAtParam: 'at' | ||
} | ||
|
||
function getEditorOptions (config) { | ||
var editorOptions = {}; | ||
var opts = (config || {}); | ||
const editorOptions = {} | ||
const opts = (config || {}) | ||
|
||
if (opts.name != null) { | ||
editorOptions.editor = String(opts.name); | ||
editorOptions.editor = String(opts.name) | ||
} | ||
if (opts.binary != null) { | ||
editorOptions.cmd = String(opts.binary); | ||
editorOptions.cmd = String(opts.binary) | ||
} | ||
if (opts.args != null) { | ||
editorOptions.pattern = String(opts.args); | ||
editorOptions.pattern = String(opts.args) | ||
} | ||
if (opts.terminal != null) { | ||
editorOptions.terminal = Boolean(opts.terminal); | ||
editorOptions.terminal = Boolean(opts.terminal) | ||
} | ||
|
||
return editorOptions; | ||
return editorOptions | ||
} | ||
|
||
function getQueryOptions (urlParts, options) { | ||
var queryOptions = null; | ||
let editor | ||
|
||
if (urlParts.searchParams.has(options.editorParam)) { | ||
editor = urlParts.searchParams.get(options.editorParam) | ||
|
||
if (urlParts.query && urlParts.query[options.editorParam]) { | ||
queryOptions = { | ||
editor: urlParts.query[options.editorParam] | ||
}; | ||
if (!editor && options.editor && options.editor.name) { | ||
editor = options.editor.name | ||
} | ||
} | ||
|
||
return queryOptions; | ||
return editor ? { editor } : null | ||
} | ||
|
||
function getFileName (path) { | ||
var ms = path.match(/^(.*?)(:[0-9]+)?(:[0-9]+)?$/); | ||
const ms = path.match(/^(.*?)(:[0-9]+)?(:[0-9]+)?$/) | ||
|
||
return ms && ms[1] | ||
} | ||
|
||
function getRequestUrl (req) { | ||
const proto = req.connection.encrypted ? 'https' : 'http' | ||
|
||
return ms && ms[1]; | ||
return proto + '://' + req.headers['host'] + req.url | ||
} | ||
|
||
function openInEditorMiddlewareFactory (rootPath, options) { | ||
if (!rootPath) { | ||
throw new Error('root path required'); | ||
throw new Error('root path required') | ||
} | ||
if (typeof rootPath !== 'string') { | ||
throw new Error('root path should be a string'); | ||
throw new Error('root path should be a string') | ||
} | ||
options = Object.assign({}, defaultOptions, options) | ||
|
||
var editorOptions = getEditorOptions(options.editor); | ||
const editorOptions = getEditorOptions(options.editor) | ||
|
||
var self = function openInEditorMiddleware (req, res, next) { | ||
var urlParts = url.parse(req.url, true); | ||
return function openInEditorMiddleware (req, res, next) { | ||
const fullUrl = getRequestUrl(req) | ||
const urlParts = new url.URL(fullUrl) | ||
|
||
if (!urlParts.pathname.match(/:\d+$/) && !(urlParts.query && options.editorParam in urlParts.query)) { | ||
next(); | ||
return; | ||
if (!urlParts.searchParams.has(options.editorParam) && !( | ||
urlParts.pathname.match(/:\d+$/) || urlParts.searchParams.has(options.editorAtParam)) | ||
) { | ||
next() | ||
return | ||
} | ||
|
||
var filePath = resolveFile(urlParts.pathname, { root: rootPath, dotfiles: options.dotfiles }); | ||
var fileName = getFileName(filePath); | ||
const filePath = resolveFile(urlParts.pathname, { | ||
root: rootPath, | ||
dotfiles: options.dotfiles | ||
}) | ||
|
||
const fileName = getFileName(filePath) | ||
|
||
fs.access(fileName, function (err) { | ||
if (err) { | ||
next(); | ||
return; | ||
next() | ||
return | ||
} | ||
|
||
if (req.method === 'POST') { | ||
var params = getQueryOptions(urlParts, options) || editorOptions; | ||
util.open(filePath, params) | ||
.then(function () { | ||
res.writeHead(200, {'Content-Type': 'application/json'}); | ||
res.end(JSON.stringify({ | ||
status: 'ok' | ||
})); | ||
}) | ||
.catch(function (err) { | ||
res.writeHead(500, {'Content-Type': 'application/json'}); | ||
res.end(JSON.stringify({ | ||
status: 'error', | ||
message: String(err) | ||
})); | ||
}); | ||
let pathToOpen = filePath | ||
const params = getQueryOptions(urlParts, options) || editorOptions | ||
|
||
if (urlParts.searchParams.has(options.editorAtParam)) { | ||
const at = String(urlParts.searchParams.get(options.editorAtParam)) | ||
|
||
if (at.match(/^\d+(:\d+)?$/)) { | ||
pathToOpen += ':' + at | ||
} | ||
} | ||
|
||
util.open(pathToOpen, params) | ||
.then(function () { | ||
res.writeHead(200, { | ||
'Content-Type': 'application/json' | ||
}) | ||
res.end(JSON.stringify({ | ||
status: 'ok' | ||
})) | ||
}) | ||
.catch(function (err) { | ||
res.writeHead(500, { | ||
'Content-Type': 'application/json' | ||
}) | ||
res.end(JSON.stringify({ | ||
status: 'error', | ||
message: String(err) | ||
})) | ||
}) | ||
} else { | ||
var template = `<!DOCTYPE html> | ||
const template = `<!DOCTYPE html> | ||
<html> | ||
<body onload="document.getElementById('form').submit()"> | ||
<form id="form" method="post" action=""> | ||
<button type="submit">Open</button> | ||
</form> | ||
</body> | ||
</html>`; | ||
res.writeHead(200, {'Content-Type': 'text/html'}); | ||
res.end(template); | ||
</html>` | ||
res.writeHead(200, { | ||
'Content-Type': 'text/html' | ||
}) | ||
res.end(template) | ||
} | ||
}); | ||
}; | ||
|
||
return self; | ||
} | ||
|
||
function openInEditorMiddlewareFactoryFactory (rootPath, settings) { | ||
if (typeof rootPath === 'object') { | ||
settings = rootPath; | ||
rootPath = undefined; | ||
} | ||
|
||
var opts = Object.assign({}, defaultOptions, settings); | ||
|
||
if (opts.serveStatic) { | ||
return require('./serve-static-adapter')(openInEditorMiddlewareFactory, opts); | ||
} else if (!rootPath && typeof settings === 'object') { | ||
return function (rootPath, options) { | ||
return openInEditorMiddlewareFactoryFactory(rootPath, Object.assign({}, opts, options)); | ||
}; | ||
} else { | ||
return openInEditorMiddlewareFactory(rootPath, opts); | ||
}) | ||
} | ||
} | ||
|
||
module.exports = openInEditorMiddlewareFactoryFactory; | ||
module.exports = openInEditorMiddlewareFactory |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,48 @@ | ||
// @ts-check | ||
|
||
var path = require('path'); | ||
var path = require('path') | ||
|
||
function containsDotFile (pathParts) { | ||
return !!pathParts.filter(function (value) { | ||
return value[0] === '.'; | ||
}).length; | ||
return value[0] === '.' | ||
}).length | ||
} | ||
|
||
module.exports = function resolve (filePath, options) { | ||
var opts = options || {}; | ||
var UP_PATH_REGEXP = /(?:^|[\\/])\.\.(?:[\\/]|$)/; | ||
var absRoot = opts.root ? path.resolve(opts.root) : null; | ||
var filename; | ||
var pathParts; | ||
var opts = options || {} | ||
var UP_PATH_REGEXP = /(?:^|[\\/])\.\.(?:[\\/]|$)/ | ||
var absRoot = opts.root ? path.resolve(opts.root) : null | ||
var filename | ||
var pathParts | ||
|
||
try { | ||
filename = decodeURIComponent(filePath); | ||
filename = decodeURIComponent(filePath) | ||
} catch (err) { | ||
throw new Error('decode the path'); | ||
throw new Error('decode the path') | ||
} | ||
|
||
if (~filename.indexOf('\0')) { | ||
throw new Error('null byte(s)'); | ||
throw new Error('null byte(s)') | ||
} | ||
|
||
if (absRoot !== null) { | ||
if (UP_PATH_REGEXP.test(path.normalize('.' + path.sep + filename))) { | ||
throw new Error('malicious path'); | ||
throw new Error('malicious path') | ||
} | ||
filename = path.normalize(path.join(absRoot, filename)); | ||
absRoot = path.normalize(absRoot + path.sep); | ||
pathParts = filename.substr(absRoot.length).split(path.sep); | ||
filename = path.normalize(path.join(absRoot, filename)) | ||
absRoot = path.normalize(absRoot + path.sep) | ||
pathParts = filename.substr(absRoot.length).split(path.sep) | ||
} else { | ||
if (UP_PATH_REGEXP.test(filename)) { | ||
throw new Error('".." is malicious without "root"'); | ||
throw new Error('".." is malicious without "root"') | ||
} | ||
pathParts = path.normalize(filename).split(path.sep); | ||
filename = path.resolve(filename); | ||
pathParts = path.normalize(filename).split(path.sep) | ||
filename = path.resolve(filename) | ||
} | ||
|
||
if (containsDotFile(pathParts) && opts.dotfiles !== 'allow') { | ||
throw new Error('dotfile handling'); | ||
throw new Error('dotfile handling') | ||
} | ||
|
||
return filename; | ||
}; | ||
return filename | ||
} |
Oops, something went wrong.