24 changed files with 429 additions and 538 deletions
@ -1,37 +0,0 @@ |
|||||
declare const nodeUfw: { |
|
||||
name: string; |
|
||||
|
|
||||
version: string; |
|
||||
|
|
||||
disable: () => Promise<Boolean>; |
|
||||
|
|
||||
enable: () => Promise<Boolean>; |
|
||||
|
|
||||
reset: () => Promise<Boolean>; |
|
||||
|
|
||||
reload: () => Promise<Boolean>; |
|
||||
|
|
||||
status: (raw?: boolean) => Promise<string | Array<ParsedStatus>>; |
|
||||
|
|
||||
logging: (type: LoggingType) => Promise<Boolean>; |
|
||||
|
|
||||
allow: { |
|
||||
port: (port: number, protocol?: "udp" | "tcp") => Promise<Boolean>; |
|
||||
address: (address: string, port?: number, protocol?: "udp" | "tcp") => Promise<Boolean>; |
|
||||
}; |
|
||||
|
|
||||
deny: { |
|
||||
port: (port: number, protocol?: "udp" | "tcp") => Promise<Boolean>; |
|
||||
address: (address: string, port?: number, protocol?: "udp" | "tcp") => Promise<Boolean>; |
|
||||
}; |
|
||||
}; |
|
||||
|
|
||||
type LoggingType = 'off' | 'on' | 'low' | 'medium' | 'high' | 'full'; |
|
||||
|
|
||||
interface ParsedStatus { |
|
||||
to: string; |
|
||||
action: string; |
|
||||
from: string; |
|
||||
} |
|
||||
|
|
||||
export = nodeUfw; |
|
@ -1 +0,0 @@ |
|||||
module.exports = require("./src/Main.js"); |
|
@ -0,0 +1,27 @@ |
|||||
|
import { checkSudo, checkNodeVersion, checkPlatform, checkPlatformExact } from './Util'; |
||||
|
|
||||
|
if (!checkSudo()) { |
||||
|
throw new Error("You need to be root to run this package."); |
||||
|
}; |
||||
|
|
||||
|
if (!checkNodeVersion()) { |
||||
|
throw new Error(`The Node version must be at least v14 or above.`); |
||||
|
}; |
||||
|
|
||||
|
if (!checkPlatform()) { |
||||
|
throw new Error("Your platform must be at least `linux`."); |
||||
|
}; |
||||
|
|
||||
|
if (!checkPlatformExact()) { |
||||
|
throw new Error("node-ufw only supported on Ubuntu."); |
||||
|
}; |
||||
|
|
||||
|
export { default as allow } from "./methods/Allow"; |
||||
|
export { default as deny } from "./methods/Deny"; |
||||
|
export { default as disable } from "./methods/Disable"; |
||||
|
export { default as enable } from "./methods/Enable"; |
||||
|
export { default as status } from "./methods/Status"; |
||||
|
export { default as delete } from "./methods/Delete"; |
||||
|
export { default as reset } from "./methods/Reset"; |
||||
|
export { default as reload } from "./methods/Reload"; |
||||
|
export { default as logging } from "./methods/Logging" |
@ -1,31 +0,0 @@ |
|||||
const {checkSudo, checkNodeVersion, checkPlatform, checkPlatformExact} = require('./Util'); |
|
||||
|
|
||||
if (!checkSudo()) { |
|
||||
throw new Error("You need to be root to run this package."); |
|
||||
}; |
|
||||
|
|
||||
if (!checkNodeVersion()) { |
|
||||
throw new Error(`The Node version must be at least v14 or above.`); |
|
||||
}; |
|
||||
|
|
||||
if (!checkPlatform()) { |
|
||||
throw new Error("Your platform must be at least `linux`."); |
|
||||
}; |
|
||||
|
|
||||
if (!checkPlatformExact()) { |
|
||||
throw new Error("node-ufw only supported on Ubuntu."); |
|
||||
}; |
|
||||
|
|
||||
module.exports = { |
|
||||
name: require("../package.json").name, |
|
||||
version: require("../package.json").version, |
|
||||
allow: require("./methods/allow"), |
|
||||
deny: require("./methods/deny"), |
|
||||
disable: require("./methods/disable"), |
|
||||
enable: require("./methods/enable"), |
|
||||
status: require("./methods/status"), |
|
||||
delete: require("./methods/delete"), |
|
||||
reset: require("./methods/reset"), |
|
||||
reload: require("./methods/reload"), |
|
||||
logging: require("./methods/logging") |
|
||||
}; |
|
@ -0,0 +1,37 @@ |
|||||
|
interface ParsedStatus { |
||||
|
to: string; |
||||
|
action: string; |
||||
|
from: string; |
||||
|
} |
||||
|
|
||||
|
type LoggingType = 'off' | 'on' | 'low' | 'medium' | 'high' | 'full'; |
||||
|
|
||||
|
type PortProtocol = "udp" | "tcp"; |
||||
|
|
||||
|
export declare const nodeUfw: { |
||||
|
name: string; |
||||
|
|
||||
|
version: string; |
||||
|
|
||||
|
disable: () => Promise<Boolean>; |
||||
|
|
||||
|
enable: () => Promise<Boolean>; |
||||
|
|
||||
|
reset: () => Promise<Boolean>; |
||||
|
|
||||
|
reload: () => Promise<Boolean>; |
||||
|
|
||||
|
status: (raw?: boolean) => Promise<string | ParsedStatus[] | null>; |
||||
|
|
||||
|
logging: (type: LoggingType) => Promise<Boolean>; |
||||
|
|
||||
|
allow: { |
||||
|
port: (port: number, protocol?: PortProtocol) => Promise<Boolean>; |
||||
|
address: (address: string, port?: number, protocol?: PortProtocol) => Promise<Boolean>; |
||||
|
}; |
||||
|
|
||||
|
deny: { |
||||
|
port: (port: number, protocol?: PortProtocol) => Promise<Boolean>; |
||||
|
address: (address: string, port?: number, protocol?: PortProtocol) => Promise<Boolean>; |
||||
|
}; |
||||
|
}; |
@ -1,105 +0,0 @@ |
|||||
const {execSync} = require("child_process"); |
|
||||
// const {promisify} = require("util");
|
|
||||
// const promisifiedExec = promisify(exec);
|
|
||||
const {getuid, versions, platform} = require("process"); |
|
||||
|
|
||||
module.exports.checkSudo = function () { |
|
||||
return getuid && getuid() == 0 ? true : false; |
|
||||
}; |
|
||||
|
|
||||
module.exports.checkNodeVersion = function () { |
|
||||
const currentApropriateVersion = 14, nodeVersion = versions.node.split('.'); |
|
||||
|
|
||||
return +nodeVersion[0] > currentApropriateVersion ? true : false; |
|
||||
}; |
|
||||
|
|
||||
module.exports.checkPlatform = function () { |
|
||||
// https://nodejs.org/api/process.html#process_process_platform
|
|
||||
return platform == "linux" ? true : false; |
|
||||
}; |
|
||||
|
|
||||
// module.exports.getDistroInfo = async function () {
|
|
||||
// let current = {
|
|
||||
// distributorID: null, distributorVersion: null
|
|
||||
// };
|
|
||||
|
|
||||
// try {
|
|
||||
// // check version
|
|
||||
// let {stdout, stderr} = await promisifiedExec('lsb_release -i -r');
|
|
||||
|
|
||||
// if (stderr) {
|
|
||||
// throw new Error(`Error while checking Linux distribution information: ${stderr}`);
|
|
||||
// };
|
|
||||
|
|
||||
// if (stdout) {
|
|
||||
// // sanitize
|
|
||||
// let parsed = stdout
|
|
||||
// .split(/\r|\n/gi) // remove break lines
|
|
||||
// .map(x => x.replace(/\s/gi, "")) // remove spaces, only remains [e.g. DistributorID:Ubuntu]
|
|
||||
// .filter(x => x); // filter empty string
|
|
||||
|
|
||||
// let findDistributorID = parsed.find(val => val.match(/^(DistributorID)/gi));
|
|
||||
// let findReleaseVersion = parsed.find(val => val.match(/^(Release)/gi));
|
|
||||
|
|
||||
// if (findDistributorID) {
|
|
||||
// let splitViaColon = findDistributorID.split(/(:)/gi);
|
|
||||
// if (splitViaColon) current.distributorID = splitViaColon.pop().toLowerCase();
|
|
||||
// };
|
|
||||
|
|
||||
// if (findReleaseVersion) {
|
|
||||
// let splitViaColon = findReleaseVersion.split(/(:)/gi);
|
|
||||
// if (splitViaColon) current.distributorVersion = splitViaColon.pop().toLowerCase();
|
|
||||
// };
|
|
||||
// };
|
|
||||
// } catch {};
|
|
||||
|
|
||||
// return current;
|
|
||||
// };
|
|
||||
|
|
||||
module.exports.checkPlatformExact = function () { |
|
||||
// let distroInfo = await this.getDistroInfo();
|
|
||||
// if (!distroInfo?.distributorID || !distroInfo?.distributorVersion) {
|
|
||||
// throw new Error("Missing distro platform information.");
|
|
||||
// };
|
|
||||
|
|
||||
// // https://en.wikipedia.org/wiki/Uncomplicated_Firewall
|
|
||||
// let platform = distroInfo.distributorID;
|
|
||||
// if (String(platform).toLowerCase() !== "ubuntu") {
|
|
||||
// throw new Error("node-ufw only supported on Ubuntu.");
|
|
||||
// };
|
|
||||
|
|
||||
// return true;
|
|
||||
|
|
||||
try { |
|
||||
const check = execSync("cat /etc/*release | grep -E ^NAME"); |
|
||||
return check?.toString("utf-8").match("Ubuntu") ? true : false; |
|
||||
} catch (e) { |
|
||||
console.error(e); |
|
||||
return false; |
|
||||
}; |
|
||||
}; |
|
||||
|
|
||||
module.exports.checkAppropriatePort = function(port) { |
|
||||
const portLimit = Math.round(2 ** 16 - 1); |
|
||||
|
|
||||
if (typeof port !== "number") throw new Error("The port must be type of number."); |
|
||||
|
|
||||
return (port > 0 || port <= portLimit) ? true : false; |
|
||||
}; |
|
||||
|
|
||||
module.exports.checkAppropriateIP = function(address) { |
|
||||
if (typeof address !== "string") throw new Error("The address must be type of string."); |
|
||||
|
|
||||
// https://blog.markhatton.co.uk/2011/03/15/regular-expressions-for-ip-addresses-cidr-ranges-and-hostnames/
|
|
||||
// also support subnet/net mask
|
|
||||
let regex = new RegExp(/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(3[0-2]|[1-2][0-9]|[0-9]))?$/gi); |
|
||||
return address.match(regex) !== null ? true : false; |
|
||||
}; |
|
||||
|
|
||||
// soon to be continued
|
|
||||
// module.exports.checkPlatformVersion = function () {
|
|
||||
// let distroInfo = this.getDistroInfo();
|
|
||||
// if (!distroInfo?.distributorID || !distroInfo?.distributorVersion) {
|
|
||||
// throw new Error("Missing distro platform information.");
|
|
||||
// };
|
|
||||
// };
|
|
@ -0,0 +1,40 @@ |
|||||
|
import { execSync } from "node:child_process"; |
||||
|
import { getuid, versions, platform } from "node:process"; |
||||
|
|
||||
|
export function checkSudo() { |
||||
|
return getuid && getuid() == 0 ? true : false; |
||||
|
}; |
||||
|
|
||||
|
export function checkNodeVersion() { |
||||
|
const currentApropriateVersion = 14, nodeVersion = versions.node.split('.'); |
||||
|
|
||||
|
return +nodeVersion[0] > currentApropriateVersion ? true : false; |
||||
|
}; |
||||
|
|
||||
|
export function checkPlatform() { |
||||
|
// https://nodejs.org/api/process.html#process_process_platform
|
||||
|
return platform == "linux" ? true : false; |
||||
|
}; |
||||
|
|
||||
|
export function checkPlatformExact() { |
||||
|
try { |
||||
|
const check = execSync("cat /etc/*release | grep -E ^NAME"); |
||||
|
return check?.toString("utf-8").match("Ubuntu") ? true : false; |
||||
|
} catch (e) { |
||||
|
console.error(e); |
||||
|
return false; |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
export function checkAppropriatePort(port: number) { |
||||
|
const portLimit = Math.round(2 ** 16 - 1); |
||||
|
|
||||
|
return port > 0 || port <= portLimit; |
||||
|
}; |
||||
|
|
||||
|
export function checkAppropriateIP(address: string) { |
||||
|
// https://blog.markhatton.co.uk/2011/03/15/regular-expressions-for-ip-addresses-cidr-ranges-and-hostnames/
|
||||
|
|
||||
|
let regex = new RegExp(/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(3[0-2]|[1-2][0-9]|[0-9]))?$/gi); |
||||
|
return address.match(regex) !== null ? true : false; |
||||
|
}; |
@ -0,0 +1,74 @@ |
|||||
|
import { exec } from "node:child_process"; |
||||
|
import { promisify } from "node:util"; |
||||
|
import { checkAppropriatePort, checkAppropriateIP } from "../Util"; |
||||
|
import type { PortProtocol } from "../Typings"; |
||||
|
|
||||
|
const promisifiedExec = promisify(exec); |
||||
|
|
||||
|
/** |
||||
|
* Allow incoming requests through specific port. (root/sudo access is mandatory) |
||||
|
*/ |
||||
|
async function port(port: number, protocol?: PortProtocol) { |
||||
|
try { |
||||
|
// check port range
|
||||
|
let checkPort = checkAppropriatePort(port); |
||||
|
if (!checkPort) return false; |
||||
|
|
||||
|
let res = await promisifiedExec(`echo "y" | sudo ufw allow ${port}${protocol ? `/${protocol}` : ""}`); |
||||
|
if (res.stderr) throw new Error(res.stderr); |
||||
|
|
||||
|
if (res.stdout) { |
||||
|
// will find a better way to parse this
|
||||
|
if (res.stdout.toLowerCase().match(/(added)/gi)) { |
||||
|
return true; |
||||
|
} else { |
||||
|
console.log(res.stdout); |
||||
|
return false; |
||||
|
}; |
||||
|
} else { |
||||
|
console.log(res.stdout); |
||||
|
return false; |
||||
|
}; |
||||
|
} catch (err) { |
||||
|
throw err; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Allow incoming requests through specific (IP) address. (root/sudo access is mandatory) |
||||
|
*/ |
||||
|
async function address(address: string, port: number, protocol?: PortProtocol) { |
||||
|
try { |
||||
|
// address validation
|
||||
|
let checkAddress = checkAppropriateIP(address); |
||||
|
if (!checkAddress) return false; |
||||
|
|
||||
|
// port validation
|
||||
|
if (port) { |
||||
|
let checkPort = checkAppropriatePort(port); |
||||
|
if (!checkPort) return false; |
||||
|
}; |
||||
|
|
||||
|
let res = await promisifiedExec(`echo "y" | sudo ufw allow from ${address} ${port ? `to any port ${port}` : ""} ${protocol ? `proto ${protocol}` : ""}`); |
||||
|
if (res.stderr) throw new Error(res.stderr); |
||||
|
|
||||
|
if (res.stdout) { |
||||
|
// will find a better way to parse this
|
||||
|
if (res.stdout.toLowerCase().match(/(added)/gi)) { |
||||
|
return true; |
||||
|
} else { |
||||
|
console.log(res.stdout); |
||||
|
return false; |
||||
|
}; |
||||
|
} else { |
||||
|
console.log(res.stdout); |
||||
|
return false; |
||||
|
}; |
||||
|
} catch (err) { |
||||
|
throw err; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default { |
||||
|
address, port |
||||
|
}; |
@ -0,0 +1,29 @@ |
|||||
|
import { exec } from "node:child_process"; |
||||
|
import { promisify } from "node:util"; |
||||
|
const promisifiedExec = promisify(exec); |
||||
|
|
||||
|
/** |
||||
|
* Delete ufw rule(s). (root/sudo access is mandatory) |
||||
|
*/ |
||||
|
export default async function(num: number) { |
||||
|
try { |
||||
|
if (num === 0) { |
||||
|
num = 1; |
||||
|
}; |
||||
|
|
||||
|
let res = await promisifiedExec(`echo "y" | sudo ufw delete ${num}`); |
||||
|
|
||||
|
if (res.stderr) { |
||||
|
throw new Error(res.stderr); |
||||
|
}; |
||||
|
|
||||
|
if (res.stdout) { |
||||
|
return true; |
||||
|
} else { |
||||
|
console.log(res.stdout); |
||||
|
return false; |
||||
|
}; |
||||
|
} catch (err) { |
||||
|
throw err; |
||||
|
}; |
||||
|
}; |
@ -0,0 +1,76 @@ |
|||||
|
import { exec } from "node:child_process"; |
||||
|
import { promisify } from "node:util"; |
||||
|
import { checkAppropriatePort, checkAppropriateIP } from "../Util"; |
||||
|
import type { PortProtocol } from "../Typings"; |
||||
|
|
||||
|
const promisifiedExec = promisify(exec); |
||||
|
|
||||
|
/** |
||||
|
* Deny incoming requests through specific port. (root/sudo access is mandatory) |
||||
|
*/ |
||||
|
async function port(port: number, protocol?: PortProtocol) { |
||||
|
try { |
||||
|
// check port range
|
||||
|
let checkPort = checkAppropriatePort(port); |
||||
|
if (!checkPort) return false; |
||||
|
|
||||
|
let res = await promisifiedExec(`echo "y" | sudo ufw deny ${port}${protocol ? `/${protocol}` : ""}`); |
||||
|
if (res.stderr) { |
||||
|
throw new Error(res.stderr); |
||||
|
}; |
||||
|
|
||||
|
if (res.stdout) { |
||||
|
// will find a better way to parse this
|
||||
|
if (res.stdout.toLowerCase().match(/(added)/gi)) { |
||||
|
return true; |
||||
|
} else { |
||||
|
console.log(res.stdout); |
||||
|
return false; |
||||
|
}; |
||||
|
} else { |
||||
|
console.log(res.stdout); |
||||
|
return false; |
||||
|
}; |
||||
|
} catch (err) { |
||||
|
throw err; |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Deny incoming requests through specific (IP) address. (root/sudo access is mandatory) |
||||
|
*/ |
||||
|
async function address(address: string, port: number, protocol?: PortProtocol) { |
||||
|
try { |
||||
|
// address validation
|
||||
|
let checkAddress = checkAppropriateIP(address); |
||||
|
if (!checkAddress) return false; |
||||
|
|
||||
|
// port validation
|
||||
|
if (port) { |
||||
|
let checkPort = checkAppropriatePort(port); |
||||
|
if (!checkPort) return false; |
||||
|
}; |
||||
|
|
||||
|
let res = await promisifiedExec(`echo "y" | sudo ufw deny from ${address} ${port ? `to any port ${port}` : ""} ${protocol ? `proto ${protocol}` : ""}`); |
||||
|
if (res.stderr) throw new Error(res.stderr); |
||||
|
|
||||
|
if (res.stdout) { |
||||
|
// will find a better way to parse this
|
||||
|
if (res.stdout.toLowerCase().match(/(added)/gi)) { |
||||
|
return true; |
||||
|
} else { |
||||
|
console.log(res.stdout); |
||||
|
return false; |
||||
|
}; |
||||
|
} else { |
||||
|
console.log(res.stdout); |
||||
|
return false; |
||||
|
}; |
||||
|
} catch (err) { |
||||
|
throw err; |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
export default { |
||||
|
address, port |
||||
|
}; |
@ -0,0 +1,23 @@ |
|||||
|
import { exec } from "node:child_process"; |
||||
|
import { promisify } from "node:util"; |
||||
|
import type { LoggingType } from "../Typings"; |
||||
|
const promisifiedExec = promisify(exec); |
||||
|
|
||||
|
/** |
||||
|
* Set/toggle UFW logging. (root/sudo access is mandatory) |
||||
|
*/ |
||||
|
export default async function(type: LoggingType) { |
||||
|
try { |
||||
|
let res = await promisifiedExec(`sudo ufw logging ${type}`); |
||||
|
|
||||
|
if (res.stderr) throw new Error(res.stderr); |
||||
|
|
||||
|
if (res.stdout) { |
||||
|
return true; |
||||
|
} else { |
||||
|
return false; |
||||
|
}; |
||||
|
} catch (err) { |
||||
|
throw err; |
||||
|
}; |
||||
|
}; |
@ -0,0 +1,22 @@ |
|||||
|
import { exec } from "node:child_process"; |
||||
|
import { promisify } from "node:util"; |
||||
|
const promisifiedExec = promisify(exec); |
||||
|
|
||||
|
/** |
||||
|
* Reloads firewall. (root/sudo access is mandatory) |
||||
|
*/ |
||||
|
export default async function() { |
||||
|
try { |
||||
|
let res = await promisifiedExec("sudo ufw reload"); |
||||
|
|
||||
|
if (res.stderr) throw new Error(res.stderr); |
||||
|
|
||||
|
if (res.stdout) { |
||||
|
return true; |
||||
|
} else { |
||||
|
return false; |
||||
|
}; |
||||
|
} catch (err) { |
||||
|
throw err; |
||||
|
}; |
||||
|
}; |
@ -0,0 +1,22 @@ |
|||||
|
import { exec } from "node:child_process"; |
||||
|
import { promisify } from "node:util"; |
||||
|
const promisifiedExec = promisify(exec); |
||||
|
|
||||
|
/** |
||||
|
* Disables and resets firewall to installation defaults. No prompt. Use this wisely. (root/sudo access is mandatory)= |
||||
|
*/ |
||||
|
export default async function() { |
||||
|
try { |
||||
|
let res = await promisifiedExec("sudo ufw --force reset"); |
||||
|
|
||||
|
if (res.stderr) throw new Error(res.stderr); |
||||
|
|
||||
|
if (res.stdout) { |
||||
|
return true; |
||||
|
} else { |
||||
|
return false; |
||||
|
}; |
||||
|
} catch (err) { |
||||
|
throw err; |
||||
|
}; |
||||
|
}; |
@ -0,0 +1,45 @@ |
|||||
|
import { exec } from "node:child_process"; |
||||
|
import { promisify } from "node:util"; |
||||
|
import type { ParsedStatus } from "../Typings"; |
||||
|
const promisifiedExec = promisify(exec); |
||||
|
|
||||
|
/** |
||||
|
* List of currently activated ufw. (root/sudo access is mandatory) |
||||
|
*/ |
||||
|
export default async function(raw?: boolean): Promise<string | ParsedStatus[] | null> { |
||||
|
try { |
||||
|
let res = await promisifiedExec("sudo ufw status"); |
||||
|
|
||||
|
if (res.stderr) throw new Error(res.stderr); |
||||
|
|
||||
|
if (res.stdout) { |
||||
|
if (raw) return res.stdout; |
||||
|
|
||||
|
let list = []; |
||||
|
|
||||
|
// parsing
|
||||
|
let parsedStatus = res.stdout.replace(/\r|\n/gi, " ").split(/\s{2,}/gi).filter(x => x.length); |
||||
|
if (!parsedStatus.length) return []; |
||||
|
|
||||
|
let findAfterFrom = parsedStatus.findIndex(x => x == "----"); |
||||
|
let afterSlice = parsedStatus.slice(findAfterFrom + 1, parsedStatus.length); |
||||
|
if (!afterSlice.length) return []; |
||||
|
|
||||
|
for (let i = 0; i < afterSlice.length; i++) { |
||||
|
if (i % 3 == 0) { |
||||
|
let to = afterSlice[i]; |
||||
|
let action = afterSlice[i + 1]; |
||||
|
let from = afterSlice[i + 2]; |
||||
|
|
||||
|
list.push({to, action, from}); |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
return list; |
||||
|
}; |
||||
|
|
||||
|
return null; |
||||
|
} catch (err) { |
||||
|
throw err; |
||||
|
}; |
||||
|
}; |
@ -1,92 +0,0 @@ |
|||||
const {exec} = require("child_process"); |
|
||||
const {promisify} = require("util"); |
|
||||
const promisifiedExec = promisify(exec); |
|
||||
const util = require("../Util"); |
|
||||
|
|
||||
/** |
|
||||
* Allow incoming requests through specific port. (root/sudo access is mandatory) |
|
||||
* @param {number} port The connection pange. From range 1 - 65535. |
|
||||
* @param {"udp" | "tcp" | undefined} protocol The protocol. |
|
||||
* @returns {Promise<Boolean>} Returns a boolean. |
|
||||
*/ |
|
||||
module.exports.port = async function (port, protocol) { |
|
||||
try { |
|
||||
if (!port) throw new Error("Missing port input."); |
|
||||
if (typeof port !== "number") throw new Error("The port must be type of number."); |
|
||||
|
|
||||
// check port range
|
|
||||
let checkPort = util.checkAppropriatePort(port); |
|
||||
if (!checkPort) return false; |
|
||||
|
|
||||
if (protocol) { |
|
||||
if (typeof protocol !== "string") throw new Error("The protocol must be type of string."); |
|
||||
if (protocol !== "tcp" || protocol !== "udp") throw new Error('The protocol must be either "tcp" or "udp"'); |
|
||||
}; |
|
||||
|
|
||||
let res = await promisifiedExec(`echo "y" | sudo ufw allow ${port}${protocol ? `/${protocol}` : ""}`); |
|
||||
if (res.stderr) throw new Error(res.stderr); |
|
||||
|
|
||||
if (res.stdout) { |
|
||||
// will find a better way to parse this
|
|
||||
if (res.stdout.toLowerCase().match(/(added)/gi)) { |
|
||||
return true; |
|
||||
} else { |
|
||||
console.log(res.stdout); |
|
||||
return false; |
|
||||
}; |
|
||||
} else { |
|
||||
console.log(res.stdout); |
|
||||
return false; |
|
||||
}; |
|
||||
} catch (err) { |
|
||||
throw new Error(err); |
|
||||
}; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Allow incoming requests through specific (IP) address. (root/sudo access is mandatory) |
|
||||
* @param {string} address IP address, supported by subnet/net mask. From range 0.0.0.0 to 255.255.255.255 |
|
||||
* @param {number | undefined} port The connection pange. From range 1 - 65535. |
|
||||
* @param {"udp" | "tcp" | undefined} protocol The protocol. |
|
||||
* @returns {Promise<Boolean>} Returns a boolean. |
|
||||
*/ |
|
||||
module.exports.address = async function (address, port, protocol) { |
|
||||
try { |
|
||||
// address validation
|
|
||||
if (!address) throw new Error("Missing address input."); |
|
||||
if (typeof address !== "string") throw new Error("The address must be type of string."); |
|
||||
let checkAddress = util.checkAppropriateIP(address); |
|
||||
if (!checkAddress) return false; |
|
||||
|
|
||||
// port validation
|
|
||||
if (port) { |
|
||||
if (typeof port !== "number") throw new Error("The port must be type of number."); |
|
||||
let checkPort = util.checkAppropriatePort(port); |
|
||||
if (!checkPort) return false; |
|
||||
}; |
|
||||
|
|
||||
// protocol (tcp/udp) validation
|
|
||||
if (protocol) { |
|
||||
if (typeof protocol !== "string") throw new Error("The protocol must be type of string."); |
|
||||
if (protocol !== "tcp" || protocol !== "udp") throw new Error('The protocol must be either "tcp" or "udp"'); |
|
||||
}; |
|
||||
|
|
||||
let res = await promisifiedExec(`echo "y" | sudo ufw allow from ${address} ${port ? `to any port ${port}` : ""} ${protocol ? `proto ${protocol}` : ""}`); |
|
||||
if (res.stderr) throw new Error(res.stderr); |
|
||||
|
|
||||
if (res.stdout) { |
|
||||
// will find a better way to parse this
|
|
||||
if (res.stdout.toLowerCase().match(/(added)/gi)) { |
|
||||
return true; |
|
||||
} else { |
|
||||
console.log(res.stdout); |
|
||||
return false; |
|
||||
}; |
|
||||
} else { |
|
||||
console.log(res.stdout); |
|
||||
return false; |
|
||||
}; |
|
||||
} catch (err) { |
|
||||
throw new Error(err); |
|
||||
}; |
|
||||
}; |
|
@ -1,30 +0,0 @@ |
|||||
const {exec} = require("child_process"); |
|
||||
const {promisify} = require("util"); |
|
||||
const promisifiedExec = promisify(exec); |
|
||||
const util = require("../Util"); |
|
||||
|
|
||||
/** |
|
||||
* Delete ufw rule(s). (root/sudo access is mandatory) |
|
||||
* @param {number} num Number of the rules list. The first rule starts from number 1. |
|
||||
* @returns {Promise<Boolean>} Returns a boolean. |
|
||||
*/ |
|
||||
module.exports = async function(num) { |
|
||||
try { |
|
||||
if (!num) throw new Error("Missing num input."); |
|
||||
if (typeof num !== "number") throw new Error("The num must be type of number."); |
|
||||
if (num === 0) num = 1; |
|
||||
|
|
||||
let res = await promisifiedExec(`echo "y" | sudo ufw delete ${num}`); |
|
||||
|
|
||||
if (res.stderr) throw new Error(res.stderr); |
|
||||
|
|
||||
if (res.stdout) { |
|
||||
return true; |
|
||||
} else { |
|
||||
console.log(res.stdout); |
|
||||
return false; |
|
||||
}; |
|
||||
} catch (err) { |
|
||||
throw new Error(err); |
|
||||
}; |
|
||||
}; |
|
@ -1,92 +0,0 @@ |
|||||
const {exec} = require("child_process"); |
|
||||
const {promisify} = require("util"); |
|
||||
const promisifiedExec = promisify(exec); |
|
||||
const util = require("../Util"); |
|
||||
|
|
||||
/** |
|
||||
* Deny incoming requests through specific port. (root/sudo access is mandatory) |
|
||||
* @param {number} port The connection pange. From range 1 - 65535. |
|
||||
* @param {"udp" | "tcp" | undefined} protocol The protocol. |
|
||||
* @returns {Promise<Boolean>} Returns a boolean. |
|
||||
*/ |
|
||||
module.exports.port = async function (port, protocol) { |
|
||||
try { |
|
||||
if (!port) throw new Error("Missing port input."); |
|
||||
if (typeof port !== "number") throw new Error("The port must be type of number."); |
|
||||
|
|
||||
// check port range
|
|
||||
let checkPort = util.checkAppropriatePort(port); |
|
||||
if (!checkPort) return false; |
|
||||
|
|
||||
if (protocol) { |
|
||||
if (typeof protocol !== "string") throw new Error("The protocol must be type of string."); |
|
||||
if (protocol !== "tcp" || protocol !== "udp") throw new Error('The protocol must be either "tcp" or "udp"'); |
|
||||
}; |
|
||||
|
|
||||
let res = await promisifiedExec(`echo "y" | sudo ufw deny ${port}${protocol ? `/${protocol}` : ""}`); |
|
||||
if (res.stderr) throw new Error(res.stderr); |
|
||||
|
|
||||
if (res.stdout) { |
|
||||
// will find a better way to parse this
|
|
||||
if (res.stdout.toLowerCase().match(/(added)/gi)) { |
|
||||
return true; |
|
||||
} else { |
|
||||
console.log(res.stdout); |
|
||||
return false; |
|
||||
}; |
|
||||
} else { |
|
||||
console.log(res.stdout); |
|
||||
return false; |
|
||||
}; |
|
||||
} catch (err) { |
|
||||
throw new Error(err); |
|
||||
}; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Deny incoming requests through specific (IP) address. (root/sudo access is mandatory) |
|
||||
* @param {string} address IP address, supported by subnet/net mask. From range 0.0.0.0 to 255.255.255.255 |
|
||||
* @param {number | undefined} port The connection pange. From range 1 - 65535. |
|
||||
* @param {"udp" | "tcp" | undefined} protocol The protocol. |
|
||||
* @returns {Promise<Boolean>} Returns a boolean. |
|
||||
*/ |
|
||||
module.exports.address = async function (address, port, protocol) { |
|
||||
try { |
|
||||
// address validation
|
|
||||
if (!address) throw new Error("Missing address input."); |
|
||||
if (typeof address !== "string") throw new Error("The address must be type of string."); |
|
||||
let checkAddress = util.checkAppropriateIP(address); |
|
||||
if (!checkAddress) return false; |
|
||||
|
|
||||
// port validation
|
|
||||
if (port) { |
|
||||
if (typeof port !== "number") throw new Error("The port must be type of number."); |
|
||||
let checkPort = util.checkAppropriatePort(port); |
|
||||
if (!checkPort) return false; |
|
||||
}; |
|
||||
|
|
||||
// protocol (tcp/udp) validation
|
|
||||
if (protocol) { |
|
||||
if (typeof protocol !== "string") throw new Error("The protocol must be type of string."); |
|
||||
if (protocol !== "tcp" || protocol !== "udp") throw new Error('The protocol must be either "tcp" or "udp"'); |
|
||||
}; |
|
||||
|
|
||||
let res = await promisifiedExec(`echo "y" | sudo ufw deny from ${address} ${port ? `to any port ${port}` : ""} ${protocol ? `proto ${protocol}` : ""}`); |
|
||||
if (res.stderr) throw new Error(res.stderr); |
|
||||
|
|
||||
if (res.stdout) { |
|
||||
// will find a better way to parse this
|
|
||||
if (res.stdout.toLowerCase().match(/(added)/gi)) { |
|
||||
return true; |
|
||||
} else { |
|
||||
console.log(res.stdout); |
|
||||
return false; |
|
||||
}; |
|
||||
} else { |
|
||||
console.log(res.stdout); |
|
||||
return false; |
|
||||
}; |
|
||||
} catch (err) { |
|
||||
throw new Error(err); |
|
||||
}; |
|
||||
}; |
|
@ -1,36 +0,0 @@ |
|||||
const {exec} = require("child_process"); |
|
||||
const {promisify} = require("util"); |
|
||||
const promisifiedExec = promisify(exec); |
|
||||
const util = require("../Util"); |
|
||||
|
|
||||
/** |
|
||||
* Set/toggle UFW logging. (root/sudo access is mandatory) |
|
||||
* @param {'off' | 'on' | 'low' | 'medium' | 'high' | 'full'} type A type of UFWlogging. |
|
||||
* @returns {Promise<Boolean>} Returns a boolean. |
|
||||
*/ |
|
||||
module.exports = async function(type) { |
|
||||
try { |
|
||||
if (!type) throw new Error("Missing type input."); |
|
||||
if (typeof type !== "string") throw new Error("The type must be type of string."); |
|
||||
|
|
||||
type = type.toLowerCase(); |
|
||||
|
|
||||
// https://manpages.ubuntu.com/manpages/focal/en/man8/ufw.8.html#logging
|
|
||||
let appropriateType = ['off', 'on', 'low', 'medium', 'high', 'full']; |
|
||||
if (!appropriateType.includes(type)) { |
|
||||
throw new Error(`Invalid type. Currently supported: ${appropriateType.join(", ")}`); |
|
||||
}; |
|
||||
|
|
||||
let res = await promisifiedExec(`sudo ufw logging ${type}`); |
|
||||
|
|
||||
if (res.stderr) throw new Error(res.stderr); |
|
||||
|
|
||||
if (res.stdout) { |
|
||||
return true; |
|
||||
} else { |
|
||||
return false; |
|
||||
}; |
|
||||
} catch (err) { |
|
||||
throw new Error(err); |
|
||||
}; |
|
||||
}; |
|
@ -1,24 +0,0 @@ |
|||||
const {exec} = require("child_process"); |
|
||||
const {promisify} = require("util"); |
|
||||
const promisifiedExec = promisify(exec); |
|
||||
const util = require("../Util"); |
|
||||
|
|
||||
/** |
|
||||
* Reloads firewall. (root/sudo access is mandatory) |
|
||||
* @returns {Promise<Boolean>} Returns a boolean. |
|
||||
*/ |
|
||||
module.exports = async function() { |
|
||||
try { |
|
||||
let res = await promisifiedExec(`sudo ufw reload`); |
|
||||
|
|
||||
if (res.stderr) throw new Error(res.stderr); |
|
||||
|
|
||||
if (res.stdout) { |
|
||||
return true; |
|
||||
} else { |
|
||||
return false; |
|
||||
}; |
|
||||
} catch (err) { |
|
||||
throw new Error(err); |
|
||||
}; |
|
||||
}; |
|
@ -1,24 +0,0 @@ |
|||||
const {exec} = require("child_process"); |
|
||||
const {promisify} = require("util"); |
|
||||
const promisifiedExec = promisify(exec); |
|
||||
const util = require("../Util"); |
|
||||
|
|
||||
/** |
|
||||
* Disables and resets firewall to installation defaults. No prompt. Use this wisely. (root/sudo access is mandatory) |
|
||||
* @returns {Promise<Boolean>} Returns a boolean. |
|
||||
*/ |
|
||||
module.exports = async function() { |
|
||||
try { |
|
||||
let res = await promisifiedExec(`sudo ufw --force reset`); |
|
||||
|
|
||||
if (res.stderr) throw new Error(res.stderr); |
|
||||
|
|
||||
if (res.stdout) { |
|
||||
return true; |
|
||||
} else { |
|
||||
return false; |
|
||||
}; |
|
||||
} catch (err) { |
|
||||
throw new Error(err); |
|
||||
}; |
|
||||
}; |
|
@ -1,51 +0,0 @@ |
|||||
const {exec} = require("child_process"); |
|
||||
const {promisify} = require("util"); |
|
||||
const promisifiedExec = promisify(exec); |
|
||||
const util = require("../Util"); |
|
||||
|
|
||||
/** |
|
||||
* List of currently activated ufw. (root/sudo access is mandatory) |
|
||||
* @param {boolean} [raw=false] A raw version of "ufw status" |
|
||||
* @returns {Promise<string | {to: string, action: string, from: string}[]>} Returns a string if "raw" param is included, otherwise a list of array with to/action/from. |
|
||||
*/ |
|
||||
module.exports = async function(raw) { |
|
||||
if (raw && typeof raw !== "boolean") { |
|
||||
throw new Error("The raw must be type of boolean."); |
|
||||
}; |
|
||||
|
|
||||
try { |
|
||||
let res = await promisifiedExec(`sudo ufw status`); |
|
||||
|
|
||||
if (res.stderr) throw new Error(res.stderr); |
|
||||
|
|
||||
if (res.stdout) { |
|
||||
if (!raw) { |
|
||||
let list = []; |
|
||||
|
|
||||
// parsing
|
|
||||
let parsedStatus = res.stdout.replace(/\r|\n/gi, " ").split(/\s{2,}/gi).filter(x => x.length); |
|
||||
if (!parsedStatus.length) return []; |
|
||||
|
|
||||
let findAfterFrom = parsedStatus.findIndex(x => x == "----"); |
|
||||
let afterSlice = parsedStatus.slice(findAfterFrom + 1, parsedStatus.length); |
|
||||
if (!afterSlice.length) return []; |
|
||||
|
|
||||
for (let i = 0; i < afterSlice.length; i++) { |
|
||||
if (i % 3 == 0) { |
|
||||
let to = afterSlice[i]; |
|
||||
let action = afterSlice[i + 1]; |
|
||||
let from = afterSlice[i + 2]; |
|
||||
|
|
||||
list.push({to, action, from}); |
|
||||
}; |
|
||||
}; |
|
||||
|
|
||||
return list; |
|
||||
} else { |
|
||||
return res.stdout; |
|
||||
}; |
|
||||
}; |
|
||||
} catch (err) { |
|
||||
throw new Error(err); |
|
||||
}; |
|
||||
}; |
|
@ -0,0 +1,26 @@ |
|||||
|
{ |
||||
|
"compilerOptions": { |
||||
|
"outDir": "dist", |
||||
|
"module": "CommonJS", |
||||
|
"target": "ESNext", |
||||
|
"inlineSourceMap": true, |
||||
|
"importHelpers": true, |
||||
|
"noFallthroughCasesInSwitch": true, |
||||
|
"noImplicitOverride": true, |
||||
|
"strict": true, |
||||
|
"esModuleInterop": true, |
||||
|
"skipLibCheck": false, |
||||
|
"forceConsistentCasingInFileNames": true, |
||||
|
"moduleResolution": "node", |
||||
|
"allowUnusedLabels": false, |
||||
|
"allowUnreachableCode": false, |
||||
|
"strictPropertyInitialization": true, |
||||
|
"strictBindCallApply": true, |
||||
|
"declaration": true, |
||||
|
"noEmitOnError": true, |
||||
|
"allowSyntheticDefaultImports": true, |
||||
|
"resolveJsonModule": true |
||||
|
}, |
||||
|
"include": ["src/**/*.ts", "src/**/*.d.ts"], |
||||
|
"exclude": ["node_modules", "dist", "test"] |
||||
|
} |
Loading…
Reference in new issue