mirror of https://github.com/mthenw/frontail.git
Basic Auth - closes #14
parent
5d3506b172
commit
987f285ead
21
README.md
21
README.md
|
@ -6,6 +6,7 @@ frontail is node.js application for serving `tail -F` output to browser using [s
|
|||
|
||||
### Features
|
||||
|
||||
* basic auth
|
||||
* filtering logs (press Tab to focus input)
|
||||
* terminal-like autoscrolling
|
||||
* marking logs
|
||||
|
@ -20,14 +21,16 @@ frontail is node.js application for serving `tail -F` output to browser using [s
|
|||
|
||||
Options:
|
||||
|
||||
-h, --help output usage information
|
||||
-V, --version output the version number
|
||||
-p, --port <port> server port, default 9001
|
||||
-n, --number <number> starting lines number, default 10
|
||||
-l, --lines <number> number on lines stored in frontend, default 2000
|
||||
-d, --daemonize run as daemon
|
||||
--pid-path <path> if run as deamon file that will store the process ID, default /var/run/frontail.pid
|
||||
--log-path <path> if run as deamon file that will be used as a log, default /dev/null
|
||||
-h, --help output usage information
|
||||
-V, --version output the version number
|
||||
-p, --port <port> server port, default 9001
|
||||
-n, --number <number> starting lines number, default 10
|
||||
-l, --lines <number> number on lines stored in frontend, default 2000
|
||||
-d, --daemonize run as daemon
|
||||
-U, --user <username> Basic Auth user
|
||||
-P, --password <password> Basic Auth password
|
||||
--pid-path <path> if run as daemon file that will store the process ID, default /var/run/frontail.pid
|
||||
--log-path <path> if run as daemon file that will be used as a log, default /dev/null
|
||||
|
||||
Web interface is on http://localhost:[port]
|
||||
|
||||
|
@ -39,7 +42,7 @@ Web interface is on http://localhost:[port]
|
|||
|
||||
(The MIT License)
|
||||
|
||||
Copyright 2012 Maciej Winnicki http://maciejwinnicki.pl
|
||||
Copyright 2013 Maciej Winnicki http://maciejwinnicki.pl
|
||||
|
||||
This project is free software released under the MIT/X11 license:
|
||||
|
||||
|
|
104
lib/frontail.js
104
lib/frontail.js
|
@ -1,11 +1,12 @@
|
|||
var program = require('commander')
|
||||
, http = require('http')
|
||||
, fs = require('fs')
|
||||
, socketio = require('socket.io')
|
||||
, spawn = require('child_process').spawn
|
||||
, connect = require('connect')
|
||||
, sanitizer = require('validator').sanitize
|
||||
, daemon = require('daemon');
|
||||
var program = require('commander')
|
||||
, http = require('http')
|
||||
, fs = require('fs')
|
||||
, socketio = require('socket.io')
|
||||
, spawn = require('child_process').spawn
|
||||
, connect = require('connect')
|
||||
, cookieParser = require('cookie')
|
||||
, sanitizer = require('validator').sanitize
|
||||
, daemon = require('daemon');
|
||||
|
||||
/**
|
||||
* Parse arg
|
||||
|
@ -15,11 +16,13 @@ program
|
|||
.usage('[options] [file ...]')
|
||||
.option('-p, --port <port>', 'server port, default 9001', Number, 9001)
|
||||
.option('-n, --number <number>', 'starting lines number, default 10', Number, 10)
|
||||
.option('-l, --lines <number>', 'number on lines stored in browser, default 2000', Number, 2000)
|
||||
.option('-l, --lines <lines>', 'number on lines stored in browser, default 2000', Number, 2000)
|
||||
.option('-d, --daemonize', 'run as daemon')
|
||||
.option('--pid-path <path>', 'if run as deamon file that will store the process ID, default /var/run/frontail.pid',
|
||||
.option('-U, --user <username>', 'Basic Auth user', String, false)
|
||||
.option('-P, --password <password>', 'Basic Auth password', String, false)
|
||||
.option('--pid-path <path>', 'if run as daemon file that will store the process id, default /var/run/frontail.pid',
|
||||
String, '/var/run/frontail.pid')
|
||||
.option('--log-path <path>', 'if run as deamon file that will be used as a log, default /dev/null',
|
||||
.option('--log-path <path>', 'if run as daemon file that will be used as a log, default /dev/null',
|
||||
String, '/dev/null')
|
||||
.parse(process.argv);
|
||||
|
||||
|
@ -31,13 +34,31 @@ if (program.args.length === 0) {
|
|||
process.exit();
|
||||
} else {
|
||||
var files = program.args;
|
||||
|
||||
var doAuthorization = false;
|
||||
if (program.user && program.password) {
|
||||
doAuthorization = true;
|
||||
var sessionSecret = String(+new Date()) + Math.random();
|
||||
var sessionKey = 'sid';
|
||||
}
|
||||
}
|
||||
|
||||
if (program.daemonize) {
|
||||
/**
|
||||
* Daemonize process
|
||||
*/
|
||||
var logFile = fs.openSync(program.logPath, 'a');
|
||||
var args = ['-p', program.port, '-n', program.number, '-l', program.lines];
|
||||
|
||||
if (doAuthorization) {
|
||||
args = args.concat(['-U', program.user, '-P', program.password]);
|
||||
}
|
||||
|
||||
args = args.concat(files);
|
||||
|
||||
var proc = daemon.daemon(
|
||||
__filename,
|
||||
['-p', program.port, '-n', program.number, files],
|
||||
args,
|
||||
{
|
||||
stdout: logFile,
|
||||
stderr: logFile
|
||||
|
@ -46,23 +67,35 @@ if (program.daemonize) {
|
|||
fs.writeFileSync(program.pidPath, proc.pid);
|
||||
} else {
|
||||
/**
|
||||
* Server setup
|
||||
* HTTP server setup
|
||||
*/
|
||||
var app = connect()
|
||||
.use(connect.static(__dirname + '/assets'))
|
||||
.use(function (req, res) {
|
||||
fs.readFile(__dirname + '/index.html', function (err, data) {
|
||||
if (err) {
|
||||
res.writeHead(500, {'Content-Type': 'text/plain'});
|
||||
res.end('Interal error');
|
||||
} else {
|
||||
res.writeHead(200, {'Content-Type': 'text/html'});
|
||||
res.end(data.toString('utf-8').replace(
|
||||
/__TITLE__/g, 'tail -F ' + files.join(' ')), 'utf-8'
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
var app = connect();
|
||||
|
||||
if (doAuthorization) {
|
||||
app
|
||||
.use(connect.cookieParser())
|
||||
.use(connect.session({secret: sessionSecret, key: sessionKey}))
|
||||
.use(connect.basicAuth(function (user, password) {
|
||||
return program.user == user & program.password == password;
|
||||
}));
|
||||
}
|
||||
|
||||
app
|
||||
.use(connect.static(__dirname + '/web/assets'))
|
||||
.use(function (req, res) {
|
||||
fs.readFile(__dirname + '/web/index.html', function (err, data) {
|
||||
if (err) {
|
||||
res.writeHead(500, {'Content-Type': 'text/plain'});
|
||||
res.end('Internal error');
|
||||
} else {
|
||||
res.writeHead(200, {'Content-Type': 'text/html'});
|
||||
res.end(data.toString('utf-8').replace(
|
||||
/__TITLE__/g, 'tail -F ' + files.join(' ')), 'utf-8'
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var server = http.createServer(app).listen(program.port);
|
||||
|
||||
/**
|
||||
|
@ -70,6 +103,21 @@ if (program.daemonize) {
|
|||
*/
|
||||
var io = socketio.listen(server, {log: false});
|
||||
|
||||
if (doAuthorization) {
|
||||
io.set('authorization', function(handshakeData, accept) {
|
||||
if (handshakeData.headers.cookie) {
|
||||
var cookie = cookieParser.parse(handshakeData.headers.cookie);
|
||||
var sessionId = connect.utils.parseSignedCookie(cookie[sessionKey], sessionSecret);
|
||||
if (sessionId) {
|
||||
return accept(null, true);
|
||||
}
|
||||
return accept('Invalid cookie', false);
|
||||
} else {
|
||||
return accept('No cookie in header', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* When connected send starting data
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "frontail",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.2",
|
||||
"description": "tail -F output in browser",
|
||||
"homepage": "https://github.com/mthenw/frontail",
|
||||
"author": {
|
||||
|
@ -16,7 +16,8 @@
|
|||
"socket.io": "0.9.13",
|
||||
"connect": "2.7.3",
|
||||
"validator": "0.4.24",
|
||||
"daemon": "1.0.0"
|
||||
"daemon": "1.0.0",
|
||||
"cookie": "0.1.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
Loading…
Reference in New Issue