commit 26d4837e0d3022a416c2f150d6c4058f11a72bfb Author: ChrisChrome Date: Wed Apr 10 10:44:35 2024 -0600 Yay diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ad9f4b --- /dev/null +++ b/.gitignore @@ -0,0 +1,134 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +config* +!config.json.default +defcon.txt \ No newline at end of file diff --git a/config.json.default b/config.json.default new file mode 100644 index 0000000..374b423 --- /dev/null +++ b/config.json.default @@ -0,0 +1,60 @@ +{ + "debug": false, + "discord": { + "token": "", + "status_messages": [ + { + "comment": "Main status", + "channel_id": "", + "message_id": "" + }, + { + "comment": "Voice Status", + "channel_id": "", + "change_name": true + } + ], + "actionable_servers": [""], + "slowmodes": [ + { + "comment": "main chat", + "channel_id": "", + "slowmode": 60, + "defaultSlowmode": 0 + } + ], + "slowmode_categories": [ + { + "comment": "Main Chat rooms", + "category_id": "", + "slowmode": 60, + "defaultSlowmode": 0 + } + ], + "invitelog": "" + }, + "DEFCON": { + "levels": { + "1": { + "color": "#ec3e40", + "message": "**DEFCON 1** - High Alert, Full Lockdown. Break all Discord Invites and lock down the SL Server if necessary." + }, + "2": { + "color": "#ff9b2b", + "message": "**DEFCON 2** - High Alert, Server invite links are locked, Discord server chats are heavily monitored (i.e. slowmodes, active moderation)." + }, + "3": { + "color": "#f5d800", + "message": "**DEFCON 3** - Moderate Alert, Server invites are locked." + }, + "4": { + "color": "#377fc7", + "message": "**DEFCON 4** - Moderate Alert, Server invites are monitored for suspicious individuals." + }, + "5": { + "color": "#01a46d", + "message": "**DEFCON 5** - Low Alert, Normal Operations." + } + } + } +} \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..74b9280 --- /dev/null +++ b/index.js @@ -0,0 +1,417 @@ +const config = require("./config"); +const fs = require("fs"); +const Discord = require("discord.js"); +const colors = require("colors"); + +const { + REST, + Routes +} = require('discord.js'); +const dcClient = new Discord.Client({ + intents: ["Guilds", "GuildMembers"] +}); +const rest = new REST({ + version: '10' +}).setToken(config.discord.token); + +const client = new Discord.Client({ + intents: [ + "Guilds", + "GuildInvites", + "AutoModerationConfiguration", + "AutoModerationExecution", + "GuildMembers", + "GuildModeration", + ] +}); + +// First time bullshit +if (!fs.existsSync("config.json")) { + // Copy config.json.default, then process.exit(1) after telling the user to fill it out + fs.copyFileSync("config.json.default", "config.json"); + console.log(`${colors.red("[ERROR]")} config.json not found. Please fill out config.json and restart the bot.`); + process.exit(1); +} + +if (!fs.existsSync("defcon.txt")) { + // Just make the file, default to lvl 1 + fs.writeFileSync("defcon.txt", "5"); +} + +/* +DEFCON Levels: +DEFCON 5 - Low Alert, Normal Operations. +DEFCON 4 - Moderate Alert, Server invites are monitored for suspicious individuals. +DEFCON 3 - Moderate Alert, Server invites are locked. +DEFCON 2 - High Alert, Server invite links are locked, Discord server chats are heavily monitored (i.e. slowmodes, active moderation). +DEFCON 1 - High Alert, Full Lockdown. Break all Discord Invites and lock down the SL Server if necessary. +*/ + +// get DEFCON level from file +let defcon = fs.readFileSync("defcon.txt", "utf8"); + +// DEFCON Functions, Set up server the way it needs to per DEFCON level +function updateDefcon(level) { + // Safety check + if (defcon > 5 || defcon < 1) { + defcon = 5; + } + // Update the file + fs.writeFileSync("defcon.txt", level); + // Update the variable + defcon = level; + // Update the bot's status + // client.user.setPresence({ + // activities: [{ + // name: `DEFCON ${level}`, + // type: Discord.ActivityType.Custom + // }] + // }) + // Update the status messages + updateStatusMessages(); + updateSlowmodes(); + + // if defcon 2 or lower, disable invites + if (level <= 3) { + actionable_servers.forEach((server) => { + server.disableInvites(true) + }); + } else { + actionable_servers.forEach((server) => { + server.disableInvites(false) + }); + } + +} + +// function updateSlowmodes() { +// if (defcon >= 3) { +// // Disable slowmodes +// slowmode_channels.forEach(async (channel) => { +// if (channel.channel.type == Discord.ChannelType.GuildCategory) { +// channel.channel.guild.channels.cache.forEach((chan) => { +// if (chan.parentId == channel.channel.id) { +// chan.setRateLimitPerUser(channel.defaultTime); +// } +// }) +// } else { +// return channel.channel.setRateLimitPerUser(channel.defaultTime); +// } +// }); +// } else if (defcon < 3) { +// // Enable slowmodes +// slowmode_channels.forEach(async (channel) => { +// if (channel.channel.type == Discord.ChannelType.GuildCategory) { +// // find all channels that have this category as a parent and set slowmode, gotta wait for the promise to resolve +// channel.channel.guild.channels.cache.forEach((chan) => { +// if (chan.parentId == channel.channel.id) { +// chan.setRateLimitPerUser(channel.time); +// } +// }) + +// } else { +// return channel.channel.setRateLimitPerUser(channel.time); +// } +// }); +// } +// } + +// Redo slowmodes, this time categories are separate, do those first. Still have to loop thru all channels in the guild and check if it has the category as a parent +function updateSlowmodes() { + if (defcon >= 3) { + // Disable slowmodes + slowmode_categories.forEach(async (category) => { + category.category.guild.channels.cache.forEach((chan) => { + if (chan.parentId == category.category.id) { + chan.setRateLimitPerUser(category.defaultTime); + } + }) + }); + + slowmode_channels.forEach(async (channel) => { + return channel.channel.setRateLimitPerUser(channel.defaultTime); + }) + } else { + // Enable slowmodes + slowmode_categories.forEach(async (category) => { + category.category.guild.channels.cache.forEach((chan) => { + if (chan.parentId == category.category.id) { + chan.setRateLimitPerUser(category.time); + } + }) + }); + + slowmode_channels.forEach(async (channel) => { + return channel.channel.setRateLimitPerUser(channel.time); + }) + } +} + +function updateStatusMessages() { + let message = config.DEFCON.levels[defcon].message; + let color = config.DEFCON.levels[defcon].color; + // strip # from color and parseInt + color = parseInt(color.replace("#", ""), 16); + status_messages.forEach((msg) => { + msg.edit({ + content: "", + embeds: [{ + title: "DEFCON Status", + description: message, + color: color + }] + }) + }); + status_names.forEach((channel) => { + if (!channel.type == Discord.ChannelType.GuildVoice) return console.log(`${colors.red("[ERROR]")} Channel ${channel.name} is not a voice channel.`); + channel.setName(`[ DEFCON ${defcon} ]`).catch((err) => { + console.log(`${colors.red("[ERROR]")} Could not set channel name for ${channel.name}.`); + }); + }); +} + + +// Setup some global variables +let status_messages = []; +let status_names = []; +let actionable_servers = []; +let slowmode_channels = []; +let slowmode_categories = []; + +client.on("ready", async () => { + console.log(`${colors.cyan("[INFO]")} Logged in as ${client.user.tag}`); + // Get status messages and actionable servers + config.discord.status_messages.forEach((msg) => { + // try to get the channel, then message, then push the msg to status_messages, if the channel or message doesnt exist, just return + let channel = client.channels.cache.get(msg.channel_id); + if (!channel) { + console.log(`${colors.red("[ERROR]")} Channel ${msg.channel} not found. Skipping, please use /msg to send a message to the channel.`); + return; + } + + if (msg.change_name) { + // if name is set, add it to status_names, then skip the rest + console.log(`${colors.green("[INFO]")} Found channel name change for ${channel.name}.`) + return status_names.push(channel); + } + console.log(`${colors.green("[INFO]")} Found status message for ${channel.name}.`) + // fetch the message id, if it doesnt exist, throw error + channel.messages.fetch(msg.message_id).then((message) => { + status_messages.push(message); + }).catch((err) => { + console.log(`${colors.red("[ERROR]")} Message ${msg.message} not found in channel ${msg.channel}. Skipping, please use /msg to send a message to the channel.`); + return; + }); + + }) + config.discord.actionable_servers.forEach((server) => { + let guild = client.guilds.cache.get(server); + actionable_servers.push(guild); + }) + // Get slowmode channels + config.discord.slowmodes.forEach((channel) => { + let chan = client.channels.cache.get(channel.channel_id); + if (!chan) { + console.log(`${colors.red("[ERROR]")} Slowmode channel ${channel.channel_id} not found.`); + return; + } + slowmode_channels.push({ channel: chan, time: channel.slowmode, defaultTime: channel.defaultSlowmode }); + }); + config.discord.slowmode_categories.forEach((category) => { + let cat = client.channels.cache.get(category.category_id); + if (!cat) { + console.log(`${colors.red("[ERROR]")} Slowmode category ${category.category_id} not found.`); + return; + } + slowmode_categories.push({ category: cat, time: category.slowmode, defaultTime: category.defaultSlowmode }); + }); + + //console.log(`Went through all guilds and channels:\nGuilds:\n${actionable_servers.map((server) => server.name).join("\n")}\nChannels:\n${slowmode_channels.map((channel.channel) => channel.name).join("\n")}`); + updateDefcon(defcon); + client.invites = []; + // Update Invites + client.guilds.cache.forEach(guild => { //on bot start, fetch all guilds and fetch all invites to store + guild.invites.fetch().then(guildInvites => { + guildInvites.each(guildInvite => { + client.invites[guildInvite.code] = guildInvite.uses + }) + }) + }) + + const commands = [ + { + name: "defcon", + description: "Set the DEFCON level.", + default_member_permissions: 0, + options: [ + { + name: "level", + description: "The DEFCON level to set.", + type: 3, + required: true, + choices: [ + { + name: "DEFCON 5", + value: "5" + }, + { + name: "DEFCON 4", + value: "4" + }, + { + name: "DEFCON 3", + value: "3" + }, + { + name: "DEFCON 2", + value: "2" + }, + { + name: "DEFCON 1", + value: "1" + } + ] + }, + { + name: "confirm1", + description: "Confirm the DEFCON level change.", + type: 5, + required: true + }, + { + name: "confirm2", + description: "Are you REALLY sure?", + type: 5, + required: true + } + ] + }, + { + name: "msg", + description: "Send a message to a channel.", + default_member_permissions: 0 + } + ] + // Do slash command stuff + await (async () => { + try { + console.log(`${colors.cyan("[INFO]")} Registering Commands...`) + let start = Date.now() + //Global + await rest.put(Routes.applicationCommands(client.user.id), { body: commands }) + console.log(`${colors.cyan("[INFO]")} Successfully registered commands. Took ${colors.green((Date.now() - start) / 1000)} seconds.`); + } catch (error) { + console.error(error); + } + })(); +}); + +client.on('interactionCreate', async interaction => { + if (!interaction.isCommand()) return; + + let command = interaction.commandName; + + switch (command) { + case "defcon": + // Update defcon + let level = interaction.options.getString("level"); + newLevel = new Number(level); + // if number not between 1 and 5 send error + if (newLevel < 1 || newLevel > 5) { + interaction.reply({ content: "Invalid DEFCON level. Please choose a number between 1 and 5.", ephemeral: true }); + return; + } + updateDefcon(level); + + // Send response + interaction.reply({ content: `Successfully set DEFCON level to ${level}.`, ephemeral: true }); + break; + case "msg": + // Send message to channel + interaction.channel.send("...").then((msg) => { + interaction.reply(msg.id) + }) + break; + } +}); + +client.on('inviteCreate', (invite) => { //if someone creates an invite while bot is running, update store + client.invites[invite.code] = invite.uses + if (defcon > 4) return; // Dont need to send new invite messages if we're not monitoring invites + const channel = client.channels.cache.get(config.discord.invitelog) + channel.send({ + embeds: [{ + color: 0x00ffff, + title: "New Invite", + fields: [ + { + name: "Invite", + // inline check, if expiry is in over 100 years, then it's never, otherwise it's the date + // ${invite.expiresTimestamp > 95617584000 ? "Never" : `` + value: `Code: ${invite.code}\nMax Uses: ${invite.maxUses}\nExpires ${invite.expiresAt}\nCreated at: ${invite.createdAt}` + }, + { + name: "Guild", + value: `${invite.guild.name}\n\`${invite.guild.id}\`` + }, + { + name: "Channel", + value: `${invite.channel.name}\n\`${invite.channel.id}\` <#${invite.channel.id}>` + }, + { + name: "Inviter", + value: `${invite.inviter}\n\`${invite.inviter.id}\`` + } + ] + }] + }); +}); + +client.on('guildMemberAdd', async (member) => { // We're just gonna always send invite logs, even if we're not monitoring them + const channel = client.channels.cache.get(config.discord.invitelog) + let guild = member.guild + member.guild.invites.fetch().then(guildInvites => { //get all guild invites + guildInvites.each(invite => { //basically a for loop over the invites + if (invite.uses != client.invites[invite.code]) { //if it doesn't match what we stored: + channel.send({ + embeds: [{ + color: 0x00ff00, + title: "New Member", + fields: [ + { + name: "New Member", + value: `${member}\n\`${member.id}\`\nJoined at: \nAccount Created: ` + }, + { + name: "Invite", + value: `Inviter: ${invite.inviter} (${invite.inviter.id})\nCode: ${invite.code}\nUses: ${invite.uses}` + }, + { + name: "Guild", + value: `${guild.name}\n\`${guild.id}\`` + } + ] + }] + }); + client.invites[invite.code] = invite.uses + } + }) + }) + + if (defcon <= 4) { + // DM user saying Invites are disabled for security reasons, then kick them with the same reason + member.send("Invites are currently disabled for security reasons. Please contact a staff member for assistance.").then(() => { + member.kick(`DEFCON ${defcon}`); + channel.send({ + embeds: [{ + color: 0xff0000, + title: "Member Kicked", + description: `${member.user.username} was kicked` + }] + }); + }); + + } +}) + +client.login(config.discord.token) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..221e795 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,486 @@ +{ + "name": "discord-defcon", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "discord-defcon", + "version": "1.0.0", + "license": "GPL-3.0-or-later", + "dependencies": { + "colors": "^1.4.0", + "discord.js": "^14.14.1" + } + }, + "node_modules/@discordjs/builders": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.7.0.tgz", + "integrity": "sha512-GDtbKMkg433cOZur8Dv6c25EHxduNIBsxeHrsRoIM8+AwmEZ8r0tEpckx/sHwTLwQPOF3e2JWloZh9ofCaMfAw==", + "dependencies": { + "@discordjs/formatters": "^0.3.3", + "@discordjs/util": "^1.0.2", + "@sapphire/shapeshift": "^3.9.3", + "discord-api-types": "0.37.61", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/collection": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", + "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/formatters": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.3.tgz", + "integrity": "sha512-wTcI1Q5cps1eSGhl6+6AzzZkBBlVrBdc9IUhJbijRgVjCNIIIZPgqnUj3ntFODsHrdbGU8BEG9XmDQmgEEYn3w==", + "dependencies": { + "discord-api-types": "0.37.61" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/rest": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.2.0.tgz", + "integrity": "sha512-nXm9wT8oqrYFRMEqTXQx9DUTeEtXUDMmnUKIhZn6O2EeDY9VCdwj23XCPq7fkqMPKdF7ldAfeVKyxxFdbZl59A==", + "dependencies": { + "@discordjs/collection": "^2.0.0", + "@discordjs/util": "^1.0.2", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.5.1", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.61", + "magic-bytes.js": "^1.5.0", + "tslib": "^2.6.2", + "undici": "5.27.2" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/rest/node_modules/@discordjs/collection": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.0.0.tgz", + "integrity": "sha512-YTWIXLrf5FsrLMycpMM9Q6vnZoR/lN2AWX23/Cuo8uOOtS8eHB2dyQaaGnaF8aZPYnttf2bkLMcXn/j6JUOi3w==", + "engines": { + "node": ">=18" + } + }, + "node_modules/@discordjs/util": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.2.tgz", + "integrity": "sha512-IRNbimrmfb75GMNEjyznqM1tkI7HrZOf14njX7tCAAUetyZM1Pr8hX/EK2lxBCOgWDRmigbp24fD1hdMfQK5lw==", + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/ws": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.2.tgz", + "integrity": "sha512-+XI82Rm2hKnFwAySXEep4A7Kfoowt6weO6381jgW+wVdTpMS/56qCvoXyFRY0slcv7c/U8My2PwIB2/wEaAh7Q==", + "dependencies": { + "@discordjs/collection": "^2.0.0", + "@discordjs/rest": "^2.1.0", + "@discordjs/util": "^1.0.2", + "@sapphire/async-queue": "^1.5.0", + "@types/ws": "^8.5.9", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.61", + "tslib": "^2.6.2", + "ws": "^8.14.2" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/ws/node_modules/@discordjs/collection": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.0.0.tgz", + "integrity": "sha512-YTWIXLrf5FsrLMycpMM9Q6vnZoR/lN2AWX23/Cuo8uOOtS8eHB2dyQaaGnaF8aZPYnttf2bkLMcXn/j6JUOi3w==", + "engines": { + "node": ">=18" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@sapphire/async-queue": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.2.tgz", + "integrity": "sha512-7X7FFAA4DngXUl95+hYbUF19bp1LGiffjJtu7ygrZrbdCSsdDDBaSjB7Akw0ZbOu6k0xpXyljnJ6/RZUvLfRdg==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/shapeshift": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.7.tgz", + "integrity": "sha512-4It2mxPSr4OGn4HSQWGmhFMsNFGfFVhWeRPCRwbH972Ek2pzfGRZtb0pJ4Ze6oIzcyh2jw7nUDa6qGlWofgd9g==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v16" + } + }, + "node_modules/@sapphire/snowflake": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", + "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@types/node": { + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/ws": { + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.9.tgz", + "integrity": "sha512-jbdrY0a8lxfdTp/+r7Z4CkycbOFN8WX+IOchLJr3juT/xzbJ8URyTVSJ/hvNdadTgM1mnedb47n+Y31GsFnQlg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vladfrangu/async_event_emitter": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.4.tgz", + "integrity": "sha512-ButUPz9E9cXMLgvAW8aLAKKJJsPu1dY1/l/E8xzLFuysowXygs6GBcyunK9rnGC4zTsnIc2mQo71rGw9U+Ykug==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/discord-api-types": { + "version": "0.37.61", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.61.tgz", + "integrity": "sha512-o/dXNFfhBpYHpQFdT6FWzeO7pKc838QeeZ9d91CfVAtpr5XLK4B/zYxQbYgPdoMiTDvJfzcsLW5naXgmHGDNXw==" + }, + "node_modules/discord.js": { + "version": "14.14.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.14.1.tgz", + "integrity": "sha512-/hUVzkIerxKHyRKopJy5xejp4MYKDPTszAnpYxzVVv4qJYf+Tkt+jnT2N29PIPschicaEEpXwF2ARrTYHYwQ5w==", + "dependencies": { + "@discordjs/builders": "^1.7.0", + "@discordjs/collection": "1.5.3", + "@discordjs/formatters": "^0.3.3", + "@discordjs/rest": "^2.1.0", + "@discordjs/util": "^1.0.2", + "@discordjs/ws": "^1.0.2", + "@sapphire/snowflake": "3.5.1", + "@types/ws": "8.5.9", + "discord-api-types": "0.37.61", + "fast-deep-equal": "3.1.3", + "lodash.snakecase": "4.1.1", + "tslib": "2.6.2", + "undici": "5.27.2", + "ws": "8.14.2" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" + }, + "node_modules/magic-bytes.js": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.10.0.tgz", + "integrity": "sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ==" + }, + "node_modules/ts-mixer": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", + "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==" + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/undici": { + "version": "5.27.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz", + "integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + }, + "dependencies": { + "@discordjs/builders": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.7.0.tgz", + "integrity": "sha512-GDtbKMkg433cOZur8Dv6c25EHxduNIBsxeHrsRoIM8+AwmEZ8r0tEpckx/sHwTLwQPOF3e2JWloZh9ofCaMfAw==", + "requires": { + "@discordjs/formatters": "^0.3.3", + "@discordjs/util": "^1.0.2", + "@sapphire/shapeshift": "^3.9.3", + "discord-api-types": "0.37.61", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.3", + "tslib": "^2.6.2" + } + }, + "@discordjs/collection": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", + "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==" + }, + "@discordjs/formatters": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.3.tgz", + "integrity": "sha512-wTcI1Q5cps1eSGhl6+6AzzZkBBlVrBdc9IUhJbijRgVjCNIIIZPgqnUj3ntFODsHrdbGU8BEG9XmDQmgEEYn3w==", + "requires": { + "discord-api-types": "0.37.61" + } + }, + "@discordjs/rest": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.2.0.tgz", + "integrity": "sha512-nXm9wT8oqrYFRMEqTXQx9DUTeEtXUDMmnUKIhZn6O2EeDY9VCdwj23XCPq7fkqMPKdF7ldAfeVKyxxFdbZl59A==", + "requires": { + "@discordjs/collection": "^2.0.0", + "@discordjs/util": "^1.0.2", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.5.1", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.61", + "magic-bytes.js": "^1.5.0", + "tslib": "^2.6.2", + "undici": "5.27.2" + }, + "dependencies": { + "@discordjs/collection": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.0.0.tgz", + "integrity": "sha512-YTWIXLrf5FsrLMycpMM9Q6vnZoR/lN2AWX23/Cuo8uOOtS8eHB2dyQaaGnaF8aZPYnttf2bkLMcXn/j6JUOi3w==" + } + } + }, + "@discordjs/util": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.2.tgz", + "integrity": "sha512-IRNbimrmfb75GMNEjyznqM1tkI7HrZOf14njX7tCAAUetyZM1Pr8hX/EK2lxBCOgWDRmigbp24fD1hdMfQK5lw==" + }, + "@discordjs/ws": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.2.tgz", + "integrity": "sha512-+XI82Rm2hKnFwAySXEep4A7Kfoowt6weO6381jgW+wVdTpMS/56qCvoXyFRY0slcv7c/U8My2PwIB2/wEaAh7Q==", + "requires": { + "@discordjs/collection": "^2.0.0", + "@discordjs/rest": "^2.1.0", + "@discordjs/util": "^1.0.2", + "@sapphire/async-queue": "^1.5.0", + "@types/ws": "^8.5.9", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.61", + "tslib": "^2.6.2", + "ws": "^8.14.2" + }, + "dependencies": { + "@discordjs/collection": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.0.0.tgz", + "integrity": "sha512-YTWIXLrf5FsrLMycpMM9Q6vnZoR/lN2AWX23/Cuo8uOOtS8eHB2dyQaaGnaF8aZPYnttf2bkLMcXn/j6JUOi3w==" + } + } + }, + "@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==" + }, + "@sapphire/async-queue": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.2.tgz", + "integrity": "sha512-7X7FFAA4DngXUl95+hYbUF19bp1LGiffjJtu7ygrZrbdCSsdDDBaSjB7Akw0ZbOu6k0xpXyljnJ6/RZUvLfRdg==" + }, + "@sapphire/shapeshift": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.7.tgz", + "integrity": "sha512-4It2mxPSr4OGn4HSQWGmhFMsNFGfFVhWeRPCRwbH972Ek2pzfGRZtb0pJ4Ze6oIzcyh2jw7nUDa6qGlWofgd9g==", + "requires": { + "fast-deep-equal": "^3.1.3", + "lodash": "^4.17.21" + } + }, + "@sapphire/snowflake": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", + "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==" + }, + "@types/node": { + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "requires": { + "undici-types": "~5.26.4" + } + }, + "@types/ws": { + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.9.tgz", + "integrity": "sha512-jbdrY0a8lxfdTp/+r7Z4CkycbOFN8WX+IOchLJr3juT/xzbJ8URyTVSJ/hvNdadTgM1mnedb47n+Y31GsFnQlg==", + "requires": { + "@types/node": "*" + } + }, + "@vladfrangu/async_event_emitter": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.4.tgz", + "integrity": "sha512-ButUPz9E9cXMLgvAW8aLAKKJJsPu1dY1/l/E8xzLFuysowXygs6GBcyunK9rnGC4zTsnIc2mQo71rGw9U+Ykug==" + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + }, + "discord-api-types": { + "version": "0.37.61", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.61.tgz", + "integrity": "sha512-o/dXNFfhBpYHpQFdT6FWzeO7pKc838QeeZ9d91CfVAtpr5XLK4B/zYxQbYgPdoMiTDvJfzcsLW5naXgmHGDNXw==" + }, + "discord.js": { + "version": "14.14.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.14.1.tgz", + "integrity": "sha512-/hUVzkIerxKHyRKopJy5xejp4MYKDPTszAnpYxzVVv4qJYf+Tkt+jnT2N29PIPschicaEEpXwF2ARrTYHYwQ5w==", + "requires": { + "@discordjs/builders": "^1.7.0", + "@discordjs/collection": "1.5.3", + "@discordjs/formatters": "^0.3.3", + "@discordjs/rest": "^2.1.0", + "@discordjs/util": "^1.0.2", + "@discordjs/ws": "^1.0.2", + "@sapphire/snowflake": "3.5.1", + "@types/ws": "8.5.9", + "discord-api-types": "0.37.61", + "fast-deep-equal": "3.1.3", + "lodash.snakecase": "4.1.1", + "tslib": "2.6.2", + "undici": "5.27.2", + "ws": "8.14.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" + }, + "magic-bytes.js": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.10.0.tgz", + "integrity": "sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ==" + }, + "ts-mixer": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", + "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==" + }, + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "undici": { + "version": "5.27.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz", + "integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==", + "requires": { + "@fastify/busboy": "^2.0.0" + } + }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "requires": {} + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..db2c8f1 --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "discord-defcon", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "GPL-3.0-or-later", + "dependencies": { + "colors": "^1.4.0", + "discord.js": "^14.14.1" + } +}