forked from snxraven/autoinstallers
first commit
This commit is contained in:
229
install/secu/apache2.conf
Normal file
229
install/secu/apache2.conf
Normal file
@ -0,0 +1,229 @@
|
||||
# This is the main Apache server configuration file. It contains the
|
||||
# configuration directives that give the server its instructions.
|
||||
# See http://httpd.apache.org/docs/2.4/ for detailed information about
|
||||
# the directives and /usr/share/doc/apache2/README.Debian about Debian specific
|
||||
# hints.
|
||||
#
|
||||
#
|
||||
# Summary of how the Apache 2 configuration works in Debian:
|
||||
# The Apache 2 web server configuration in Debian is quite different to
|
||||
# upstream's suggested way to configure the web server. This is because Debian's
|
||||
# default Apache2 installation attempts to make adding and removing modules,
|
||||
# virtual hosts, and extra configuration directives as flexible as possible, in
|
||||
# order to make automating the changes and administering the server as easy as
|
||||
# possible.
|
||||
|
||||
# It is split into several files forming the configuration hierarchy outlined
|
||||
# below, all located in the /etc/apache2/ directory:
|
||||
#
|
||||
# /etc/apache2/
|
||||
# |-- apache2.conf
|
||||
# | `-- ports.conf
|
||||
# |-- mods-enabled
|
||||
# | |-- *.load
|
||||
# | `-- *.conf
|
||||
# |-- conf-enabled
|
||||
# | `-- *.conf
|
||||
# `-- sites-enabled
|
||||
# `-- *.conf
|
||||
#
|
||||
#
|
||||
# * apache2.conf is the main configuration file (this file). It puts the pieces
|
||||
# together by including all remaining configuration files when starting up the
|
||||
# web server.
|
||||
#
|
||||
# * ports.conf is always included from the main configuration file. It is
|
||||
# supposed to determine listening ports for incoming connections which can be
|
||||
# customized anytime.
|
||||
#
|
||||
# * Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/
|
||||
# directories contain particular configuration snippets which manage modules,
|
||||
# global configuration fragments, or virtual host configurations,
|
||||
# respectively.
|
||||
#
|
||||
# They are activated by symlinking available configuration files from their
|
||||
# respective *-available/ counterparts. These should be managed by using our
|
||||
# helpers a2enmod/a2dismod, a2ensite/a2dissite and a2enconf/a2disconf. See
|
||||
# their respective man pages for detailed information.
|
||||
#
|
||||
# * The binary is called apache2. Due to the use of environment variables, in
|
||||
# the default configuration, apache2 needs to be started/stopped with
|
||||
# /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not
|
||||
# work with the default configuration.
|
||||
|
||||
|
||||
# Global configuration
|
||||
#
|
||||
|
||||
#
|
||||
# ServerRoot: The top of the directory tree under which the server's
|
||||
# configuration, error, and log files are kept.
|
||||
#
|
||||
# NOTE! If you intend to place this on an NFS (or otherwise network)
|
||||
# mounted filesystem then please read the Mutex documentation (available
|
||||
# at <URL:http://httpd.apache.org/docs/2.4/mod/core.html#mutex>);
|
||||
# you will save yourself a lot of trouble.
|
||||
#
|
||||
# Do NOT add a slash at the end of the directory path.
|
||||
#
|
||||
#ServerRoot "/etc/apache2"
|
||||
|
||||
#
|
||||
# The accept serialization lock file MUST BE STORED ON A LOCAL DISK.
|
||||
#
|
||||
#Mutex file:${APACHE_LOCK_DIR} default
|
||||
|
||||
#
|
||||
# The directory where shm and other runtime files will be stored.
|
||||
#
|
||||
|
||||
DefaultRuntimeDir ${APACHE_RUN_DIR}
|
||||
|
||||
#
|
||||
# PidFile: The file in which the server should record its process
|
||||
# identification number when it starts.
|
||||
# This needs to be set in /etc/apache2/envvars
|
||||
#
|
||||
PidFile ${APACHE_PID_FILE}
|
||||
|
||||
#
|
||||
# Timeout: The number of seconds before receives and sends time out.
|
||||
#
|
||||
Timeout 300
|
||||
|
||||
#
|
||||
# KeepAlive: Whether or not to allow persistent connections (more than
|
||||
# one request per connection). Set to "Off" to deactivate.
|
||||
#
|
||||
KeepAlive On
|
||||
|
||||
#
|
||||
# MaxKeepAliveRequests: The maximum number of requests to allow
|
||||
# during a persistent connection. Set to 0 to allow an unlimited amount.
|
||||
# We recommend you leave this number high, for maximum performance.
|
||||
#
|
||||
MaxKeepAliveRequests 100
|
||||
|
||||
#
|
||||
# KeepAliveTimeout: Number of seconds to wait for the next request from the
|
||||
# same client on the same connection.
|
||||
#
|
||||
KeepAliveTimeout 5
|
||||
|
||||
|
||||
# These need to be set in /etc/apache2/envvars
|
||||
User ${APACHE_RUN_USER}
|
||||
Group ${APACHE_RUN_GROUP}
|
||||
|
||||
#
|
||||
# HostnameLookups: Log the names of clients or just their IP addresses
|
||||
# e.g., www.apache.org (on) or 204.62.129.132 (off).
|
||||
# The default is off because it'd be overall better for the net if people
|
||||
# had to knowingly turn this feature on, since enabling it means that
|
||||
# each client request will result in AT LEAST one lookup request to the
|
||||
# nameserver.
|
||||
#
|
||||
HostnameLookups Off
|
||||
|
||||
# ErrorLog: The location of the error log file.
|
||||
# If you do not specify an ErrorLog directive within a <VirtualHost>
|
||||
# container, error messages relating to that virtual host will be
|
||||
# logged here. If you *do* define an error logfile for a <VirtualHost>
|
||||
# container, that host's errors will be logged there and not here.
|
||||
#
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
|
||||
#
|
||||
# LogLevel: Control the severity of messages logged to the error_log.
|
||||
# Available values: trace8, ..., trace1, debug, info, notice, warn,
|
||||
# error, crit, alert, emerg.
|
||||
# It is also possible to configure the log level for particular modules, e.g.
|
||||
# "LogLevel info ssl:warn"
|
||||
#
|
||||
LogLevel warn
|
||||
|
||||
# Include module configuration:
|
||||
IncludeOptional mods-enabled/*.load
|
||||
IncludeOptional mods-enabled/*.conf
|
||||
|
||||
# Include list of ports to listen on
|
||||
Include ports.conf
|
||||
|
||||
|
||||
# Sets the default security model of the Apache2 HTTPD server. It does
|
||||
# not allow access to the root filesystem outside of /usr/share and /var/www.
|
||||
# The former is used by web applications packaged in Debian,
|
||||
# the latter may be used for local directories served by the web server. If
|
||||
# your system is serving content from a sub-directory in /srv you must allow
|
||||
# access here, or in any related virtual host.
|
||||
<Directory />
|
||||
Options FollowSymLinks
|
||||
AllowOverride All
|
||||
Require all denied
|
||||
</Directory>
|
||||
|
||||
<Directory /usr/share>
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
<Directory /var/www/>
|
||||
Options Indexes FollowSymLinks
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
#<Directory /srv/>
|
||||
# Options Indexes FollowSymLinks
|
||||
# AllowOverride All
|
||||
# Require all granted
|
||||
#</Directory>
|
||||
|
||||
|
||||
|
||||
|
||||
# AccessFileName: The name of the file to look for in each directory
|
||||
# for additional configuration directives. See also the AllowOverride
|
||||
# directive.
|
||||
#
|
||||
AccessFileName .htaccess
|
||||
|
||||
#
|
||||
# The following lines prevent .htaccess and .htpasswd files from being
|
||||
# viewed by Web clients.
|
||||
#
|
||||
<FilesMatch "^\.ht">
|
||||
Require all denied
|
||||
</FilesMatch>
|
||||
|
||||
|
||||
#
|
||||
# The following directives define some format nicknames for use with
|
||||
# a CustomLog directive.
|
||||
#
|
||||
# These deviate from the Common Log Format definitions in that they use %O
|
||||
# (the actual bytes sent including headers) instead of %b (the size of the
|
||||
# requested file), because the latter makes it impossible to detect partial
|
||||
# requests.
|
||||
#
|
||||
# Note that the use of %{X-Forwarded-For}i instead of %h is not recommended.
|
||||
# Use mod_remoteip instead.
|
||||
#
|
||||
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
|
||||
#LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
|
||||
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %O" common
|
||||
LogFormat "%{Referer}i -> %U" referer
|
||||
LogFormat "%{User-agent}i" agent
|
||||
|
||||
# Include of directories ignores editors' and dpkg's backup files,
|
||||
# see README.Debian for details.
|
||||
|
||||
# Include generic snippets of statements
|
||||
IncludeOptional conf-enabled/*.conf
|
||||
|
||||
# Include the virtual host configurations:
|
||||
IncludeOptional sites-enabled/*.conf
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
serverName secuNotifyHTTP
|
160
install/secu/build
Normal file
160
install/secu/build
Normal file
@ -0,0 +1,160 @@
|
||||
// Lets use some libs to help us out.
|
||||
const fs = require('fs')
|
||||
Tail = require('tail').Tail;
|
||||
|
||||
sshTail = new Tail("/var/log/auth.log");
|
||||
wpTail = new Tail("/var/log/apache2/access.log");
|
||||
const cmd = require('cmd-promise')
|
||||
|
||||
// Setting up our main storage logic - for now this program does not use a database system.
|
||||
let serverStatusCount = 0;
|
||||
let attackData = []
|
||||
let blockedIPs = []
|
||||
let ipToBlock
|
||||
|
||||
console.log("Welcome to the security notification system secuNotify by Discord-Linux!");
|
||||
console.log("We currently will notify you about login events, such as failed logins and successful logins.");
|
||||
|
||||
// Setting up our notification function - This allows us to direct message our user.
|
||||
function notify(message) {
|
||||
const { spawn } = require('child_process');
|
||||
const notif = spawn('notif', [message]);
|
||||
|
||||
notif.stdout.on('data', (data) => {
|
||||
console.log(`stdout: ${data}`);
|
||||
});
|
||||
|
||||
notif.stderr.on('data', (data) => {
|
||||
console.error(`stderr: ${data}`);
|
||||
});
|
||||
|
||||
notif.on('close', (code) => {
|
||||
console.log(`Code: ${code} - Continuing to monitor`);
|
||||
});
|
||||
}
|
||||
|
||||
function listenAuthLog(logLocation) {
|
||||
sshTail.on("line", function (info) {
|
||||
let infoString = info.toString();
|
||||
|
||||
if (infoString.includes("Failed password for root")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info);
|
||||
}
|
||||
|
||||
if (infoString.includes("Accepted password for")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info + "This does mean that someone (Maybe you) has logged in successfully!");
|
||||
}
|
||||
if (infoString.includes("Invalid user")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info + "This means that someone (Maybe you) has tried to login with an invalid username!");
|
||||
}
|
||||
})
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
function listenWPLog(logLocation) {
|
||||
// Check to see if we are a wordpress user, if so, activate the wordpress notification service
|
||||
const wpLog = '/var/www/html/wp-config.php'
|
||||
if (fs.existsSync(wpLog)) console.log("We are a wordpress user, activating wordpress notification service");
|
||||
try {
|
||||
if (fs.existsSync(wpLog)) {
|
||||
// Tail Logs section, if we have a lot, it will have a listeniner below.
|
||||
wpTail.on("line", function (info) {
|
||||
|
||||
// Convert Data to String
|
||||
let requestInfo = info.toString()
|
||||
// FIND IP Address from this request
|
||||
var ipRegEx = /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/; // RegEx IPAddress Format
|
||||
var ipRegExMatched = requestInfo.match(ipRegEx); // Set up our match
|
||||
let remoteIP = ipRegExMatched[0] // Set our var
|
||||
|
||||
// // Grab the whitelist
|
||||
// let whitelistData = process.env.WHITELIST
|
||||
// let whitelist = whitelistData.split(",")
|
||||
|
||||
// // If an IP is found to be in the whitelist, return as to do nothing.
|
||||
// for (const [key, value] of Object.entries(whitelist)) {
|
||||
// if (value === remoteIP) return
|
||||
// }
|
||||
|
||||
// Filtering out any server-status requests - These are annoying.
|
||||
if (requestInfo.includes("server-status")) {
|
||||
// Add to the server status count so we may keep track of these requests.
|
||||
serverStatusCount++
|
||||
// Lets return the data as no not proceed with any further code, as it is not needed.
|
||||
// We return to stdout here to update the cli without adding a new line line a clock
|
||||
return process.stdout.write("Server Status Count: " + serverStatusCount + "\r");
|
||||
}
|
||||
|
||||
// If request contans wp-login lets process its request
|
||||
if (requestInfo.includes("wp-login.php")) {
|
||||
// Lets start the process of logging attack attempts to determine request intent.
|
||||
// Over the threshhold here will automatically CSF D the IP Address.
|
||||
// In this simple version, we will just log each IP Address as they come in within an array
|
||||
// We will then roll and count this array after each detection to determine the IPs intent.
|
||||
console.log("---------\nWP LOGIN REQUEST DETECTED!\n---------")
|
||||
console.log(info + "\n----------");
|
||||
attackData.push(remoteIP)
|
||||
|
||||
// Lets count the attack data per IP Address to ensure its logged properly.
|
||||
var counts = {};
|
||||
|
||||
// For each IP Address recorded into the main attackData array, count them and see outmany bad requests they have made.
|
||||
attackData.forEach(function (x) {
|
||||
// Add a point for each entry
|
||||
counts[x] = (counts[x] || 0) + 1;
|
||||
//
|
||||
for ([key, value] of Object.entries(counts)) {
|
||||
// If the count has hit the blockON Count we start the blocking process
|
||||
|
||||
if (counts[x] == 5) {
|
||||
// Preserve the key for later blocklist addition
|
||||
ipToBlock = key
|
||||
|
||||
// Check the already blocked IPs - If the remoteIP is in the list do nothing
|
||||
if (blockedIPs.includes(key)) {
|
||||
return
|
||||
|
||||
} else {
|
||||
// The remoteIP is not listed, lets add it.
|
||||
blockedIPs.push(ipToBlock)
|
||||
// Let the log know we are blocking the IP
|
||||
console.log("Starting to block bad IP")
|
||||
// Run the block, wait for the promise - Requests are still going on
|
||||
cmd(`/var/tools/firewallctl 123.123.123.123 ` + key + " WP-Login Brute Force Blocked Via secuNotify").then(out => {
|
||||
notify("secuNotify Service Alert: \n " + key + " has been blocked for 5 bad wordpress login attempts!");
|
||||
|
||||
// The block has finished - remoteIP no longer has access
|
||||
}).catch(err => {
|
||||
// IF we see an error, give its output
|
||||
console.log('CSF Error: ', err)
|
||||
}).then(out2 => {
|
||||
// Set IPBLOCK to null for a reset and start scanning for new attacks
|
||||
ipToBlock = null;
|
||||
console.log("Attack Stopped, Looking for new attacks....")
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Live view of the counts
|
||||
console.log(counts)
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
listenAuthLog("/var/log/auth.log")
|
||||
listenWPLog("/var/log/apache2/access.log")
|
BIN
install/secu/csf
Executable file
BIN
install/secu/csf
Executable file
Binary file not shown.
BIN
install/secu/make/new
Executable file
BIN
install/secu/make/new
Executable file
Binary file not shown.
180
install/secu/make/new.js
Normal file
180
install/secu/make/new.js
Normal file
@ -0,0 +1,180 @@
|
||||
// Lets use some libs to help us out.
|
||||
const fs = require('fs')
|
||||
Tail = require('tail').Tail;
|
||||
|
||||
sshTail = new Tail("/var/log/auth.log");
|
||||
const cmd = require('cmd-promise')
|
||||
|
||||
// Setting up our main storage logic - for now this program does not use a database system.
|
||||
let serverStatusCount = 0;
|
||||
let attackData = []
|
||||
let blockedIPs = []
|
||||
let ipToBlock
|
||||
|
||||
console.log("Welcome to the security notification system secuNotify by Discord-Linux!");
|
||||
console.log("We currently will notify you about login events, such as failed logins and successful logins.");
|
||||
|
||||
// Setting up our notification function - This allows us to direct message our user.
|
||||
function notify(message) {
|
||||
const { spawn } = require('child_process');
|
||||
const notif = spawn('notif', [message]);
|
||||
|
||||
notif.stdout.on('data', (data) => {
|
||||
console.log(`stdout: ${data}`);
|
||||
});
|
||||
|
||||
notif.stderr.on('data', (data) => {
|
||||
console.error(`stderr: ${data}`);
|
||||
});
|
||||
|
||||
notif.on('close', (code) => {
|
||||
console.log(`Code: ${code} - Continuing to monitor`);
|
||||
});
|
||||
}
|
||||
|
||||
function listenAuthLog(logLocation) {
|
||||
sshTail.on("line", function (info) {
|
||||
let infoString = info.toString();
|
||||
|
||||
if (infoString.includes("Failed password for root")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info);
|
||||
}
|
||||
|
||||
if (infoString.includes("Accepted password for")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info + "This does mean that someone (Maybe you) has logged in successfully!");
|
||||
}
|
||||
if (infoString.includes("Invalid user")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info + "This means that someone (Maybe you) has tried to login with an invalid username!");
|
||||
}
|
||||
})
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
function listenWPLog(logLocation) {
|
||||
// Check to see if we are a wordpress user, if so, activate the wordpress notification service
|
||||
try {
|
||||
if (fs.existsSync("/var/www/html/wp-config.php")) {
|
||||
console.log("We are a wordpress user, activating wordpress notification service");
|
||||
|
||||
// Tail Logs section, if we have a lot, it will have a listeniner below.
|
||||
wpTail.on("line", function (info) {
|
||||
|
||||
// Convert Data to String
|
||||
let requestInfo = info.toString()
|
||||
// FIND IP Address from this request
|
||||
var ipRegEx = /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/; // RegEx IPAddress Format
|
||||
var ipRegExMatched = requestInfo.match(ipRegEx); // Set up our match
|
||||
let remoteIP = ipRegExMatched[0] // Set our var
|
||||
|
||||
// // Grab the whitelist
|
||||
// let whitelistData = process.env.WHITELIST
|
||||
// let whitelist = whitelistData.split(",")
|
||||
|
||||
// // If an IP is found to be in the whitelist, return as to do nothing.
|
||||
// for (const [key, value] of Object.entries(whitelist)) {
|
||||
// if (value === remoteIP) return
|
||||
// }
|
||||
|
||||
// Filtering out any server-status requests - These are annoying.
|
||||
if (requestInfo.includes("server-status")) {
|
||||
// Add to the server status count so we may keep track of these requests.
|
||||
serverStatusCount++
|
||||
// Lets return the data as no not proceed with any further code, as it is not needed.
|
||||
// We return to stdout here to update the cli without adding a new line line a clock
|
||||
return process.stdout.write("Server Status Count: " + serverStatusCount + "\r");
|
||||
}
|
||||
|
||||
// If request contans wp-login lets process its request
|
||||
if (requestInfo.includes("wp-login.php") && requestInfo.includes("POST")) {
|
||||
// Lets start the process of logging attack attempts to determine request intent.
|
||||
// Over the threshhold here will automatically CSF D the IP Address.
|
||||
// In this simple version, we will just log each IP Address as they come in within an array
|
||||
// We will then roll and count this array after each detection to determine the IPs intent.
|
||||
console.log("---------\nWP LOGIN REQUEST DETECTED!\n---------")
|
||||
console.log(info + "\n----------");
|
||||
attackData.push(remoteIP)
|
||||
|
||||
// Lets count the attack data per IP Address to ensure its logged properly.
|
||||
var counts = {};
|
||||
|
||||
// For each IP Address recorded into the main attackData array, count them and see outmany bad requests they have made.
|
||||
attackData.forEach(function (x) {
|
||||
// Add a point for each entry
|
||||
counts[x] = (counts[x] || 0) + 1;
|
||||
//
|
||||
for ([key, value] of Object.entries(counts)) {
|
||||
// If the count has hit the blockON Count we start the blocking process
|
||||
|
||||
if (counts[x] === 5) {
|
||||
console.log("counts: " + counts[x])
|
||||
counts = {}
|
||||
|
||||
|
||||
// Preserve the key for later blocklist addition
|
||||
ipToBlock = key
|
||||
|
||||
// Check the already blocked IPs - If the remoteIP is in the list do nothing
|
||||
if (blockedIPs.includes(key)) {
|
||||
return
|
||||
|
||||
} else {
|
||||
// The remoteIP is not listed, lets add it.
|
||||
blockedIPs.push(ipToBlock)
|
||||
// Let the log know we are blocking the IP
|
||||
console.log("Starting to block bad IP")
|
||||
// Run the block, wait for the promise - Requests are still going on
|
||||
cmd(`/var/tools/firewallctl ` + key + " WP-Login Brute Force Blocked Via secuNotify").then(out => {
|
||||
notify("secuNotify Service Alert:\n " + key + " has been blocked for 5 bad wordpress login attempts!");
|
||||
|
||||
// The block has finished - remoteIP no longer has access
|
||||
}).catch(err => {
|
||||
// IF we see an error, give its output
|
||||
console.log('CSF Error: ', err)
|
||||
}).then(out2 => {
|
||||
// Set IPBLOCK to null for a reset and start scanning for new attacks
|
||||
ipToBlock = null;
|
||||
console.log("Attack Stopped, Looking for new attacks....")
|
||||
// Live view of the counts
|
||||
})
|
||||
|
||||
|
||||
if (blockedIPs.length == 0) {
|
||||
console.log("No IPs have been blocked yet.")
|
||||
} else {
|
||||
console.log("Blocked IP List (Since Service start): " + blockedIPs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
listenAuthLog("/var/log/auth.log")
|
||||
|
||||
fs.exists("/var/log/apache2/access.log", function (isExist) {
|
||||
if (isExist) {
|
||||
wpTail = new Tail("/var/log/apache2/access.log");
|
||||
listenWPLog("/var/log/apache2/access.log")
|
||||
} else {
|
||||
console.log("ApacheHTTP Server is not installed, not enabling WP protection.");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
20
install/secu/make/node_modules/.package-lock.json
generated
vendored
Normal file
20
install/secu/make/node_modules/.package-lock.json
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "make",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"node_modules/cmd-promise": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/cmd-promise/-/cmd-promise-1.2.0.tgz",
|
||||
"integrity": "sha1-PPUTIiAZi1HBbakt44ag03Q9u1w="
|
||||
},
|
||||
"node_modules/tail": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/tail/-/tail-2.2.4.tgz",
|
||||
"integrity": "sha512-PX8klSxW1u3SdgDrDeewh5GNE+hkJ4h02JvHfV6YrHqWOVJ88nUdSQqtsUf/gWhgZlPAws3fiZ+F1f8euspcuQ==",
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
6
install/secu/make/node_modules/cmd-promise/.npmignore
generated
vendored
Normal file
6
install/secu/make/node_modules/cmd-promise/.npmignore
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
node_modules/
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
Desktop.ini
|
||||
$RECYCLE.BIN/
|
164
install/secu/make/node_modules/cmd-promise/README.md
generated
vendored
Normal file
164
install/secu/make/node_modules/cmd-promise/README.md
generated
vendored
Normal file
@ -0,0 +1,164 @@
|
||||
|
||||
# CMD Promise
|
||||
|
||||
Node command line interface with a simple Promise based API.
|
||||
|
||||
[](http://standardjs.com/)
|
||||
[](https://www.npmjs.com/package/cmd-promise)
|
||||
[](https://www.npmjs.com/package/cmd-promise)
|
||||
|
||||
Inspired by [node-cmd](https://github.com/RIAEvangelist/node-cmd).
|
||||
|
||||
## Features
|
||||
|
||||
- Simple Promise based API.
|
||||
- Single or multiple commands in one call.
|
||||
- Passes the [`exec()`](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) node options through.
|
||||
- Returns an `object` containing both `stdout` and `stderr`.
|
||||
- Optionally return the [child process](https://nodejs.org/api/child_process.html#child_process_class_childprocess) instead of the output.
|
||||
- Zero dependencies.
|
||||
|
||||
## Requirments
|
||||
|
||||
Uses native node promises (including `Promise.all` with generic iterables) so requires at least node version 4.0.0. See [http://node.green/](http://node.green/#ES2015-built-ins-Promise).
|
||||
|
||||
## Install
|
||||
|
||||
`npm install cmd-promise`
|
||||
|
||||
## Examples
|
||||
|
||||
### Single command
|
||||
|
||||
```js
|
||||
const cmd = require('cmd-promise')
|
||||
|
||||
cmd(`node -v`).then(out => {
|
||||
console.log('out =', out)
|
||||
}).catch(err => {
|
||||
console.log('err =', err)
|
||||
})
|
||||
|
||||
// out = { stdout: 'v4.2.2\r\n', stderr: '' }
|
||||
```
|
||||
|
||||
### Multiple commands
|
||||
|
||||
```js
|
||||
const cmd = require('cmd-promise')
|
||||
|
||||
const commands = `
|
||||
node -v
|
||||
npm -v
|
||||
`
|
||||
|
||||
cmd(commands).then(out => {
|
||||
console.log('out =', out)
|
||||
}).catch(err => {
|
||||
console.log('err =', err)
|
||||
})
|
||||
|
||||
// out = [ { stdout: 'v4.2.2\r\n', stderr: '' }, { stdout: '4.4.1\n', stderr: '' } ]
|
||||
// out[0].stdout = v4.2.2
|
||||
```
|
||||
|
||||
### More involved example
|
||||
|
||||
```js
|
||||
const semver = require('semver') // https://github.com/npm/node-semver
|
||||
const cmd = require('cmd-promise')
|
||||
|
||||
const commands = `
|
||||
npm view npm version
|
||||
npm -v
|
||||
`
|
||||
|
||||
cmd(commands).then(out => {
|
||||
return {
|
||||
npm: out[0].stdout.replace(/\n/g, ''),
|
||||
me: out[1].stdout.replace(/\n/g, '')
|
||||
}
|
||||
}).then(versions => {
|
||||
if (semver.lt(versions.me, versions.npm)) {
|
||||
console.log(`My npm version is out of date (npm install npm@latest -g).`)
|
||||
} else {
|
||||
console.log(`My npm version is up to date! :-)`)
|
||||
}
|
||||
}).catch(err => {
|
||||
console.log('err =', err)
|
||||
})
|
||||
```
|
||||
|
||||
### Return the child process instead
|
||||
|
||||
```js
|
||||
const cmd = require('../cmd-promise')
|
||||
|
||||
const options = { returnProcess: true }
|
||||
|
||||
cmd(`node -v`, options).then(childProcess => {
|
||||
console.log('pid =', childProcess.pid)
|
||||
childProcess.stdout.on('data', stdout => {
|
||||
console.log('stdout =', stdout)
|
||||
})
|
||||
childProcess.stderr.on('data', stderr => {
|
||||
console.log('stderr =', stderr)
|
||||
})
|
||||
}).catch(err => {
|
||||
console.log('err =', err)
|
||||
})
|
||||
```
|
||||
|
||||
### Pass exec() options
|
||||
|
||||
Pass [`child_process.exec()`](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) options as defined in the node docs.
|
||||
|
||||
```js
|
||||
const cmd = require('../cmd-promise')
|
||||
|
||||
const execOptions = { timeout: 1000 }
|
||||
|
||||
cmd(`node -v`, {}, execOptions).then(out => {
|
||||
console.log('out =', out)
|
||||
}).catch(err => {
|
||||
console.log('err =', err)
|
||||
})
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
`cmd(commands [,options] [,execOptions]) -> Promise`
|
||||
|
||||
- **commands** (string) Single or multiple line string of commands to execute.
|
||||
- **options** (object)
|
||||
- `returnProcess` (boolean) Return the child process instead of waiting on and returning the outcome. Default is `false`.
|
||||
- **execOptions** (object) Options as passed to the [`exec()`](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) method of the [child_process](https://nodejs.org/api/child_process.html) node module.
|
||||
|
||||
Returns a Promise.
|
||||
|
||||
For **single** commands the promises return value is an `object` containing `stdout` and `stderr` properties. If `options.returnProcess` is set to `true` the return value is the [child process](https://nodejs.org/api/child_process.html#child_process_class_childprocess) instead.
|
||||
|
||||
```js
|
||||
const cmd = require('cmd-promise')
|
||||
|
||||
cmd(`node -v`).then(out => {
|
||||
console.log('out.stdout =', out.stdout) // v4.2.2
|
||||
console.log('out.stderr =', out.stderr)
|
||||
})
|
||||
```
|
||||
|
||||
For **multiple line** command calls the promises return value is an array of `object`'s containing `stdout` and `stderr` properties. If `options.returnProcess` is set to `true` the return value is an array of [child processes](https://nodejs.org/api/child_process.html#child_process_class_childprocess) instead.
|
||||
|
||||
```js
|
||||
const cmd = require('cmd-promise')
|
||||
|
||||
const commands = `
|
||||
node -v
|
||||
npm -v
|
||||
`
|
||||
|
||||
cmd(commands).then(out => {
|
||||
console.log('out[0] =', out[0]) // result from 'node -v'
|
||||
console.log('out[1] =', out[1]) // result from 'npm -v'
|
||||
})
|
||||
```
|
88
install/secu/make/node_modules/cmd-promise/cmd-promise.js
generated
vendored
Normal file
88
install/secu/make/node_modules/cmd-promise/cmd-promise.js
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
|
||||
const exec = require('child_process').exec
|
||||
|
||||
/**
|
||||
* does the given object have the given property
|
||||
* @param {object} obj object to check.
|
||||
* @param {string} prop property to check for.
|
||||
* @return Boolean
|
||||
*/
|
||||
function hasProp (obj, prop) {
|
||||
return obj.hasOwnProperty(prop)
|
||||
}
|
||||
|
||||
/**
|
||||
* is this a string please sir?
|
||||
* @param {string} str string (or is it?) to check.
|
||||
* @return Boolean
|
||||
*/
|
||||
function isString (str) {
|
||||
return (typeof str === 'string' || str instanceof String)
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper for child_process.exec()
|
||||
* @param {string} command command line command to run.
|
||||
* @param {object} options cmd-promise options.
|
||||
* @param {object} execOptions exec() options object as outlined in the node docs.
|
||||
* @return Promise
|
||||
*/
|
||||
function runCommand (command, options, execOptions) {
|
||||
// defaults
|
||||
if (!options) { options = {} }
|
||||
if (!execOptions) { execOptions = {} }
|
||||
|
||||
// resolve to the child process?
|
||||
const returnProcess = hasProp(options, 'returnProcess') ? options.returnProcess : false
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (returnProcess) {
|
||||
// resolve to the child process, don't wait for the output
|
||||
resolve(exec(command, execOptions))
|
||||
} else {
|
||||
// resolve to the output, using the callback
|
||||
exec(command, execOptions, (error, stdout, stderr) => {
|
||||
if (error) { return reject(error) }
|
||||
resolve({ stdout, stderr })
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* run one or many commands
|
||||
* @param {string} commands command line command(s) string to run.
|
||||
* @param {object} options options object as outlined in the node docs.
|
||||
* @return Promise
|
||||
*/
|
||||
function cmdPromise (commands, options, execOptions) {
|
||||
// make sure the command is a string
|
||||
if (!isString(commands)) {
|
||||
return Promise.reject(new Error('Command not a string.'))
|
||||
}
|
||||
|
||||
// do we have multiple lines?
|
||||
if (commands.indexOf('\n') > -1) {
|
||||
// split by new lines
|
||||
const arrSplit = commands.split(/\n/g)
|
||||
|
||||
// remove empty array elements
|
||||
const arrFiltered = arrSplit.filter(ele => ele.length)
|
||||
|
||||
// trim each array element
|
||||
const arrTrimmed = arrFiltered.map(ele => ele.trim())
|
||||
|
||||
// array of command promises
|
||||
const arrOut = arrTrimmed.map(command => {
|
||||
return runCommand(command, options, execOptions)
|
||||
})
|
||||
|
||||
// multiple lines, return an array of outs
|
||||
return Promise.all(arrOut)
|
||||
} else {
|
||||
// one line, run it
|
||||
return runCommand(commands, options, execOptions)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = cmdPromise
|
21
install/secu/make/node_modules/cmd-promise/package.json
generated
vendored
Normal file
21
install/secu/make/node_modules/cmd-promise/package.json
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "cmd-promise",
|
||||
"version": "1.2.0",
|
||||
"description": "Node command line interface with a simple Promise based API.",
|
||||
"main": "cmd-promise.js",
|
||||
"scripts": {
|
||||
"test": ""
|
||||
},
|
||||
"author": {
|
||||
"name": "Stephen Last",
|
||||
"email": "stephen.last@gmail.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"semver": "^5.3.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/stephen-last/cmd-promise.git"
|
||||
}
|
||||
}
|
25
install/secu/make/node_modules/cmd-promise/test/my-npm-version.js
generated
vendored
Normal file
25
install/secu/make/node_modules/cmd-promise/test/my-npm-version.js
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
const semver = require('semver')
|
||||
const cmd = require('../cmd-promise')
|
||||
|
||||
console.log('cmd-promise: More involved example.')
|
||||
|
||||
const commands = `
|
||||
npm view npm version
|
||||
npm -v
|
||||
`
|
||||
|
||||
cmd(commands).then(out => {
|
||||
return {
|
||||
npm: out[0].stdout.replace(/\n/g, ''),
|
||||
me: out[1].stdout.replace(/\n/g, '')
|
||||
}
|
||||
}).then(versions => {
|
||||
if (semver.lt(versions.me, versions.npm)) {
|
||||
console.log(`My npm version is out of date (npm install npm@latest -g).`)
|
||||
} else {
|
||||
console.log(`My npm version is up to date! :-)`)
|
||||
}
|
||||
}).catch(err => {
|
||||
console.log('err =', err)
|
||||
})
|
18
install/secu/make/node_modules/cmd-promise/test/process.js
generated
vendored
Normal file
18
install/secu/make/node_modules/cmd-promise/test/process.js
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
const cmd = require('../cmd-promise')
|
||||
|
||||
console.log('cmd-promise: Return child process instead of output.')
|
||||
|
||||
const options = { returnProcess: true }
|
||||
|
||||
cmd(`node -v`, options).then(childProcess => {
|
||||
console.log('pid =', childProcess.pid)
|
||||
childProcess.stdout.on('data', stdout => {
|
||||
console.log('stdout =', stdout)
|
||||
})
|
||||
childProcess.stderr.on('data', stderr => {
|
||||
console.log('stderr =', stderr)
|
||||
})
|
||||
}).catch(err => {
|
||||
console.log('err =', err)
|
||||
})
|
17
install/secu/make/node_modules/cmd-promise/test/simple.js
generated
vendored
Normal file
17
install/secu/make/node_modules/cmd-promise/test/simple.js
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
const cmd = require('../cmd-promise')
|
||||
|
||||
console.log('cmd-promise: One or multiple commands.')
|
||||
|
||||
// const single = `node -v`
|
||||
|
||||
const multiple = `
|
||||
node -v
|
||||
npm -v
|
||||
`
|
||||
|
||||
cmd(multiple).then(out => {
|
||||
console.log('out =', out)
|
||||
}).catch(err => {
|
||||
console.log('err =', err)
|
||||
})
|
3
install/secu/make/node_modules/tail/.github/FUNDING.yml
generated
vendored
Normal file
3
install/secu/make/node_modules/tail/.github/FUNDING.yml
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: lucagrulla
|
7
install/secu/make/node_modules/tail/.github/dependabot.yml
generated
vendored
Normal file
7
install/secu/make/node_modules/tail/.github/dependabot.yml
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: npm
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: monthly
|
||||
open-pull-requests-limit: 10
|
67
install/secu/make/node_modules/tail/.github/workflows/codeql-analysis.yml
generated
vendored
Normal file
67
install/secu/make/node_modules/tail/.github/workflows/codeql-analysis.yml
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '16 13 * * 3'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
21
install/secu/make/node_modules/tail/LICENSE
generated
vendored
Normal file
21
install/secu/make/node_modules/tail/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011 2012 2013 Forward
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
122
install/secu/make/node_modules/tail/README.md
generated
vendored
Normal file
122
install/secu/make/node_modules/tail/README.md
generated
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
# Tail
|
||||
|
||||
The **zero** dependency Node.js module for tailing a file
|
||||
|
||||
[](https://nodei.co/npm/tail.png?downloads=true&downloadRank=true)
|
||||
|
||||
[](https://github.com/lucagrulla/node-tail/blob/master/LICENSE)
|
||||
[](https://www.npmjs.com/package/tail)
|
||||

|
||||
|
||||
Made with ❤️ by [Luca Grulla](https://www.lucagrulla.com)
|
||||
|
||||
1. TOC
|
||||
{:toc}
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install tail
|
||||
```
|
||||
|
||||
## Use
|
||||
|
||||
```javascript
|
||||
Tail = require('tail').Tail;
|
||||
|
||||
tail = new Tail("fileToTail");
|
||||
|
||||
tail.on("line", function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
tail.on("error", function(error) {
|
||||
console.log('ERROR: ', error);
|
||||
});
|
||||
```
|
||||
|
||||
If you want to stop tail:
|
||||
|
||||
```javascript
|
||||
tail.unwatch()
|
||||
```
|
||||
|
||||
To start watching again:
|
||||
|
||||
```javascript
|
||||
tail.watch()
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The only mandatory parameter is the path to the file to tail.
|
||||
|
||||
```javascript
|
||||
var fileToTail = "/path/to/fileToTail.txt";
|
||||
new Tail(fileToTail)
|
||||
```
|
||||
|
||||
If the file is **missing or invalid** ```Tail``` constructor will throw an Exception and won't initialize.
|
||||
|
||||
```javascript
|
||||
try {
|
||||
new Tail('missingFile.txt')
|
||||
} catch (ex) {
|
||||
console.log(ex)
|
||||
}
|
||||
```
|
||||
|
||||
Optional parameters can be passed via a hash:
|
||||
|
||||
```javascript
|
||||
var options= {separator: /[\r]{0,1}\n/, fromBeginning: false, fsWatchOptions: {}, follow: true, logger: console}
|
||||
new Tail(fileToTail, options)
|
||||
```
|
||||
|
||||
### Constructor parameters
|
||||
|
||||
* `separator`: the line separator token (default: `/[\r]{0,1}\n/` to handle linux/mac (9+)/windows). Pass `null` for is binary files with no line separator.
|
||||
* `fsWatchOptions`: the full set of options that can be passed to `fs.watch` as per node documentation (default: {}).
|
||||
* `fromBeginning`: tail from the beginning of the file (default: `false`). If `fromBeginning` is true `nLines` will be ignored.
|
||||
* `follow`: simulate `tail -F` option. In the case the file is moved/renamed/logrotated, if set to `true` will start tailing again after a 1 second delay; if set to `false` it will emit an error event (default: `true`).
|
||||
* `logger`: a logger object(default: no logger). The passed logger should follow the folliwing signature:
|
||||
* `info([data][, ...])`
|
||||
* `error([data][, ...])`
|
||||
* `nLines`: tail from the last n lines. (default: `undefined`). Ignored if `fromBeginning` is set to `true`.
|
||||
* `useWatchFile`: if set to `true` will force the use of `fs.watchFile` over delegating to the library the choice between `fs.watch` and `fs.watchFile` (default: `false`).
|
||||
* `encoding`: the file encoding (default:`utf-8`).
|
||||
* `flushAtEOF`: set to `true` to force flush of content when end of file is reached. Useful when there's no separator character at the end of the file (default: `false`).
|
||||
|
||||
## Emitted events
|
||||
|
||||
`Tail` emits two events:
|
||||
|
||||
* line
|
||||
|
||||
```javascript
|
||||
tail.on('line', (data) => {
|
||||
console.log(data)
|
||||
})
|
||||
```
|
||||
|
||||
* error
|
||||
|
||||
```javascript
|
||||
tail.on('error', (err) => {
|
||||
console.log(err)
|
||||
})
|
||||
```
|
||||
The error emitted is either the underline exception or a descriptive string.
|
||||
|
||||
## How to contribute
|
||||
Node Tail code repo is [here](https://github.com/lucagrulla/node-tail/)
|
||||
Tail is written in ES6. Pull Requests are welcome.
|
||||
|
||||
## History
|
||||
|
||||
Tail was born as part of a data firehose. Read more about that project [here](https://www.lucagrulla.com/posts/building-a-firehose-with-nodejs/).
|
||||
Tail originally was written in [CoffeeScript](https://coffeescript.org/). Since December 2020 it's pure ES6.
|
||||
|
||||
## License
|
||||
|
||||
MIT. Please see [License](https://github.com/lucagrulla/node-tail/blob/master/LICENSE) file for more details.
|
233
install/secu/make/node_modules/tail/lib/tail.js
generated
vendored
Normal file
233
install/secu/make/node_modules/tail/lib/tail.js
generated
vendored
Normal file
@ -0,0 +1,233 @@
|
||||
let events = require(`events`)
|
||||
let fs = require('fs')
|
||||
let path = require('path')
|
||||
|
||||
// const environment = process.env['NODE_ENV'] || 'development'
|
||||
|
||||
class devNull {
|
||||
info() { };
|
||||
error() { };
|
||||
};
|
||||
|
||||
class Tail extends events.EventEmitter {
|
||||
|
||||
constructor(filename, options = {}) {
|
||||
super();
|
||||
this.filename = filename;
|
||||
this.absPath = path.dirname(this.filename);
|
||||
this.separator = (options.separator !== undefined) ? options.separator : /[\r]{0,1}\n/;// null is a valid param
|
||||
this.fsWatchOptions = options.fsWatchOptions || {};
|
||||
this.follow = options['follow'] != undefined ? options['follow'] : true;
|
||||
this.logger = options.logger || new devNull();
|
||||
this.useWatchFile = options.useWatchFile || false;
|
||||
this.flushAtEOF = options.flushAtEOF || false;
|
||||
this.encoding = options.encoding || 'utf-8';
|
||||
const fromBeginning = options.fromBeginning || false;
|
||||
this.nLines = options.nLines || undefined;
|
||||
|
||||
this.logger.info(`Tail starting...`)
|
||||
this.logger.info(`filename: ${this.filename}`);
|
||||
this.logger.info(`encoding: ${this.encoding}`);
|
||||
|
||||
try {
|
||||
fs.accessSync(this.filename, fs.constants.F_OK);
|
||||
} catch (err) {
|
||||
if (err.code == 'ENOENT') {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
this.buffer = '';
|
||||
this.internalDispatcher = new events.EventEmitter();
|
||||
this.queue = [];
|
||||
this.isWatching = false;
|
||||
this.pos = 0;
|
||||
|
||||
// this.internalDispatcher.on('next',this.readBlock);
|
||||
this.internalDispatcher.on('next', () => {
|
||||
this.readBlock();
|
||||
});
|
||||
|
||||
this.logger.info(`fromBeginning: ${fromBeginning}`);
|
||||
let startingCursor;
|
||||
if (fromBeginning) {
|
||||
startingCursor = 0;
|
||||
} else if (this.nLines !== undefined) {
|
||||
const data = fs.readFileSync(this.filename, {
|
||||
flag: 'r',
|
||||
encoding: this.encoding
|
||||
});
|
||||
const tokens = data.split(this.separator);
|
||||
const dropLastToken = (tokens[tokens.length - 1] === '') ? 1 : 0;//if the file ends with empty line ignore line NL
|
||||
if (tokens.length - this.nLines - dropLastToken <= 0) {
|
||||
//nLines is bigger than avaiable tokens: tail from the begin
|
||||
startingCursor = 0;
|
||||
} else {
|
||||
const match = data.match(new RegExp(`(?:[^\r\n]*[\r]{0,1}\n){${tokens.length - this.nLines - dropLastToken}}`));
|
||||
startingCursor = (match && match.length) ? Buffer.byteLength(match[0], this.encoding) : this.latestPosition();
|
||||
}
|
||||
} else {
|
||||
startingCursor = this.latestPosition();
|
||||
}
|
||||
if (startingCursor === undefined) throw new Error("Tail can't initialize.");
|
||||
const flush = fromBeginning || (this.nLines != undefined);
|
||||
try {
|
||||
this.watch(startingCursor, flush);
|
||||
} catch (err) {
|
||||
this.logger.error(`watch for ${this.filename} failed: ${err}`);
|
||||
this.emit("error", `watch for ${this.filename} failed: ${err}`);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
latestPosition() {
|
||||
try {
|
||||
return fs.statSync(this.filename).size;
|
||||
} catch (err) {
|
||||
this.logger.error(`size check for ${this.filename} failed: ${err}`);
|
||||
this.emit("error", `size check for ${this.filename} failed: ${err}`);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
readBlock() {
|
||||
if (this.queue.length >= 1) {
|
||||
const block = this.queue[0];
|
||||
if (block.end > block.start) {
|
||||
let stream = fs.createReadStream(this.filename, { start: block.start, end: block.end - 1, encoding: this.encoding });
|
||||
stream.on('error', (error) => {
|
||||
this.logger.error(`Tail error: ${error}`);
|
||||
this.emit('error', error);
|
||||
});
|
||||
stream.on('end', () => {
|
||||
let _ = this.queue.shift();
|
||||
if (this.queue.length > 0) {
|
||||
this.internalDispatcher.emit('next');
|
||||
}
|
||||
if (this.flushAtEOF && this.buffer.length > 0) {
|
||||
this.emit('line', this.buffer);
|
||||
this.buffer = "";
|
||||
}
|
||||
});
|
||||
stream.on('data', (d) => {
|
||||
if (this.separator === null) {
|
||||
this.emit("line", d);
|
||||
} else {
|
||||
this.buffer += d;
|
||||
let parts = this.buffer.split(this.separator);
|
||||
this.buffer = parts.pop();
|
||||
for (const chunk of parts) {
|
||||
this.emit("line", chunk);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
change() {
|
||||
let p = this.latestPosition()
|
||||
if (p < this.currentCursorPos) {//scenario where text is not appended but it's actually a w+
|
||||
this.currentCursorPos = p
|
||||
} else if (p > this.currentCursorPos) {
|
||||
this.queue.push({ start: this.currentCursorPos, end: p });
|
||||
this.currentCursorPos = p
|
||||
if (this.queue.length == 1) {
|
||||
this.internalDispatcher.emit("next");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
watch(startingCursor, flush) {
|
||||
if (this.isWatching) return;
|
||||
this.logger.info(`filesystem.watch present? ${fs.watch != undefined}`);
|
||||
this.logger.info(`useWatchFile: ${this.useWatchFile}`);
|
||||
|
||||
this.isWatching = true;
|
||||
this.currentCursorPos = startingCursor;
|
||||
//force a file flush is either fromBegining or nLines flags were passed.
|
||||
if (flush) this.change();
|
||||
|
||||
if (!this.useWatchFile && fs.watch) {
|
||||
this.logger.info(`watch strategy: watch`);
|
||||
this.watcher = fs.watch(this.filename, this.fsWatchOptions, (e, filename) => { this.watchEvent(e, filename); });
|
||||
} else {
|
||||
this.logger.info(`watch strategy: watchFile`);
|
||||
fs.watchFile(this.filename, this.fsWatchOptions, (curr, prev) => { this.watchFileEvent(curr, prev) });
|
||||
}
|
||||
}
|
||||
|
||||
rename(filename) {
|
||||
//TODO
|
||||
//MacOS sometimes throws a rename event for no reason.
|
||||
//Different platforms might behave differently.
|
||||
//see https://nodejs.org/api/fs.html#fs_fs_watch_filename_options_listener
|
||||
//filename might not be present.
|
||||
//https://nodejs.org/api/fs.html#fs_filename_argument
|
||||
//Better solution would be check inode but it will require a timeout and
|
||||
// a sync file read.
|
||||
if (filename === undefined || filename !== this.filename) {
|
||||
this.unwatch();
|
||||
if (this.follow) {
|
||||
this.filename = path.join(this.absPath, filename);
|
||||
this.rewatchId = setTimeout((() => {
|
||||
try {
|
||||
this.watch(this.currentCursorPos);
|
||||
} catch (ex) {
|
||||
this.logger.error(`'rename' event for ${this.filename}. File not available anymore.`);
|
||||
this.emit("error", ex);
|
||||
}
|
||||
}), 1000);
|
||||
} else {
|
||||
this.logger.error(`'rename' event for ${this.filename}. File not available anymore.`);
|
||||
this.emit("error", `'rename' event for ${this.filename}. File not available anymore.`);
|
||||
}
|
||||
} else {
|
||||
// this.logger.info("rename event but same filename")
|
||||
}
|
||||
}
|
||||
|
||||
watchEvent(e, evtFilename) {
|
||||
try {
|
||||
if (e === 'change') {
|
||||
this.change();
|
||||
} else if (e === 'rename') {
|
||||
this.rename(evtFilename);
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.error(`watchEvent for ${this.filename} failed: ${err}`);
|
||||
this.emit("error", `watchEvent for ${this.filename} failed: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
watchFileEvent(curr, prev) {
|
||||
if (curr.size > prev.size) {
|
||||
this.currentCursorPos = curr.size; //Update this.currentCursorPos so that a consumer can determine if entire file has been handled
|
||||
this.queue.push({ start: prev.size, end: curr.size });
|
||||
if (this.queue.length == 1) {
|
||||
this.internalDispatcher.emit("next");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unwatch() {
|
||||
if (this.watcher) {
|
||||
this.watcher.close();
|
||||
} else {
|
||||
fs.unwatchFile(this.filename);
|
||||
}
|
||||
if (this.rewatchId) {
|
||||
clearTimeout(this.rewatchId);
|
||||
this.rewatchId = undefined;
|
||||
}
|
||||
this.isWatching = false;
|
||||
this.queue = [];// TODO: is this correct behaviour?
|
||||
if (this.logger) {
|
||||
this.logger.info(`Unwatch ${this.filename}`);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
exports.Tail = Tail
|
40
install/secu/make/node_modules/tail/package.json
generated
vendored
Normal file
40
install/secu/make/node_modules/tail/package.json
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"author": {
|
||||
"name": "Luca Grulla",
|
||||
"url": "https://www.lucagrulla.com"
|
||||
},
|
||||
"contributors": [
|
||||
"Luca Grulla",
|
||||
"Tom Hall"
|
||||
],
|
||||
"name": "tail",
|
||||
"description": "tail a file in node",
|
||||
"keywords": [
|
||||
"tail",
|
||||
"file",
|
||||
"logs"
|
||||
],
|
||||
"version": "2.2.4",
|
||||
"homepage": "https://www.lucagrulla.com/node-tail",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/lucagrulla/node-tail.git"
|
||||
},
|
||||
"main": "lib/tail",
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rm -f ./lib/** && cp src/tail.js ./lib/",
|
||||
"prepare": "npm run build",
|
||||
"prepublishOnly": "npm run test",
|
||||
"test": "mocha",
|
||||
"coverage": "nyc npm run test"
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"chai": "4.x",
|
||||
"mocha": "9.x",
|
||||
"nyc": "^15.1.0"
|
||||
}
|
||||
}
|
38
install/secu/make/package-lock.json
generated
Normal file
38
install/secu/make/package-lock.json
generated
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "make",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"cmd-promise": "^1.2.0",
|
||||
"tail": "^2.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/cmd-promise": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/cmd-promise/-/cmd-promise-1.2.0.tgz",
|
||||
"integrity": "sha1-PPUTIiAZi1HBbakt44ag03Q9u1w="
|
||||
},
|
||||
"node_modules/tail": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/tail/-/tail-2.2.4.tgz",
|
||||
"integrity": "sha512-PX8klSxW1u3SdgDrDeewh5GNE+hkJ4h02JvHfV6YrHqWOVJ88nUdSQqtsUf/gWhgZlPAws3fiZ+F1f8euspcuQ==",
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"cmd-promise": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/cmd-promise/-/cmd-promise-1.2.0.tgz",
|
||||
"integrity": "sha1-PPUTIiAZi1HBbakt44ag03Q9u1w="
|
||||
},
|
||||
"tail": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/tail/-/tail-2.2.4.tgz",
|
||||
"integrity": "sha512-PX8klSxW1u3SdgDrDeewh5GNE+hkJ4h02JvHfV6YrHqWOVJ88nUdSQqtsUf/gWhgZlPAws3fiZ+F1f8euspcuQ=="
|
||||
}
|
||||
}
|
||||
}
|
6
install/secu/make/package.json
Normal file
6
install/secu/make/package.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"cmd-promise": "^1.2.0",
|
||||
"tail": "^2.2.4"
|
||||
}
|
||||
}
|
173
install/secu/make/v1.1.js
Normal file
173
install/secu/make/v1.1.js
Normal file
@ -0,0 +1,173 @@
|
||||
// Lets use some libs to help us out.
|
||||
const fs = require('fs')
|
||||
Tail = require('tail').Tail;
|
||||
|
||||
sshTail = new Tail("/var/log/auth.log");
|
||||
wpTail = new Tail("/var/log/apache2/access.log");
|
||||
const cmd = require('cmd-promise')
|
||||
|
||||
// Setting up our main storage logic - for now this program does not use a database system.
|
||||
let serverStatusCount = 0;
|
||||
let attackData = []
|
||||
let blockedIPs = []
|
||||
let ipToBlock
|
||||
|
||||
console.log("Welcome to the security notification system secuNotify by Discord-Linux!");
|
||||
console.log("We currently will notify you about login events, such as failed logins and successful logins.");
|
||||
|
||||
// Setting up our notification function - This allows us to direct message our user.
|
||||
function notify(message) {
|
||||
const { spawn } = require('child_process');
|
||||
const notif = spawn('notif', [message]);
|
||||
|
||||
notif.stdout.on('data', (data) => {
|
||||
console.log(`stdout: ${data}`);
|
||||
});
|
||||
|
||||
notif.stderr.on('data', (data) => {
|
||||
console.error(`stderr: ${data}`);
|
||||
});
|
||||
|
||||
notif.on('close', (code) => {
|
||||
console.log(`Code: ${code} - Continuing to monitor`);
|
||||
});
|
||||
}
|
||||
|
||||
function listenAuthLog(logLocation) {
|
||||
sshTail.on("line", function (info) {
|
||||
let infoString = info.toString();
|
||||
|
||||
if (infoString.includes("Failed password for root")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info);
|
||||
}
|
||||
|
||||
if (infoString.includes("Accepted password for")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info + "This does mean that someone (Maybe you) has logged in successfully!");
|
||||
}
|
||||
if (infoString.includes("Invalid user")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info + "This means that someone (Maybe you) has tried to login with an invalid username!");
|
||||
}
|
||||
})
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
function listenWPLog(logLocation) {
|
||||
// Check to see if we are a wordpress user, if so, activate the wordpress notification service
|
||||
const wpLog = '/var/www/html/wp-config.php'
|
||||
try {
|
||||
if (fs.existsSync(wpLog)) {
|
||||
console.log("We are a wordpress user, activating wordpress notification service");
|
||||
|
||||
// Tail Logs section, if we have a lot, it will have a listeniner below.
|
||||
wpTail.on("line", function (info) {
|
||||
|
||||
// Convert Data to String
|
||||
let requestInfo = info.toString()
|
||||
// FIND IP Address from this request
|
||||
var ipRegEx = /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/; // RegEx IPAddress Format
|
||||
var ipRegExMatched = requestInfo.match(ipRegEx); // Set up our match
|
||||
let remoteIP = ipRegExMatched[0] // Set our var
|
||||
|
||||
// // Grab the whitelist
|
||||
// let whitelistData = process.env.WHITELIST
|
||||
// let whitelist = whitelistData.split(",")
|
||||
|
||||
// // If an IP is found to be in the whitelist, return as to do nothing.
|
||||
// for (const [key, value] of Object.entries(whitelist)) {
|
||||
// if (value === remoteIP) return
|
||||
// }
|
||||
|
||||
// Filtering out any server-status requests - These are annoying.
|
||||
if (requestInfo.includes("server-status")) {
|
||||
// Add to the server status count so we may keep track of these requests.
|
||||
serverStatusCount++
|
||||
// Lets return the data as no not proceed with any further code, as it is not needed.
|
||||
// We return to stdout here to update the cli without adding a new line line a clock
|
||||
return process.stdout.write("Server Status Count: " + serverStatusCount + "\r");
|
||||
}
|
||||
|
||||
// If request contans wp-login lets process its request
|
||||
if (requestInfo.includes("wp-login.php")) {
|
||||
// Lets start the process of logging attack attempts to determine request intent.
|
||||
// Over the threshhold here will automatically CSF D the IP Address.
|
||||
// In this simple version, we will just log each IP Address as they come in within an array
|
||||
// We will then roll and count this array after each detection to determine the IPs intent.
|
||||
console.log("---------\nWP LOGIN REQUEST DETECTED!\n---------")
|
||||
console.log(info + "\n----------");
|
||||
attackData.push(remoteIP)
|
||||
|
||||
// Lets count the attack data per IP Address to ensure its logged properly.
|
||||
var counts = {};
|
||||
|
||||
// For each IP Address recorded into the main attackData array, count them and see outmany bad requests they have made.
|
||||
attackData.forEach(function (x) {
|
||||
// Add a point for each entry
|
||||
counts[x] = (counts[x] || 0) + 1;
|
||||
//
|
||||
for ([key, value] of Object.entries(counts)) {
|
||||
// If the count has hit the blockON Count we start the blocking process
|
||||
|
||||
if (counts[x] == 5) {
|
||||
// Preserve the key for later blocklist addition
|
||||
ipToBlock = key
|
||||
|
||||
// Check the already blocked IPs - If the remoteIP is in the list do nothing
|
||||
if (blockedIPs.includes(key)) {
|
||||
return
|
||||
|
||||
} else {
|
||||
// The remoteIP is not listed, lets add it.
|
||||
blockedIPs.push(ipToBlock)
|
||||
// Let the log know we are blocking the IP
|
||||
console.log("Starting to block bad IP")
|
||||
// Run the block, wait for the promise - Requests are still going on
|
||||
cmd(`/var/tools/firewallctl 123.123.123.123 ` + key + " WP-Login Brute Force Blocked Via secuNotify").then(out => {
|
||||
notify("secuNotify Service Alert: \n " + key + " has been blocked for 5 bad wordpress login attempts!");
|
||||
|
||||
// The block has finished - remoteIP no longer has access
|
||||
}).catch(err => {
|
||||
// IF we see an error, give its output
|
||||
console.log('CSF Error: ', err)
|
||||
}).then(out2 => {
|
||||
// Set IPBLOCK to null for a reset and start scanning for new attacks
|
||||
ipToBlock = null;
|
||||
console.log("Attack Stopped, Looking for new attacks....")
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Live view of the counts
|
||||
console.log(counts)
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
listenAuthLog("/var/log/auth.log")
|
||||
|
||||
const fs = require('fs')
|
||||
|
||||
const path = '/var/log/apache2/access.log'
|
||||
|
||||
try {
|
||||
if (fs.existsSync(path)) {
|
||||
listenWPLog("/var/log/apache2/access.log")
|
||||
}
|
||||
} catch(err) {
|
||||
console.log("I could not find any WP instaltion within the /var/www/html directory\nNOT loading the WP Log listener")
|
||||
}
|
||||
|
161
install/secu/make/v1.js
Normal file
161
install/secu/make/v1.js
Normal file
@ -0,0 +1,161 @@
|
||||
// Lets use some libs to help us out.
|
||||
const fs = require('fs')
|
||||
Tail = require('tail').Tail;
|
||||
|
||||
sshTail = new Tail("/var/log/auth.log");
|
||||
wpTail = new Tail("/var/log/apache2/access.log");
|
||||
const cmd = require('cmd-promise')
|
||||
|
||||
// Setting up our main storage logic - for now this program does not use a database system.
|
||||
let serverStatusCount = 0;
|
||||
let attackData = []
|
||||
let blockedIPs = []
|
||||
let ipToBlock
|
||||
|
||||
console.log("Welcome to the security notification system secuNotify by Discord-Linux!");
|
||||
console.log("We currently will notify you about login events, such as failed logins and successful logins.");
|
||||
|
||||
// Setting up our notification function - This allows us to direct message our user.
|
||||
function notify(message) {
|
||||
const { spawn } = require('child_process');
|
||||
const notif = spawn('notif', [message]);
|
||||
|
||||
notif.stdout.on('data', (data) => {
|
||||
console.log(`stdout: ${data}`);
|
||||
});
|
||||
|
||||
notif.stderr.on('data', (data) => {
|
||||
console.error(`stderr: ${data}`);
|
||||
});
|
||||
|
||||
notif.on('close', (code) => {
|
||||
console.log(`Code: ${code} - Continuing to monitor`);
|
||||
});
|
||||
}
|
||||
|
||||
function listenAuthLog(logLocation) {
|
||||
sshTail.on("line", function (info) {
|
||||
let infoString = info.toString();
|
||||
|
||||
if (infoString.includes("Failed password for root")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info);
|
||||
}
|
||||
|
||||
if (infoString.includes("Accepted password for")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info + "This does mean that someone (Maybe you) has logged in successfully!");
|
||||
}
|
||||
if (infoString.includes("Invalid user")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info + "This means that someone (Maybe you) has tried to login with an invalid username!");
|
||||
}
|
||||
})
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
function listenWPLog(logLocation) {
|
||||
// Check to see if we are a wordpress user, if so, activate the wordpress notification service
|
||||
const wpLog = '/var/www/html/wp-config.php'
|
||||
try {
|
||||
if (fs.existsSync(wpLog)) {
|
||||
console.log("We are a wordpress user, activating wordpress notification service");
|
||||
|
||||
// Tail Logs section, if we have a lot, it will have a listeniner below.
|
||||
wpTail.on("line", function (info) {
|
||||
|
||||
// Convert Data to String
|
||||
let requestInfo = info.toString()
|
||||
// FIND IP Address from this request
|
||||
var ipRegEx = /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/; // RegEx IPAddress Format
|
||||
var ipRegExMatched = requestInfo.match(ipRegEx); // Set up our match
|
||||
let remoteIP = ipRegExMatched[0] // Set our var
|
||||
|
||||
// // Grab the whitelist
|
||||
// let whitelistData = process.env.WHITELIST
|
||||
// let whitelist = whitelistData.split(",")
|
||||
|
||||
// // If an IP is found to be in the whitelist, return as to do nothing.
|
||||
// for (const [key, value] of Object.entries(whitelist)) {
|
||||
// if (value === remoteIP) return
|
||||
// }
|
||||
|
||||
// Filtering out any server-status requests - These are annoying.
|
||||
if (requestInfo.includes("server-status")) {
|
||||
// Add to the server status count so we may keep track of these requests.
|
||||
serverStatusCount++
|
||||
// Lets return the data as no not proceed with any further code, as it is not needed.
|
||||
// We return to stdout here to update the cli without adding a new line line a clock
|
||||
return process.stdout.write("Server Status Count: " + serverStatusCount + "\r");
|
||||
}
|
||||
|
||||
// If request contans wp-login lets process its request
|
||||
if (requestInfo.includes("wp-login.php")) {
|
||||
// Lets start the process of logging attack attempts to determine request intent.
|
||||
// Over the threshhold here will automatically CSF D the IP Address.
|
||||
// In this simple version, we will just log each IP Address as they come in within an array
|
||||
// We will then roll and count this array after each detection to determine the IPs intent.
|
||||
console.log("---------\nWP LOGIN REQUEST DETECTED!\n---------")
|
||||
console.log(info + "\n----------");
|
||||
attackData.push(remoteIP)
|
||||
|
||||
// Lets count the attack data per IP Address to ensure its logged properly.
|
||||
var counts = {};
|
||||
|
||||
// For each IP Address recorded into the main attackData array, count them and see outmany bad requests they have made.
|
||||
attackData.forEach(function (x) {
|
||||
// Add a point for each entry
|
||||
counts[x] = (counts[x] || 0) + 1;
|
||||
//
|
||||
for ([key, value] of Object.entries(counts)) {
|
||||
// If the count has hit the blockON Count we start the blocking process
|
||||
|
||||
if (counts[x] == 5) {
|
||||
// Preserve the key for later blocklist addition
|
||||
ipToBlock = key
|
||||
|
||||
// Check the already blocked IPs - If the remoteIP is in the list do nothing
|
||||
if (blockedIPs.includes(key)) {
|
||||
return
|
||||
|
||||
} else {
|
||||
// The remoteIP is not listed, lets add it.
|
||||
blockedIPs.push(ipToBlock)
|
||||
// Let the log know we are blocking the IP
|
||||
console.log("Starting to block bad IP")
|
||||
// Run the block, wait for the promise - Requests are still going on
|
||||
cmd(`/var/tools/firewallctl 123.123.123.123 ` + key + " WP-Login Brute Force Blocked Via secuNotify").then(out => {
|
||||
notify("secuNotify Service Alert: \n " + key + " has been blocked for 5 bad wordpress login attempts!");
|
||||
|
||||
// The block has finished - remoteIP no longer has access
|
||||
}).catch(err => {
|
||||
// IF we see an error, give its output
|
||||
console.log('CSF Error: ', err)
|
||||
}).then(out2 => {
|
||||
// Set IPBLOCK to null for a reset and start scanning for new attacks
|
||||
ipToBlock = null;
|
||||
console.log("Attack Stopped, Looking for new attacks....")
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Live view of the counts
|
||||
console.log(counts)
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
listenAuthLog("/var/log/auth.log")
|
||||
listenWPLog("/var/log/apache2/access.log")
|
BIN
install/secu/make/vs
Executable file
BIN
install/secu/make/vs
Executable file
Binary file not shown.
172
install/secu/make/vs.js
Normal file
172
install/secu/make/vs.js
Normal file
@ -0,0 +1,172 @@
|
||||
// Lets use some libs to help us out.
|
||||
const fs = require('fs')
|
||||
Tail = require('tail').Tail;
|
||||
|
||||
sshTail = new Tail("/var/log/auth.log");
|
||||
const cmd = require('cmd-promise')
|
||||
|
||||
// Setting up our main storage logic - for now this program does not use a database system.
|
||||
let serverStatusCount = 0;
|
||||
let attackData = []
|
||||
let blockedIPs = []
|
||||
let ipToBlock
|
||||
|
||||
console.log("Welcome to the security notification system secuNotify by Discord-Linux!");
|
||||
console.log("We currently will notify you about login events, such as failed logins and successful logins.");
|
||||
|
||||
// Setting up our notification function - This allows us to direct message our user.
|
||||
function notify(message) {
|
||||
const { spawn } = require('child_process');
|
||||
const notif = spawn('notif', [message]);
|
||||
|
||||
notif.stdout.on('data', (data) => {
|
||||
console.log(`stdout: ${data}`);
|
||||
});
|
||||
|
||||
notif.stderr.on('data', (data) => {
|
||||
console.error(`stderr: ${data}`);
|
||||
});
|
||||
|
||||
notif.on('close', (code) => {
|
||||
console.log(`Code: ${code} - Continuing to monitor`);
|
||||
});
|
||||
}
|
||||
|
||||
function listenAuthLog(logLocation) {
|
||||
sshTail.on("line", function (info) {
|
||||
let infoString = info.toString();
|
||||
|
||||
if (infoString.includes("Failed password for root")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info);
|
||||
}
|
||||
|
||||
if (infoString.includes("Accepted password for")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info + "This does mean that someone (Maybe you) has logged in successfully!");
|
||||
}
|
||||
if (infoString.includes("Invalid user")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info + "This means that someone (Maybe you) has tried to login with an invalid username!");
|
||||
}
|
||||
})
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
function listenWPLog(logLocation) {
|
||||
// Check to see if we are a wordpress user, if so, activate the wordpress notification service
|
||||
try {
|
||||
if (fs.existsSync("/var/www/html/wp-config.php")) {
|
||||
console.log("We are a wordpress user, activating wordpress notification service");
|
||||
|
||||
// Tail Logs section, if we have a lot, it will have a listeniner below.
|
||||
wpTail.on("line", function (info) {
|
||||
|
||||
// Convert Data to String
|
||||
let requestInfo = info.toString()
|
||||
// FIND IP Address from this request
|
||||
var ipRegEx = /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/; // RegEx IPAddress Format
|
||||
var ipRegExMatched = requestInfo.match(ipRegEx); // Set up our match
|
||||
let remoteIP = ipRegExMatched[0] // Set our var
|
||||
|
||||
// // Grab the whitelist
|
||||
// let whitelistData = process.env.WHITELIST
|
||||
// let whitelist = whitelistData.split(",")
|
||||
|
||||
// // If an IP is found to be in the whitelist, return as to do nothing.
|
||||
// for (const [key, value] of Object.entries(whitelist)) {
|
||||
// if (value === remoteIP) return
|
||||
// }
|
||||
|
||||
// Filtering out any server-status requests - These are annoying.
|
||||
if (requestInfo.includes("server-status")) {
|
||||
// Add to the server status count so we may keep track of these requests.
|
||||
serverStatusCount++
|
||||
// Lets return the data as no not proceed with any further code, as it is not needed.
|
||||
// We return to stdout here to update the cli without adding a new line line a clock
|
||||
return process.stdout.write("Server Status Count: " + serverStatusCount + "\r");
|
||||
}
|
||||
|
||||
// If request contans wp-login lets process its request
|
||||
if (requestInfo.includes("wp-login.php") && requestInfo.includes("POST")) {
|
||||
// Lets start the process of logging attack attempts to determine request intent.
|
||||
// Over the threshhold here will automatically CSF D the IP Address.
|
||||
// In this simple version, we will just log each IP Address as they come in within an array
|
||||
// We will then roll and count this array after each detection to determine the IPs intent.
|
||||
console.log("---------\nWP LOGIN REQUEST DETECTED!\n---------")
|
||||
console.log(info + "\n----------");
|
||||
attackData.push(remoteIP)
|
||||
|
||||
// Lets count the attack data per IP Address to ensure its logged properly.
|
||||
var counts = {};
|
||||
|
||||
// For each IP Address recorded into the main attackData array, count them and see outmany bad requests they have made.
|
||||
attackData.forEach(function (x) {
|
||||
// Add a point for each entry
|
||||
counts[x] = (counts[x] || 0) + 1;
|
||||
//
|
||||
for ([key, value] of Object.entries(counts)) {
|
||||
// If the count has hit the blockON Count we start the blocking process
|
||||
|
||||
if (counts[x] == 5) {
|
||||
// Preserve the key for later blocklist addition
|
||||
ipToBlock = key
|
||||
|
||||
// Check the already blocked IPs - If the remoteIP is in the list do nothing
|
||||
if (blockedIPs.includes(key)) {
|
||||
return
|
||||
|
||||
} else {
|
||||
// The remoteIP is not listed, lets add it.
|
||||
blockedIPs.push(ipToBlock)
|
||||
// Let the log know we are blocking the IP
|
||||
console.log("Starting to block bad IP")
|
||||
// Run the block, wait for the promise - Requests are still going on
|
||||
cmd(`/var/tools/firewallctl ` + key + " WP-Login Brute Force Blocked Via secuNotify").then(out => {
|
||||
notify("secuNotify Service Alert:\n " + key + " has been blocked for 5 bad wordpress login attempts!");
|
||||
|
||||
// The block has finished - remoteIP no longer has access
|
||||
}).catch(err => {
|
||||
// IF we see an error, give its output
|
||||
console.log('CSF Error: ', err)
|
||||
}).then(out2 => {
|
||||
// Set IPBLOCK to null for a reset and start scanning for new attacks
|
||||
ipToBlock = null;
|
||||
console.log("Attack Stopped, Looking for new attacks....")
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Live view of the counts
|
||||
console.log(counts)
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
listenAuthLog("/var/log/auth.log")
|
||||
|
||||
fs.exists("/var/log/apache2/access.log", function (isExist) {
|
||||
if (isExist) {
|
||||
wpTail = new Tail("/var/log/apache2/access.log");
|
||||
listenWPLog("/var/log/apache2/access.log")
|
||||
} else {
|
||||
console.log("ApacheHTTP Server is not installed, not enabling WP protection.");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
172
install/secu/make/vs_.js
Normal file
172
install/secu/make/vs_.js
Normal file
@ -0,0 +1,172 @@
|
||||
// Lets use some libs to help us out.
|
||||
const fs = require('fs')
|
||||
Tail = require('tail').Tail;
|
||||
|
||||
sshTail = new Tail("/var/log/auth.log");
|
||||
const cmd = require('cmd-promise')
|
||||
|
||||
// Setting up our main storage logic - for now this program does not use a database system.
|
||||
let serverStatusCount = 0;
|
||||
let attackData = []
|
||||
let blockedIPs = []
|
||||
let ipToBlock
|
||||
|
||||
console.log("Welcome to the security notification system secuNotify by Discord-Linux!");
|
||||
console.log("We currently will notify you about login events, such as failed logins and successful logins.");
|
||||
|
||||
// Setting up our notification function - This allows us to direct message our user.
|
||||
function notify(message) {
|
||||
const { spawn } = require('child_process');
|
||||
const notif = spawn('notif', [message]);
|
||||
|
||||
notif.stdout.on('data', (data) => {
|
||||
console.log(`stdout: ${data}`);
|
||||
});
|
||||
|
||||
notif.stderr.on('data', (data) => {
|
||||
console.error(`stderr: ${data}`);
|
||||
});
|
||||
|
||||
notif.on('close', (code) => {
|
||||
console.log(`Code: ${code} - Continuing to monitor`);
|
||||
});
|
||||
}
|
||||
|
||||
function listenAuthLog(logLocation) {
|
||||
sshTail.on("line", function (info) {
|
||||
let infoString = info.toString();
|
||||
|
||||
if (infoString.includes("Failed password for root")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info);
|
||||
}
|
||||
|
||||
if (infoString.includes("Accepted password for")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info + "This does mean that someone (Maybe you) has logged in successfully!");
|
||||
}
|
||||
if (infoString.includes("Invalid user")) {
|
||||
console.log(info);
|
||||
notify("secuNotify Service Alert: \n" + info + "This means that someone (Maybe you) has tried to login with an invalid username!");
|
||||
}
|
||||
})
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
function listenWPLog(logLocation) {
|
||||
// Check to see if we are a wordpress user, if so, activate the wordpress notification service
|
||||
try {
|
||||
if (fs.existsSync("/var/www/html/wp-config.php")) {
|
||||
console.log("We are a wordpress user, activating wordpress notification service");
|
||||
|
||||
// Tail Logs section, if we have a lot, it will have a listeniner below.
|
||||
wpTail.on("line", function (info) {
|
||||
|
||||
// Convert Data to String
|
||||
let requestInfo = info.toString()
|
||||
// FIND IP Address from this request
|
||||
var ipRegEx = /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/; // RegEx IPAddress Format
|
||||
var ipRegExMatched = requestInfo.match(ipRegEx); // Set up our match
|
||||
let remoteIP = ipRegExMatched[0] // Set our var
|
||||
|
||||
// // Grab the whitelist
|
||||
// let whitelistData = process.env.WHITELIST
|
||||
// let whitelist = whitelistData.split(",")
|
||||
|
||||
// // If an IP is found to be in the whitelist, return as to do nothing.
|
||||
// for (const [key, value] of Object.entries(whitelist)) {
|
||||
// if (value === remoteIP) return
|
||||
// }
|
||||
|
||||
// Filtering out any server-status requests - These are annoying.
|
||||
if (requestInfo.includes("server-status")) {
|
||||
// Add to the server status count so we may keep track of these requests.
|
||||
serverStatusCount++
|
||||
// Lets return the data as no not proceed with any further code, as it is not needed.
|
||||
// We return to stdout here to update the cli without adding a new line line a clock
|
||||
return process.stdout.write("Server Status Count: " + serverStatusCount + "\r");
|
||||
}
|
||||
|
||||
// If request contans wp-login lets process its request
|
||||
if (requestInfo.includes("wp-login.php")) {
|
||||
// Lets start the process of logging attack attempts to determine request intent.
|
||||
// Over the threshhold here will automatically CSF D the IP Address.
|
||||
// In this simple version, we will just log each IP Address as they come in within an array
|
||||
// We will then roll and count this array after each detection to determine the IPs intent.
|
||||
console.log("---------\nWP LOGIN REQUEST DETECTED!\n---------")
|
||||
console.log(info + "\n----------");
|
||||
attackData.push(remoteIP)
|
||||
|
||||
// Lets count the attack data per IP Address to ensure its logged properly.
|
||||
var counts = {};
|
||||
|
||||
// For each IP Address recorded into the main attackData array, count them and see outmany bad requests they have made.
|
||||
attackData.forEach(function (x) {
|
||||
// Add a point for each entry
|
||||
counts[x] = (counts[x] || 0) + 1;
|
||||
//
|
||||
for ([key, value] of Object.entries(counts)) {
|
||||
// If the count has hit the blockON Count we start the blocking process
|
||||
|
||||
if (counts[x] == 5) {
|
||||
// Preserve the key for later blocklist addition
|
||||
ipToBlock = key
|
||||
|
||||
// Check the already blocked IPs - If the remoteIP is in the list do nothing
|
||||
if (blockedIPs.includes(key)) {
|
||||
return
|
||||
|
||||
} else {
|
||||
// The remoteIP is not listed, lets add it.
|
||||
blockedIPs.push(ipToBlock)
|
||||
// Let the log know we are blocking the IP
|
||||
console.log("Starting to block bad IP")
|
||||
// Run the block, wait for the promise - Requests are still going on
|
||||
cmd(`/var/tools/firewallctl ` + key + " WP-Login Brute Force Blocked Via secuNotify").then(out => {
|
||||
notify("secuNotify Service Alert:\n " + key + " has been blocked for 5 bad wordpress login attempts!");
|
||||
|
||||
// The block has finished - remoteIP no longer has access
|
||||
}).catch(err => {
|
||||
// IF we see an error, give its output
|
||||
console.log('CSF Error: ', err)
|
||||
}).then(out2 => {
|
||||
// Set IPBLOCK to null for a reset and start scanning for new attacks
|
||||
ipToBlock = null;
|
||||
console.log("Attack Stopped, Looking for new attacks....")
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Live view of the counts
|
||||
console.log(counts)
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
listenAuthLog("/var/log/auth.log")
|
||||
|
||||
fs.exists("/var/log/apache2/access.log", function (isExist) {
|
||||
if (isExist) {
|
||||
wpTail = new Tail("/var/log/apache2/access.log");
|
||||
listenWPLog("/var/log/apache2/access.log")
|
||||
} else {
|
||||
console.log("ApacheHTTP Server is not installed, not enabling WP protection.");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
BIN
install/secu/secuNotify
Executable file
BIN
install/secu/secuNotify
Executable file
Binary file not shown.
15
install/secu/secuNotify.service
Normal file
15
install/secu/secuNotify.service
Normal file
@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=secunotify service
|
||||
After=network.target
|
||||
StartLimitIntervalSec=0
|
||||
[Service]
|
||||
EnvironmentFile=
|
||||
WorkingDirectory=/var/tools/
|
||||
Type=simple
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
User=root
|
||||
ExecStart=/var/tools/secuNotify
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
BIN
install/secu/secuNotifyold
Executable file
BIN
install/secu/secuNotifyold
Executable file
Binary file not shown.
Reference in New Issue
Block a user