diff --git a/index.js b/index.js index 146a8a0..66832e5 100644 --- a/index.js +++ b/index.js @@ -1,81 +1,120 @@ -require("dotenv").config({quiet: true}); -const exec = require("child_process").exec; -const Discord = require("discord.js"); +const blocked = [ + '0', + '0000', + '9998', + '9999' +]; + +import dotenv from 'dotenv'; +dotenv.config({ quiet: true }) +import AMISocket from 'ami'; +const sock = new AMISocket({ + connect: { + host: '127.0.0.1', + port: 5038 + }, + credentials: { + username: process.env.AMI_USER, + secret: process.env.AMI_SECRET + }, + events: true +}) +import Discord from 'discord.js'; const hook = new Discord.WebhookClient({ url: process.env.DISCORD_WEBHOOK_URL }); const cfTypes = { - CF: "Unconditional", - CFB: "Busy", - CFU: "Unavailable", + CF: "Unconditional", + CFB: "Busy", + CFU: "Unavailable", } -const main = async () => { - const runAsterisk = (command) => - new Promise((resolve) => - exec(command, (error, stdout, stderr) => resolve({ error, stdout, stderr })) - ); +const main = () => { + var respData = []; + console.log('checking') + // getList for CF, CFB, CFU + sock.getList({ + action: 'DBGetTree', + family: 'CF' + }).then(async (response) => { + // Responses are an array of objects. The first should always have eventlist: 'start', and last should have eventlist: 'complete'. Remove these, make an array of objects {key, val} based on the rest of the response objects. + let entries = response.filter(r => r.eventlist !== 'start' && r.eventlist !== 'Complete').map(r => ({ key: r.key, val: r.val })); + for (let entry of entries) { + let stuff = entry.key.split('/'); + let type = stuff[1]; + let ext = stuff[2]; + console + respData.push({ + extension: ext, + type: type, + target: entry.val + }); + } - try { - var forwards = {}; - const commands = [ - 'asterisk -x "database show CF"', - 'asterisk -x "database show CFB"', - 'asterisk -x "database show CFU"', - ]; - for (const command of commands) { - const { error, stdout, stderr } = await runAsterisk(command); - if (error) { - console.error(`Error executing command "${command}": ${error}`); - continue; - } - - const lines = stdout.split('\n'); - for (const line of lines) { - const match = line.match(/^\/(CF|CFB|CFU)\/(\d+)\s+:\s+(.+)$/); - if (match) { - const type = match[1]; - const extension = match[2]; - const target = match[3]; - - forwards[`${type}/${extension}`] = target.replace(/\s+$/, ''); - } - } - } - - // Search all forwards for any target that is between 700 and 800. If it exists, log to console and run `asterisk -x "database del CF[U/B] "` to delete it - for (const [key, target] of Object.entries(forwards)) { - const targetExt = parseInt(target, 10); - if ((targetExt >= 700 && targetExt < 800) || targetExt === 0) { // Also block forwards to 0 (operator line) - console.log(`Deleting forward ${key} to target ${target}`); - await hook.send(`Fuckass with extension ${key.split('/')[1]} tried to forward to ${target}. ${cfTypes[key.split('/')[0]]} Forward has been deleted.`); - const delCommand = `asterisk -x "database del ${key.replace('/', ' ')}"`; - const { error, stdout, stderr } = await runAsterisk(delCommand); - if (error) { - console.error(`Error executing command "${delCommand}": ${error}`); - } else { - console.log(`Successfully deleted forward ${key}`); - } - } - } - } catch (err) { - console.error(`Unexpected error: ${err}`); - } - setTimeout(main, process.env.CHECK_INTERVAL * 1000); // Run every CHECK_INTERVAL seconds -}; + }).then(() => { + sock.getList({ + action: 'DBGetTree', + family: 'CFB' + }).then(async (response) => { + let entries = response.filter(r => r.eventlist !== 'start' && r.eventlist !== 'Complete').map(r => ({ key: r.key, val: r.val })); + for (let entry of entries) { + let stuff = entry.key.split('/'); + let type = stuff[1]; + let ext = stuff[2]; + console + respData.push({ + extension: ext, + type: type, + target: entry.val + }); + } + }).then(() => { + sock.getList({ + action: 'DBGetTree', + family: 'CFU' + }).then(async (response) => { + let entries = response.filter(r => r.eventlist !== 'start' && r.eventlist !== 'Complete').map(r => ({ key: r.key, val: r.val })); + for (let entry of entries) { + let stuff = entry.key.split('/'); + let type = stuff[1]; + let ext = stuff[2]; + console + respData.push({ + extension: ext, + type: type, + target: entry.val + }); + } + }).then(() => { + console.log(`Found ${respData.length} call forwards.`); + for (let cf of respData) { + // Check if forward target is anything in the 700-800 range, or is a number in the blocked list + if ((cf.target >= 700 && cf.target < 800) || blocked.includes(cf.target)) { + // Violation. Remove call forward from db. + console.log(`---> Violation found on extension ${cf.extension}. Removing call forward to ${cf.target}`); + sock.send({ + action: 'DBDel', + family: cf.type, + key: cf.extension + }).then((resp) => { + console.log(`-----> Call forward removed successfully.`); + hook.send(`:no_entry: **Call Forward Removed** :no_entry:\nExtension **${cf.extension}** had a **${cfTypes[cf.type]}** call forward to **${cf.target}** The call forward has been removed.`); + }) + } + }; + setTimeout(main, 5000); // Repeat every 60 seconds + }); + }); + }) +} const startup = async () => { - // Run `asterisk -x "core show version"` to get the Asterisk version. If it fails, wait 10 seconds before running main again - exec('asterisk -x "core show version"', (error, stdout, stderr) => { - if (error) { - console.error(`Error executing command: ${error}`); - console.log("Asterisk is not running. Retrying in 10 seconds..."); - setTimeout(startup, 10000); - return; - } - const version = stdout.trim(); - console.log(`Asterisk version: ${version}`); - main(); - }); + sock.connect().then(() => { + console.log(sock.amiVersion) + main(); + }).catch((err) => { + console.error('Error connecting to AMI:', err); + setTimeout(startup, 10000); // Retry after 10 seconds + }); } -startup(); \ No newline at end of file +startup(); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 60f06ee..52dd274 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "ami": "^1.0.0", "discord.js": "^14.24.0", "dotenv": "^17.2.3" } @@ -201,6 +202,15 @@ "npm": ">=7.0.0" } }, + "node_modules/ami": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ami/-/ami-1.0.0.tgz", + "integrity": "sha512-wkuxJl8ahQ4FYVwXvtJpQ7wuRUAqD30ueVpeJ1t5UyYqjzh+GtmrnaeHrXzzp+KO3ukhHZoMrsZlKB0j91oAlw==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/discord-api-types": { "version": "0.38.31", "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.31.tgz", diff --git a/package.json b/package.json index 1019a64..3aeccd6 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,9 @@ "keywords": [], "author": "", "license": "ISC", - "type": "commonjs", + "type": "module", "dependencies": { + "ami": "^1.0.0", "discord.js": "^14.24.0", "dotenv": "^17.2.3" }