require("dotenv").config() const Discord = require("discord.js") const Client = new Discord.Client({ intents: [ "DirectMessages" ] }) const { REST, Routes } = require('discord.js'); const rest = new REST({ version: '10' }).setToken(process.env.TOKEN); const axios = require("axios"); const jsondb = require("node-json-db") const db = new jsondb.JsonDB(new jsondb.Config("cache", true, true, "/", true)) db.push const commands = [ { name: "cid", description: "Lookup a CallerID", contexts: [0, 1, 2], integration_types: [0, 1], options: [ { name: "number", description: "The number to look up (11 digit US only!)", type: Discord.ApplicationCommandOptionType.String, required: true }, { name: "show", description: "Whether to show the response to everyone or not.", type: Discord.ApplicationCommandOptionType.Boolean, } ] }, { name: "lrn", description: "Lookup a Local Routing Number", contexts: [0, 1, 2], integration_types: [0, 1], options: [ { name: "did", description: "The number to look up (11 digit US only!)", type: Discord.ApplicationCommandOptionType.String, required: true }, { name: "ani", description: "The ANI to use for the lookup. i.e the caller's number (for routing info) (11 digit US only!)", type: Discord.ApplicationCommandOptionType.String, required: false }, { name: "show", description: "Whether to show the response to everyone or not.", type: Discord.ApplicationCommandOptionType.Boolean, required: false } ] } ] Client.on("ready", async () => { console.log(`Logged in as ${Client.user.displayName}`); await (async () => { try { //Global console.log(`Registering global commands`); await rest.put(Routes.applicationCommands(Client.user.id), { body: commands }) } catch (error) { console.error(error); } })(); }) /** * Converts a T9-style alphanumeric phone number to its numeric equivalent. * Example: "1610LITENET" => "16105483638" * @param {string} input * @returns {string} */ function t9ToNumber(input) { input = String(input).replace(/[^a-zA-Z0-9]/g, ''); const t9 = { A: '2', B: '2', C: '2', D: '3', E: '3', F: '3', G: '4', H: '4', I: '4', J: '5', K: '5', L: '5', M: '6', N: '6', O: '6', P: '7', Q: '7', R: '7', S: '7', T: '8', U: '8', V: '8', W: '9', X: '9', Y: '9', Z: '9' }; let output = String(input).toUpperCase().split('').map(c => t9[c] || (/\d/.test(c) ? c : '') ).join(''); return output.length === 11 ? output : null; // Ensure it's 11 digits } Client.on("interactionCreate", async (interaction) => { switch (interaction.type) { case Discord.InteractionType.ApplicationCommand: switch (interaction.commandName) { case "cid": let show = !interaction.options.getBoolean("show"); if (show == null) show = true; let number = t9ToNumber(interaction.options.getString("number")) if (!/^\d{11}$/.test(number)) return interaction.reply({ ephemeral: true, content: "<:invalid:1305271064993071185> That's not a valid number! (11 digit US only)" }); if (await db.exists(`/cache/${number}`)) { cached = await db.getData(`/cache/${number}`); } else { cached = {} } if (!cached.cnam || new Date() > new Date(cached?.expires)) { // Old, get from API interaction.reply({ ephemeral: show, content: `<:checking:1305271116134092842> Looking up \`${number}\`` }).then(() => { axios.get(process.env.CNAM_API_URL.replaceAll("%n", number)).then((response) => { db.push(`/cache/${number}`, { timestamp: new Date(), expires: new Date(new Date().getTime() + 7 * 24 * 60 * 60 * 1000), cnam: response.data }); interaction.editReply({ ephemeral: show, content: `<:success:1305271084806963220> CNAM for \`${number}\` is \`${response.data}\`` }) }).catch((err) => { interaction.editReply({ ephemeral: show, content: `<:server_error:1305271074551758868> There was a server error when trying to get that!` }) }) }); } else { // Spit out cached version interaction.reply({ ephemeral: show, content: `<:cached:1305276187966443612> CNAM for \`${number}\` is \`${cached.cnam}\`\n-# This was cached ` }) } break; case "lrn": let showLrn = !interaction.options.getBoolean("show"); if (showLrn == null) showLrn = true; let did = t9ToNumber(interaction.options.getString("did")) if (!/^\d{11}$/.test(did)) return interaction.reply({ ephemeral: true, content: "<:invalid:1305271064993071185> That's not a valid number! (11 digit US only)" }); let ani = t9ToNumber(interaction.options.getString("ani")) || null; if (ani && !/^\d{11}$/.test(ani)) { return interaction.reply({ ephemeral: true, content: "<:invalid:1305271064993071185> That's not a valid ANI! (11 digit US only)" }); } if (await db.exists(`/lrncache/${did}`)) { cached = await db.getData(`/lrncache/${did}`); } else { cached = {} } if (!cached.lrn || new Date() > new Date(cached?.expires) || ani) { // Old, get from API interaction.reply({ ephemeral: showLrn, content: `<:checking:1305271116134092842> Looking up \`${did}\`` }).then(() => { axios.get(process.env.LRN_API_URL.replaceAll("%did", did).replaceAll("%ani", ani || "")).then((response) => { let lrn = response.data; /*lrn data: {"tn":"15809197945","lrn":"15809197945","ocn":"5813","lata":"536","city":"LAWTON","ratecenter":"LAWTON","province":"OK","jurisdiction":"INDETERMINATE","local":"INDETERMINATE","lec":"CELLCO PARTNERSHIP DBA VERIZON WIRELESS - OK","lectype":"WIRELESS","spid":"6006","activation":"1241582400"} */ db.push(`/lrncache/${did}`, { timestamp: new Date(), expires: new Date(new Date().getTime() + 7 * 24 * 60 * 60 * 1000), // 7 days lrn }); interaction.editReply({ content: `<:success:1305271084806963220> LRN for \`${did}\` is \`${lrn.lrn}\``, ephemeral: showLrn, embeds: [{ title: `LRN for ${did}`, fields: [ { name: "LRN", value: `\`${lrn.lrn}\`` || "`NULL`", inline: true }, { name: "OCN", value: `\`${lrn.ocn}\`` || "`NULL`", inline: true }, { name: "LATA", value: `\`${lrn.lata}\`` || "`NULL`", inline: true }, { name: "City", value: `\`${lrn.city}\`` || "`NULL`", inline: true }, { name: "Rate Center", value: `\`${lrn.ratecenter}\`` || "`NULL`", inline: true }, { name: "Province", value: `\`${lrn.province}\`` || "`NULL`", inline: true }, { name: "Jurisdiction", value: `\`${lrn.jurisdiction}\`` || "`NULL`", inline: true }, { name: "Local", value: `\`${lrn.local}\`` || "`NULL`", inline: true }, { name: "LEC", value: `\`${lrn.lec}\`` || "`NULL`", inline: true }, { name: "LEC Type", value: `\`${lrn.lectype}\`` || "`NULL`", inline: true }, { name: "SPID", value: `\`${lrn.spid}\`` || "`NULL`", inline: true }, { name: "Activation Date", value: `` } ], footer: { text: "This data is provided by the LRN API" }, color: 0x00FF00 }] }) }).catch((err) => { console.error(err); interaction.editReply({ ephemeral: showLrn, content: `<:server_error:1305271074551758868> There was a server error when trying to get that!` }) }) }); } else { // Spit out cached version let lrn = cached.lrn; interaction.reply({ content: `<:cached:1305276187966443612> LRN for \`${did}\``, ephemeral: showLrn, embeds: [{ title: `LRN for ${did}`, fields: [ { name: "LRN", value: `\`${lrn.lrn}\`` || "`NULL`", inline: true }, { name: "OCN", value: `\`${lrn.ocn}\`` || "`NULL`", inline: true }, { name: "LATA", value: `\`${lrn.lata}\`` || "`NULL`", inline: true }, { name: "City", value: `\`${lrn.city}\`` || "`NULL`", inline: true }, { name: "Rate Center", value: `\`${lrn.ratecenter}\`` || "`NULL`", inline: true }, { name: "Province", value: `\`${lrn.province}\`` || "`NULL`", inline: true }, { name: "Jurisdiction", value: `\`${lrn.jurisdiction}\`` || "`NULL`", inline: true }, { name: "Local", value: `\`${lrn.local}\`` || "`NULL`", inline: true }, { name: "LEC", value: `\`${lrn.lec}\`` || "`NULL`", inline: true }, { name: "LEC Type", value: `\`${lrn.lectype}\`` || "`NULL`", inline: true }, { name: "SPID", value: `\`${lrn.spid}\`` || "`NULL`", inline: true }, { name: "Activation Date", value: `` } ], footer: { text: "This is cached data. Cached" }, timestamp: new Date(cached.timestamp).toISOString(), color: 0x00FF00 }] }) } break; } } }); Client.login(process.env.TOKEN)