altd 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -19
- package/dist/altd.js +132 -0
- package/dist/index.js +29 -0
- package/index.js +23 -18
- package/package.json +67 -62
- package/scripts/build.js +15 -0
- package/src/altd.js +132 -0
- package/check-version.js +0 -19
- package/lib/altd.js +0 -155
package/README.md
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
[](https://travis-ci.org/freddiefujiwara/altd)
|
|
2
|
-
[](https://ci.appveyor.com/project/freddiefujiwara/altd/branch/master)
|
|
3
|
-
[](https://circleci.com/gh/freddiefujiwara/altd)
|
|
4
1
|
[](https://badge.fury.io/js/altd)
|
|
5
|
-
[](https://codecov.io/gh/freddiefujiwara/altd)
|
|
6
|
-
[](https://david-dm.org/freddiefujiwara/altd)
|
|
7
2
|
|
|
8
3
|
# altd
|
|
9
|
-
Web
|
|
4
|
+
Web server access log tail dispatcher for running whitelisted commands based on GET requests.
|
|
10
5
|
|
|
11
6
|
## Requirements
|
|
12
7
|
|
|
13
|
-
|
|
8
|
+
- Node.js 18 or later
|
|
14
9
|
|
|
15
10
|
## Installation
|
|
16
11
|
|
|
@@ -18,26 +13,30 @@ Web Server(like nginx..) Access log tail dispatcher
|
|
|
18
13
|
npm i -g altd
|
|
19
14
|
```
|
|
20
15
|
|
|
16
|
+
## Build
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm run build
|
|
20
|
+
```
|
|
21
|
+
|
|
21
22
|
## Usage
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
Options:
|
|
27
|
-
|
|
28
|
-
-V, --version output the version number
|
|
29
|
-
-h, --help output usage information
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
altd <access_log.file> -w [commands]
|
|
30
26
|
```
|
|
31
27
|
|
|
28
|
+
### Options
|
|
29
|
+
|
|
30
|
+
- `-V, --version` output the version number
|
|
31
|
+
- `-h, --help` output usage information
|
|
32
|
+
- `-w, --whitelist <commands>` comma-separated list of allowed commands
|
|
33
|
+
|
|
32
34
|
## Example
|
|
35
|
+
|
|
33
36
|
```bash
|
|
34
37
|
altd /var/log/nginx/access_log -w ls,hostname
|
|
35
38
|
```
|
|
36
39
|
|
|
37
|
-
## FAQ
|
|
38
|
-
|
|
39
|
-
[FAQ](https://github.com/freddiefujiwara/altd/wiki/FAQ)
|
|
40
|
-
|
|
41
40
|
## Contributing
|
|
42
41
|
|
|
43
42
|
Bug reports and pull requests are welcome on GitHub at https://github.com/freddiefujiwara/altd
|
package/dist/altd.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import {spawn} from 'child_process';
|
|
2
|
+
import Tail from 'nodejs-tail';
|
|
3
|
+
/**
|
|
4
|
+
** main class of AccessLogTailDispatcher
|
|
5
|
+
*/
|
|
6
|
+
export default class AccessLogTailDispatcher {
|
|
7
|
+
/**
|
|
8
|
+
* @constructor
|
|
9
|
+
* @param {string} file access_log
|
|
10
|
+
* @param {Array} whitelist ['command1','command2'..]
|
|
11
|
+
*/
|
|
12
|
+
constructor(file, whitelist) {
|
|
13
|
+
this.file = file;
|
|
14
|
+
this.whitelist = whitelist;
|
|
15
|
+
this.spawn = undefined;
|
|
16
|
+
this.tail = undefined;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get the path from 'GET /path/to/dir HTTP'
|
|
20
|
+
* @param {string} line access_log
|
|
21
|
+
* @return {string} /path/to/dir
|
|
22
|
+
*/
|
|
23
|
+
path(line) {
|
|
24
|
+
if (!(typeof line === 'string')) {
|
|
25
|
+
return '';
|
|
26
|
+
}
|
|
27
|
+
let match = line.match(
|
|
28
|
+
/GET\s((\/[a-z0-9-._~%!$&'()*+,;=:@?]+)+\/?)\sHTTP/i);
|
|
29
|
+
if (null !== match && match.length > 2) {
|
|
30
|
+
return match[1];
|
|
31
|
+
}
|
|
32
|
+
return '';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Extract command and args
|
|
37
|
+
* @param {string} path
|
|
38
|
+
* @return {Array} [command,arg1,arg2...]
|
|
39
|
+
*/
|
|
40
|
+
commandWithArgs(path) {
|
|
41
|
+
if (!(typeof path === 'string')) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
let commands = path.split(/\//).map(function(element, index, array) {
|
|
45
|
+
let ret = "";
|
|
46
|
+
try{
|
|
47
|
+
ret = decodeURIComponent(element);
|
|
48
|
+
}catch(e){
|
|
49
|
+
console.error(e);
|
|
50
|
+
}
|
|
51
|
+
return ret;
|
|
52
|
+
});
|
|
53
|
+
commands.shift();
|
|
54
|
+
return commands;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Filter by whitelist
|
|
59
|
+
* @param {Array} commandWithArgs [command,arg1,arg2...]
|
|
60
|
+
* @param {Array} whitelist ['command1','command2'...]
|
|
61
|
+
* @return {Array} filtered commandWithArgs
|
|
62
|
+
*/
|
|
63
|
+
filterByWhitelist(commandWithArgs, whitelist) {
|
|
64
|
+
if (!this.isArray(commandWithArgs) ||
|
|
65
|
+
!this.isArray(whitelist) ||
|
|
66
|
+
commandWithArgs.length == 0 ||
|
|
67
|
+
whitelist.indexOf(commandWithArgs[0]) == -1
|
|
68
|
+
) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
return commandWithArgs;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Dispatch
|
|
76
|
+
* @param {Array} commandWithArgs [command,arg1,arg2...]
|
|
77
|
+
*/
|
|
78
|
+
dispatch(commandWithArgs) {
|
|
79
|
+
if (commandWithArgs.length == 0) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
let command = commandWithArgs.shift();
|
|
83
|
+
let proc = this.spawn(command, commandWithArgs);
|
|
84
|
+
proc.on('error', (err) => {
|
|
85
|
+
console.error(err);
|
|
86
|
+
});
|
|
87
|
+
proc.stdout.on('data', (data) => {
|
|
88
|
+
process.stdout.write(data.toString());
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* isArray
|
|
94
|
+
* @param {object} obj [command,arg1,arg2...]
|
|
95
|
+
* @return {boolean}
|
|
96
|
+
*/
|
|
97
|
+
isArray(obj) {
|
|
98
|
+
return Object.prototype.toString.call(obj) === '[object Array]';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* run
|
|
103
|
+
* @param {string} file
|
|
104
|
+
* @param {Array} whitelist ['command1','command2'...]
|
|
105
|
+
*/
|
|
106
|
+
run(file, whitelist) {
|
|
107
|
+
if ( typeof file !== 'undefined') {
|
|
108
|
+
this.file = file;
|
|
109
|
+
}
|
|
110
|
+
if ( typeof whitelist !== 'undefined') {
|
|
111
|
+
this.whitelist = whitelist;
|
|
112
|
+
}
|
|
113
|
+
if ( typeof this.spawn === 'undefined') {
|
|
114
|
+
this.spawn = spawn;
|
|
115
|
+
}
|
|
116
|
+
if ( typeof this.tail === 'undefined') {
|
|
117
|
+
this.tail = new Tail(this.file,
|
|
118
|
+
{alwaysStat: true, ignoreInitial: true, persistent: true});
|
|
119
|
+
}
|
|
120
|
+
this.tail.on('line', (line) => {
|
|
121
|
+
this.dispatch(
|
|
122
|
+
this.filterByWhitelist(
|
|
123
|
+
this.commandWithArgs(
|
|
124
|
+
this.path(line)),
|
|
125
|
+
this.whitelist));
|
|
126
|
+
});
|
|
127
|
+
this.tail.on('close', () => {
|
|
128
|
+
console.log('watching stopped');
|
|
129
|
+
});
|
|
130
|
+
this.tail.watch();
|
|
131
|
+
}
|
|
132
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import pkg from './package.json' assert { type: 'json' };
|
|
4
|
+
import AccessLogTailDispatcher from './altd.js';
|
|
5
|
+
|
|
6
|
+
const program = new Command();
|
|
7
|
+
|
|
8
|
+
program
|
|
9
|
+
.name('altd')
|
|
10
|
+
.version(pkg.version)
|
|
11
|
+
.description(pkg.description)
|
|
12
|
+
.argument('<file>')
|
|
13
|
+
.option(
|
|
14
|
+
'-w, --whitelist <commands>',
|
|
15
|
+
'Add commands to whitelist',
|
|
16
|
+
(commands) => commands.split(',')
|
|
17
|
+
)
|
|
18
|
+
.parse(process.argv);
|
|
19
|
+
|
|
20
|
+
const fileValue = program.args[0];
|
|
21
|
+
const { whitelist } = program.opts();
|
|
22
|
+
|
|
23
|
+
if (!fileValue || !whitelist) {
|
|
24
|
+
console.log('altd <file> -w <commands...>');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const altd = new AccessLogTailDispatcher(fileValue, whitelist);
|
|
29
|
+
altd.run();
|
package/index.js
CHANGED
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import pkg from './package.json' assert { type: 'json' };
|
|
4
|
+
import AccessLogTailDispatcher from './src/altd.js';
|
|
5
|
+
|
|
6
|
+
const program = new Command();
|
|
6
7
|
|
|
7
8
|
program
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
.name('altd')
|
|
10
|
+
.version(pkg.version)
|
|
11
|
+
.description(pkg.description)
|
|
12
|
+
.argument('<file>')
|
|
13
|
+
.option(
|
|
14
|
+
'-w, --whitelist <commands>',
|
|
15
|
+
'Add commands to whitelist',
|
|
16
|
+
(commands) => commands.split(',')
|
|
17
|
+
)
|
|
18
|
+
.parse(process.argv);
|
|
19
|
+
|
|
20
|
+
const fileValue = program.args[0];
|
|
21
|
+
const { whitelist } = program.opts();
|
|
22
|
+
|
|
23
|
+
if (!fileValue || !whitelist) {
|
|
24
|
+
console.log('altd <file> -w <commands...>');
|
|
25
|
+
process.exit(1);
|
|
20
26
|
}
|
|
21
|
-
let AccessLogTailDispatcher = require('./lib/altd');
|
|
22
27
|
|
|
23
|
-
|
|
28
|
+
const altd = new AccessLogTailDispatcher(fileValue, whitelist);
|
|
24
29
|
altd.run();
|
package/package.json
CHANGED
|
@@ -1,65 +1,70 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
2
|
+
"name": "altd",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "Access log tail dispatcher",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"altd": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/altd.js",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./dist/altd.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"src",
|
|
16
|
+
"index.js",
|
|
17
|
+
"scripts",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "node scripts/build.js",
|
|
23
|
+
"test": "vitest run --coverage",
|
|
24
|
+
"test:watch": "vitest",
|
|
25
|
+
"prepublishOnly": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/freddiefujiwara/altd.git"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"access log",
|
|
33
|
+
"httpd",
|
|
34
|
+
"log"
|
|
35
|
+
],
|
|
36
|
+
"author": "Fumikazu Fujiwara <npm@ze.gs> (http://freddiefujiwara.com)",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/freddiefujiwara/altd/issues"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/freddiefujiwara/altd#readme",
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"commander": "^12.1.0",
|
|
47
|
+
"nodejs-tail": "^1.1.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
51
|
+
"vitest": "^2.1.8"
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public"
|
|
55
|
+
},
|
|
56
|
+
"vitest": {
|
|
57
|
+
"coverage": {
|
|
58
|
+
"provider": "v8",
|
|
59
|
+
"reporter": [
|
|
60
|
+
"text",
|
|
61
|
+
"html",
|
|
62
|
+
"lcov"
|
|
63
|
+
],
|
|
64
|
+
"exclude": [
|
|
65
|
+
"node_modules",
|
|
66
|
+
"test"
|
|
67
|
+
]
|
|
64
68
|
}
|
|
69
|
+
}
|
|
65
70
|
}
|
package/scripts/build.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile, copyFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const rootDir = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const projectRoot = dirname(rootDir);
|
|
7
|
+
const distDir = join(projectRoot, 'dist');
|
|
8
|
+
|
|
9
|
+
await mkdir(distDir, { recursive: true });
|
|
10
|
+
|
|
11
|
+
const indexSource = await readFile(join(projectRoot, 'index.js'), 'utf8');
|
|
12
|
+
const indexOutput = indexSource.replace('./src/altd.js', './altd.js');
|
|
13
|
+
|
|
14
|
+
await writeFile(join(distDir, 'index.js'), indexOutput);
|
|
15
|
+
await copyFile(join(projectRoot, 'src', 'altd.js'), join(distDir, 'altd.js'));
|
package/src/altd.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import {spawn} from 'child_process';
|
|
2
|
+
import Tail from 'nodejs-tail';
|
|
3
|
+
/**
|
|
4
|
+
** main class of AccessLogTailDispatcher
|
|
5
|
+
*/
|
|
6
|
+
export default class AccessLogTailDispatcher {
|
|
7
|
+
/**
|
|
8
|
+
* @constructor
|
|
9
|
+
* @param {string} file access_log
|
|
10
|
+
* @param {Array} whitelist ['command1','command2'..]
|
|
11
|
+
*/
|
|
12
|
+
constructor(file, whitelist) {
|
|
13
|
+
this.file = file;
|
|
14
|
+
this.whitelist = whitelist;
|
|
15
|
+
this.spawn = undefined;
|
|
16
|
+
this.tail = undefined;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get the path from 'GET /path/to/dir HTTP'
|
|
20
|
+
* @param {string} line access_log
|
|
21
|
+
* @return {string} /path/to/dir
|
|
22
|
+
*/
|
|
23
|
+
path(line) {
|
|
24
|
+
if (!(typeof line === 'string')) {
|
|
25
|
+
return '';
|
|
26
|
+
}
|
|
27
|
+
let match = line.match(
|
|
28
|
+
/GET\s((\/[a-z0-9-._~%!$&'()*+,;=:@?]+)+\/?)\sHTTP/i);
|
|
29
|
+
if (null !== match && match.length > 2) {
|
|
30
|
+
return match[1];
|
|
31
|
+
}
|
|
32
|
+
return '';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Extract command and args
|
|
37
|
+
* @param {string} path
|
|
38
|
+
* @return {Array} [command,arg1,arg2...]
|
|
39
|
+
*/
|
|
40
|
+
commandWithArgs(path) {
|
|
41
|
+
if (!(typeof path === 'string')) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
let commands = path.split(/\//).map(function(element, index, array) {
|
|
45
|
+
let ret = "";
|
|
46
|
+
try{
|
|
47
|
+
ret = decodeURIComponent(element);
|
|
48
|
+
}catch(e){
|
|
49
|
+
console.error(e);
|
|
50
|
+
}
|
|
51
|
+
return ret;
|
|
52
|
+
});
|
|
53
|
+
commands.shift();
|
|
54
|
+
return commands;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Filter by whitelist
|
|
59
|
+
* @param {Array} commandWithArgs [command,arg1,arg2...]
|
|
60
|
+
* @param {Array} whitelist ['command1','command2'...]
|
|
61
|
+
* @return {Array} filtered commandWithArgs
|
|
62
|
+
*/
|
|
63
|
+
filterByWhitelist(commandWithArgs, whitelist) {
|
|
64
|
+
if (!this.isArray(commandWithArgs) ||
|
|
65
|
+
!this.isArray(whitelist) ||
|
|
66
|
+
commandWithArgs.length == 0 ||
|
|
67
|
+
whitelist.indexOf(commandWithArgs[0]) == -1
|
|
68
|
+
) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
return commandWithArgs;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Dispatch
|
|
76
|
+
* @param {Array} commandWithArgs [command,arg1,arg2...]
|
|
77
|
+
*/
|
|
78
|
+
dispatch(commandWithArgs) {
|
|
79
|
+
if (commandWithArgs.length == 0) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
let command = commandWithArgs.shift();
|
|
83
|
+
let proc = this.spawn(command, commandWithArgs);
|
|
84
|
+
proc.on('error', (err) => {
|
|
85
|
+
console.error(err);
|
|
86
|
+
});
|
|
87
|
+
proc.stdout.on('data', (data) => {
|
|
88
|
+
process.stdout.write(data.toString());
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* isArray
|
|
94
|
+
* @param {object} obj [command,arg1,arg2...]
|
|
95
|
+
* @return {boolean}
|
|
96
|
+
*/
|
|
97
|
+
isArray(obj) {
|
|
98
|
+
return Object.prototype.toString.call(obj) === '[object Array]';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* run
|
|
103
|
+
* @param {string} file
|
|
104
|
+
* @param {Array} whitelist ['command1','command2'...]
|
|
105
|
+
*/
|
|
106
|
+
run(file, whitelist) {
|
|
107
|
+
if ( typeof file !== 'undefined') {
|
|
108
|
+
this.file = file;
|
|
109
|
+
}
|
|
110
|
+
if ( typeof whitelist !== 'undefined') {
|
|
111
|
+
this.whitelist = whitelist;
|
|
112
|
+
}
|
|
113
|
+
if ( typeof this.spawn === 'undefined') {
|
|
114
|
+
this.spawn = spawn;
|
|
115
|
+
}
|
|
116
|
+
if ( typeof this.tail === 'undefined') {
|
|
117
|
+
this.tail = new Tail(this.file,
|
|
118
|
+
{alwaysStat: true, ignoreInitial: true, persistent: true});
|
|
119
|
+
}
|
|
120
|
+
this.tail.on('line', (line) => {
|
|
121
|
+
this.dispatch(
|
|
122
|
+
this.filterByWhitelist(
|
|
123
|
+
this.commandWithArgs(
|
|
124
|
+
this.path(line)),
|
|
125
|
+
this.whitelist));
|
|
126
|
+
});
|
|
127
|
+
this.tail.on('close', () => {
|
|
128
|
+
console.log('watching stopped');
|
|
129
|
+
});
|
|
130
|
+
this.tail.watch();
|
|
131
|
+
}
|
|
132
|
+
}
|
package/check-version.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
var _semver = require('semver');
|
|
5
|
-
|
|
6
|
-
var _semver2 = _interopRequireDefault(_semver);
|
|
7
|
-
|
|
8
|
-
var _package = require('./package');
|
|
9
|
-
|
|
10
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
-
|
|
12
|
-
var version = _package.engines.node;
|
|
13
|
-
if (!_semver2.default.satisfies(process.version, version)) {
|
|
14
|
-
var warn = 'Required node version ' + version + ' ';
|
|
15
|
-
warn += 'not satisfied with current version ' + process.version + '.';
|
|
16
|
-
console.log(warn);
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
|
package/lib/altd.js
DELETED
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
|
|
7
|
-
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
8
|
-
|
|
9
|
-
var _child_process = require('child_process');
|
|
10
|
-
|
|
11
|
-
var _nodejsTail = require('nodejs-tail');
|
|
12
|
-
|
|
13
|
-
var _nodejsTail2 = _interopRequireDefault(_nodejsTail);
|
|
14
|
-
|
|
15
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
16
|
-
|
|
17
|
-
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
** main class of AccessLogTailDispatcher
|
|
21
|
-
*/
|
|
22
|
-
var AccessLogTailDispatcher = function () {
|
|
23
|
-
/**
|
|
24
|
-
* @constructor
|
|
25
|
-
* @param {string} file access_log
|
|
26
|
-
* @param {Array} whitelist ['command1','command2'..]
|
|
27
|
-
*/
|
|
28
|
-
function AccessLogTailDispatcher(file, whitelist) {
|
|
29
|
-
_classCallCheck(this, AccessLogTailDispatcher);
|
|
30
|
-
|
|
31
|
-
this.file = file;
|
|
32
|
-
this.whitelist = whitelist;
|
|
33
|
-
this.spawn = undefined;
|
|
34
|
-
this.tail = undefined;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Get the path from 'GET /path/to/dir HTTP'
|
|
38
|
-
* @param {string} line access_log
|
|
39
|
-
* @return {string} /path/to/dir
|
|
40
|
-
*/
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
_createClass(AccessLogTailDispatcher, [{
|
|
44
|
-
key: 'path',
|
|
45
|
-
value: function path(line) {
|
|
46
|
-
if (!(typeof line === 'string')) {
|
|
47
|
-
return '';
|
|
48
|
-
}
|
|
49
|
-
var match = line.match(/GET\s((\/[a-z0-9-._~%!$&'()*+,;=:@?]+)+\/?)\sHTTP/i);
|
|
50
|
-
if (null !== match && match.length > 2) {
|
|
51
|
-
return match[1];
|
|
52
|
-
}
|
|
53
|
-
return '';
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Extract command and args
|
|
58
|
-
* @param {string} path
|
|
59
|
-
* @return {Array} [command,arg1,arg2...]
|
|
60
|
-
*/
|
|
61
|
-
|
|
62
|
-
}, {
|
|
63
|
-
key: 'commandWithArgs',
|
|
64
|
-
value: function commandWithArgs(path) {
|
|
65
|
-
if (!(typeof path === 'string')) {
|
|
66
|
-
return [];
|
|
67
|
-
}
|
|
68
|
-
var commands = path.split(/\//).map(function (element, index, array) {
|
|
69
|
-
return decodeURIComponent(element);
|
|
70
|
-
});
|
|
71
|
-
commands.shift();
|
|
72
|
-
return commands;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Filter by whitelist
|
|
77
|
-
* @param {Array} commandWithArgs [command,arg1,arg2...]
|
|
78
|
-
* @param {Array} whitelist ['command1','command2'...]
|
|
79
|
-
* @return {Array} filtered commandWithArgs
|
|
80
|
-
*/
|
|
81
|
-
|
|
82
|
-
}, {
|
|
83
|
-
key: 'filterByWhitelist',
|
|
84
|
-
value: function filterByWhitelist(commandWithArgs, whitelist) {
|
|
85
|
-
if (!this.isArray(commandWithArgs) || !this.isArray(whitelist) || commandWithArgs.length == 0 || whitelist.indexOf(commandWithArgs[0]) == -1) {
|
|
86
|
-
return [];
|
|
87
|
-
}
|
|
88
|
-
return commandWithArgs;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Dispatch
|
|
93
|
-
* @param {Array} commandWithArgs [command,arg1,arg2...]
|
|
94
|
-
*/
|
|
95
|
-
|
|
96
|
-
}, {
|
|
97
|
-
key: 'dispatch',
|
|
98
|
-
value: function dispatch(commandWithArgs) {
|
|
99
|
-
if (commandWithArgs.length == 0) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
var command = commandWithArgs.shift();
|
|
103
|
-
var proc = this.spawn(command, commandWithArgs);
|
|
104
|
-
proc.on('error', function (err) {
|
|
105
|
-
console.error(err);
|
|
106
|
-
});
|
|
107
|
-
proc.stdout.on('data', function (data) {
|
|
108
|
-
process.stdout.write(data.toString());
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* isArray
|
|
114
|
-
* @param {object} obj [command,arg1,arg2...]
|
|
115
|
-
* @return {boolean}
|
|
116
|
-
*/
|
|
117
|
-
|
|
118
|
-
}, {
|
|
119
|
-
key: 'isArray',
|
|
120
|
-
value: function isArray(obj) {
|
|
121
|
-
return Object.prototype.toString.call(obj) === '[object Array]';
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* run
|
|
126
|
-
* @param {string} file
|
|
127
|
-
* @param {Array} whitelist ['command1','command2'...]
|
|
128
|
-
*/
|
|
129
|
-
|
|
130
|
-
}, {
|
|
131
|
-
key: 'run',
|
|
132
|
-
value: function run(file, whitelist) {
|
|
133
|
-
var _this = this;
|
|
134
|
-
|
|
135
|
-
if (typeof this.spawn === 'undefined') {
|
|
136
|
-
this.spawn = _child_process.spawn;
|
|
137
|
-
}
|
|
138
|
-
if (typeof this.tail === 'undefined') {
|
|
139
|
-
this.tail = new _nodejsTail2.default(this.file, { alwaysStat: true, ignoreInitial: true, persistent: true });
|
|
140
|
-
}
|
|
141
|
-
this.tail.on('line', function (line) {
|
|
142
|
-
_this.dispatch(_this.filterByWhitelist(_this.commandWithArgs(_this.path(line)), _this.whitelist));
|
|
143
|
-
});
|
|
144
|
-
this.tail.on('close', function () {
|
|
145
|
-
console.log('watching stopped');
|
|
146
|
-
});
|
|
147
|
-
this.tail.watch();
|
|
148
|
-
}
|
|
149
|
-
}]);
|
|
150
|
-
|
|
151
|
-
return AccessLogTailDispatcher;
|
|
152
|
-
}();
|
|
153
|
-
|
|
154
|
-
exports.default = AccessLogTailDispatcher;
|
|
155
|
-
module.exports = exports['default'];
|