forked from engineering/cloudservices
Stuff?
parent
3942e96524
commit
246944c3ce
|
@ -2,3 +2,4 @@ node_modules
|
|||
yarn.lock
|
||||
src/config.json
|
||||
package-lock.json
|
||||
htmlEmail_templates
|
|
@ -3,10 +3,10 @@ import mongoose from 'mongoose';
|
|||
import signale from 'signale';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import { config, Util } from '.';
|
||||
import { config } from '.';
|
||||
import { Account, AccountInterface, Moderation, ModerationInterface, Domain, DomainInterface } from './models';
|
||||
import { emojis } from './stores';
|
||||
import { Command } from './class';
|
||||
import { Command, Util } from './class';
|
||||
|
||||
|
||||
export default class Client extends Eris.Client {
|
||||
|
@ -27,6 +27,7 @@ export default class Client extends Eris.Client {
|
|||
constructor() {
|
||||
super(config.token, { getAllUsers: true, restMode: true, defaultImageFormat: 'png' });
|
||||
|
||||
process.title = 'cloudservices';
|
||||
this.config = config;
|
||||
this.util = new Util(this);
|
||||
this.commands = new Map();
|
||||
|
@ -39,13 +40,21 @@ export default class Client extends Eris.Client {
|
|||
displayTimestamp: true,
|
||||
displayFilename: true,
|
||||
});
|
||||
this.events();
|
||||
this.loadFunctions();
|
||||
this.init();
|
||||
}
|
||||
|
||||
private async events() {
|
||||
process.on('unhandledRejection', (error) => {
|
||||
this.signale.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
private async loadFunctions() {
|
||||
const functions = await fs.readdir('./functions');
|
||||
functions.forEach(async (func) => {
|
||||
if (func === 'index.ts') return;
|
||||
try {
|
||||
require(`./functions/${func}`).default(this);
|
||||
} catch (error) {
|
||||
|
@ -57,7 +66,8 @@ export default class Client extends Eris.Client {
|
|||
public loadCommand(commandPath: string) {
|
||||
// eslint-disable-next-line no-useless-catch
|
||||
try {
|
||||
const command = new (require(commandPath))(this);
|
||||
// eslint-disable-next-line
|
||||
const command = new (require(commandPath).default)(this);
|
||||
this.commands.set(command.name, command);
|
||||
this.signale.complete(`Loaded command ${command.name}`);
|
||||
} catch (err) { throw err; }
|
||||
|
@ -67,17 +77,24 @@ export default class Client extends Eris.Client {
|
|||
const evtFiles = await fs.readdir('./events/');
|
||||
const commands = await fs.readdir(path.join(__dirname, './commands/'));
|
||||
commands.forEach((command) => {
|
||||
if (command === 'index.js') return;
|
||||
this.loadCommand(`./commands/${command}`);
|
||||
});
|
||||
|
||||
evtFiles.forEach((file) => {
|
||||
const eventName = file.split('.')[0];
|
||||
const event = new (require(`./events/${file}`))(this);
|
||||
if (file === 'index.js') return;
|
||||
// eslint-disable-next-line
|
||||
const event = new (require(`./events/${file}`).default)(this);
|
||||
this.signale.complete(`Loaded event ${eventName}`);
|
||||
this.on(eventName, (...args) => event.run(...args));
|
||||
delete require.cache[require.resolve(`./events/${file}`)];
|
||||
});
|
||||
|
||||
this.connect();
|
||||
await mongoose.connect(config.mongoURL, { useNewUrlParser: true, useUnifiedTopology: true });
|
||||
await this.connect();
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
new Client();
|
||||
|
|
|
@ -28,5 +28,6 @@ export default class Command {
|
|||
this.aliases = [];
|
||||
this.guildOnly = true;
|
||||
this.client = client;
|
||||
this.permissions = {};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,16 +33,24 @@ export default class RichEmbed {
|
|||
thumbnail?: { url?: string, proxy_url?: string, height?: number, width?: number }, video?: { url?: string, height?: number, width?: number },
|
||||
provider?: { name?: string, url?: string}, author?: { name?: string, url?: string, proxy_icon_url?: string, icon_url?: string},
|
||||
} = {}) {
|
||||
/*
|
||||
let types: {
|
||||
title?: string, type?: string, description?: string, url?: string, timestamp?: Date, color?: number, fields?: {name: string, value: string, inline?: boolean}[]
|
||||
footer?: { text: string, icon_url?: string, proxy_icon_url?: string}, image?: { url?: string, proxy_url?: string, height?: number, width?: number },
|
||||
thumbnail?: { url?: string, proxy_url?: string, height?: number, width?: number }, video?: { url?: string, height?: number, width?: number },
|
||||
provider?: { name?: string, url?: string}, author?: { name?: string, url?: string, proxy_icon_url?: string, icon_url?: string}
|
||||
};
|
||||
this.fields = [];
|
||||
for (const key of Object.keys(types)) {
|
||||
if (data[key]) this[key] = data[key];
|
||||
}
|
||||
*/
|
||||
this.title = data.title;
|
||||
this.description = data.description;
|
||||
this.url = data.url;
|
||||
this.color = data.color;
|
||||
this.author = data.author;
|
||||
this.timestamp = data.timestamp;
|
||||
this.fields = data.fields || [];
|
||||
this.thumbnail = data.thumbnail;
|
||||
this.image = data.image;
|
||||
this.footer = data.footer;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,10 +105,8 @@ export default class RichEmbed {
|
|||
*/
|
||||
setAuthor(name: string, icon_url?: string, url?: string) {
|
||||
if (typeof name !== 'string') throw new TypeError('RichEmbed Author names must be a string.');
|
||||
if (typeof url !== 'string') throw new TypeError('RichEmbed Author URLs must be a string.');
|
||||
if (typeof icon_url !== 'string') throw new TypeError('RichEmbed Author icons must be a string.');
|
||||
if (!url.startsWith('http://') || !url.startsWith('https://')) url = `https://${url}`;
|
||||
if (!icon_url.startsWith('http://') || !icon_url.startsWith('https://')) icon_url = `https://${icon_url}`;
|
||||
if (url && typeof url !== 'string') throw new TypeError('RichEmbed Author URLs must be a string.');
|
||||
if (icon_url && typeof icon_url !== 'string') throw new TypeError('RichEmbed Author icons must be a string.');
|
||||
this.author = { name, icon_url, url };
|
||||
return this;
|
||||
}
|
||||
|
@ -164,7 +170,6 @@ export default class RichEmbed {
|
|||
setFooter(text: string, icon_url?: string) {
|
||||
if (typeof text !== 'string') throw new TypeError('RichEmbed Footers must be a string.');
|
||||
if (icon_url && typeof icon_url !== 'string') throw new TypeError('RichEmbed Footer icon URLs must be a string.');
|
||||
if (!icon_url.startsWith('http://') || !icon_url.startsWith('https://')) icon_url = `https://${icon_url}`;
|
||||
if (text.length > 2048) throw new RangeError('RichEmbed footer text may not exceed 2048 characters.');
|
||||
this.footer = { text, icon_url };
|
||||
return this;
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
import { promisify, isArray } from 'util';
|
||||
import childProcess from 'child_process';
|
||||
import nodemailer from 'nodemailer';
|
||||
import { Message, TextChannel, PrivateChannel } from 'eris';
|
||||
import { Message, PrivateChannel } from 'eris';
|
||||
import { outputFile } from 'fs-extra';
|
||||
import { Client } from '.';
|
||||
import { Command, RichEmbed } from './class';
|
||||
import { Client } from '..';
|
||||
import { Command, RichEmbed } from '.';
|
||||
|
||||
export default class Util {
|
||||
public client: Client;
|
||||
|
@ -45,6 +45,8 @@ export default class Util {
|
|||
}
|
||||
|
||||
public async handleError(error: Error, message?: Message, command?: Command): Promise<void> {
|
||||
this.client.signale.error(error);
|
||||
/*
|
||||
const info = { content: `\`\`\`js\n${error.stack}\n\`\`\``, embed: null };
|
||||
if (message) {
|
||||
const embed = new RichEmbed();
|
||||
|
@ -65,6 +67,7 @@ export default class Util {
|
|||
if (message) this.client.createMessage('595788220764127272', 'Message content for above error');
|
||||
if (command) this.client.commands.get(command.name).enabled = false;
|
||||
if (message) message.channel.createMessage(`***${this.client.stores.emojis.error} An unexpected error has occured - please contact a member of the Engineering Team.${command ? ' This command has been disabled.' : ''}***`);
|
||||
*/
|
||||
}
|
||||
|
||||
public splitFields(fields: {name: string, value: string, inline?: boolean}[]): {name: string, value: string, inline?: boolean}[][] {
|
||||
|
@ -94,6 +97,7 @@ export default class Util {
|
|||
return arrayString;
|
||||
}
|
||||
|
||||
|
||||
public async createHash(password: string) {
|
||||
const hashed = await this.exec(`mkpasswd -m sha-512 "${password}"`);
|
||||
return hashed;
|
||||
|
@ -128,14 +132,14 @@ export default class Util {
|
|||
await this.client.db.Account.deleteOne({ username });
|
||||
}
|
||||
|
||||
public async messageCollector(message: Message, question: string, timeout: number, shouldDelete = false, choices: string[] = null, filter = (msg: Message): boolean|void => {}): Promise<string> {
|
||||
public async messageCollector(message: Message, question: string, timeout: number, shouldDelete = false, choices: string[] = null, filter = (msg: Message): boolean|void => {}): Promise<Message> {
|
||||
const msg = await message.channel.createMessage(question);
|
||||
return new Promise((res, rej) => {
|
||||
setTimeout(() => { if (shouldDelete) msg.delete(); rej(new Error('Did not supply a valid input in time')); }, timeout);
|
||||
this.client.on('messageCreate', (Msg) => {
|
||||
if (filter(Msg) === false) return;
|
||||
const verif = choices ? choices.includes(Msg.content) : Msg.content;
|
||||
if (verif) { if (shouldDelete) msg.delete(); res(Msg.content); }
|
||||
if (verif) { if (shouldDelete) msg.delete(); res(Msg); }
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { Message } from 'eris';
|
||||
import { Client, config } from '..';
|
||||
import { Client } from '..';
|
||||
import { Command } from '../class';
|
||||
|
||||
export default class Announce extends Command {
|
||||
|
@ -7,7 +7,7 @@ export default class Announce extends Command {
|
|||
super(client);
|
||||
this.name = 'announce';
|
||||
this.description = 'Sends an announcement to all active terminals';
|
||||
this.usage = `${config.prefix}announce Hi there! | ${config.prefix}announce -e EMERGENCY!`;
|
||||
this.usage = `${this.client.config.prefix}announce Hi there! | ${this.client.config.prefix}announce -e EMERGENCY!`;
|
||||
this.aliases = ['ann'];
|
||||
this.permissions = { roles: ['608095934399643649', '521312697896271873'] };
|
||||
this.enabled = true;
|
||||
|
@ -17,8 +17,8 @@ export default class Announce extends Command {
|
|||
try {
|
||||
if (!args.length) return this.client.commands.get('help').run(message, [this.name]);
|
||||
const notification = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Sending announcement, please wait...***`);
|
||||
if (args[0] === '-e') await this.client.util.exec(`echo "\n\n**************************************************************************\nEMERGENCY SYSTEM BROADCAST MESSAGE | Library of Code sp-us (root enforced)\n--------------------------------------------------------------------------\n\n\n${args.slice(1).join(' ')}\n\n\n\n\n\n\n\n\n\n\n\n\n" | wall -n`);
|
||||
else await this.client.util.exec(`echo "\nSYSTEM BROADCAST MESSAGE | Library of Code sp-us (root enforced)\n\n\n${args.join(' ')}" | wall -n`);
|
||||
if (args[0] === '-e') await this.client.util.exec(`echo "\n\n**************************************************************************\nEMERGENCY SYSTEM BROADCAST MESSAGE | Library of Code sp-us (root enforced)\n--------------------------------------------------------------------------\n\n\n${args.slice(1).join(' ').trim()}\n\n\n\n\n\n\n\n\n\n\n\n\n" | wall -n`);
|
||||
else await this.client.util.exec(`echo "\nSYSTEM BROADCAST MESSAGE | Library of Code sp-us (root enforced)\n\n\n${args.join(' ').trim()}" | wall -n`);
|
||||
message.delete();
|
||||
return notification.edit(`${this.client.stores.emojis.success} ***Sent${args[0] === '-e' ? ' emergency' : ''} announcement to all active terminals***`);
|
||||
} catch (error) {
|
||||
|
|
|
@ -59,7 +59,64 @@ export default class CreateAccount extends Command {
|
|||
embed.setTimestamp();
|
||||
// @ts-ignore
|
||||
this.client.createMessage('580950455581147146', { embed });
|
||||
return confirmation.edit(`${this.client.stores.emojis.success} ***Account successfully created***\n**Username:** \`${args[2]}\`\n**Temporary Password:** \`${tempPass}\``);
|
||||
|
||||
this.client.util.transport.sendMail({
|
||||
to: args[1],
|
||||
from: 'Library of Code sp-us | Cloud Services <support@libraryofcode.org>',
|
||||
subject: 'Your account has been created',
|
||||
html: `
|
||||
<body>
|
||||
<style>* {font-family: 'Calibri';}</style>
|
||||
<h1>Library of Code | Cloud Services</h1>
|
||||
<h2>Your Cloud Account has been created, welcome! Please see below for some details regarding your account and our services</h2>
|
||||
<p><b>Username:</b> ${args[2]}</p>
|
||||
<p><b>SSH Login:</b> <pre><code style="font-family: Courier;">ssh ${args[2]}@cloud.libraryofcode.org</code></pre>
|
||||
<p><b>Email address (see below for further information):</b> ${args[2]}@cloud.libraryofcode.org</p>
|
||||
<h2>Useful information</h2>
|
||||
<h3>How to log in:</h3>
|
||||
<ol>
|
||||
<li>Open your desired terminal application - we recommend using <a target="_blank" href="https://www.gnu.org/software/bash/">Bash</a>, but you can use your computer's default</li>
|
||||
<li>Type in your SSH Login as above</li>
|
||||
<li>When prompted, enter your password <em>Please note that inputs will be blank, so be careful not to type in your password incorrectly</em></li>
|
||||
</ol>
|
||||
<p>If you fail to authenticate yourself too many times, you will be IP banned and will fail to connect. If this is the case, feel free to DM Ramirez with your <a target="_blank" href="https://whatismyip.com">public IPv4 address</a>.
|
||||
|
||||
<h3>Setting up your cloud email</h3>
|
||||
<p>All email applications are different, so here are some information you can use to connect your email</p>
|
||||
<ul>
|
||||
<li><b>Server:</b> cloud.libraryofcode.org</li>
|
||||
<li><b>Account username/password:</b> Normal login</li>
|
||||
<li><b>Account type (incoming):</b> IMAP</li>
|
||||
<li><b>Incoming port:</b> 143 (993 if you're using TLS security type)</li>
|
||||
<li><b>Incoming Security Type:</b> STARTTLS (TLS if you're using port 993)</li>
|
||||
<li><b>Outgoing port:</b> 587 (If that doesn't work, try 25)</li>
|
||||
<li><b>Outgoing Security Type:</b> STARTTLS</li>
|
||||
</ul>
|
||||
<h3>Channels and Links</h3>
|
||||
<ul>
|
||||
<li><a target="_blank" href="https://discordapp.com/channels/446067825673633794/622856541325885453">#status</a> - You can find the status of all our services, including the cloud machine, here</li>
|
||||
<li><a target="_blank" href="https://discordapp.com/channels/446067825673633794/620355063088414769">#cloud-announcements</a> - Announcements regarding the cloud machine will be here. These include planned maintenance, updates to preinstalled services etc.</li>
|
||||
<li><a target="_blank" href="https://discordapp.com/channels/446067825673633794/620349128295186472">#cloud-info</a> - Important information you will need to, or should, know to a certain extent. These include our infractions system and Tier limits</li>
|
||||
<li><a target="_blank" href="https://discordapp.com/channels/446067825673633794/546457788184789013">#cloud-support</a> - A support channel specifically for the cloud machine, you can use this to ask how to renew your certificates, for example</li>
|
||||
<li><a target="_blank" href="https://support.libraryofcode.us">Library of Code Support Desk</a> - Our Support desk, you will find some handy info there</li>
|
||||
<li><a target="_blank" href="https://www.securesign.org">SecureSign</a> - our certificates manager</li>
|
||||
</ul>
|
||||
<h3>Want to support us?</h3>
|
||||
<p>You can support us on Patreon! Head to <a target="_blank" href="https://www.patreon.com/libraryofcode">our Patreon page</a> and feel free to donate as much or as little as you want!<br>Donating $5 or more will grant you Tier 3, which means we will manage your account at your request, longer certificates, increased Tier limits as well as some roles in the server!</p>
|
||||
<b><i>Library of Code sp-us | Support Team</i></b>
|
||||
</body>
|
||||
`,
|
||||
});
|
||||
|
||||
const dmChannel = await this.client.getDMChannel(args[0]).catch();
|
||||
dmChannel.createMessage('<:loc:607695848612167700> **Thank you for creating an account with us!** <:loc:607695848612167700>\n'
|
||||
+ `Please log into your account by running \`ssh ${args[2]}@cloud.libraryofcode.us\` in your terminal, then use the password \`${tempPass}\` to log in.\n`
|
||||
+ `You will be asked to change your password, \`(current) UNIX password\` is \`${tempPass}\`, then create a password that is at least 12 characters long, with at least one number, special character, and an uppercase letter\n`
|
||||
+ 'Bear in mind that when you enter your password, it will be blank, so be careful not to type in your password incorrectly.\n'
|
||||
+ 'You may now return to Modmail, and continue setting up your account from there.\n\n'
|
||||
+ 'An email containing some useful information has also been sent').catch();
|
||||
|
||||
return confirmation.edit(`${this.client.stores.emojis.success} ***Account successfully created***\n**Username:** \`${args[3]}\`\n**Temporary Password:** \`${tempPass}\``);
|
||||
} catch (error) {
|
||||
return this.client.util.handleError(error, message, this);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ export default class CWG extends Command {
|
|||
}
|
||||
|
||||
public async run(message: Message, args?: string[]) {
|
||||
if (!args.length) return this.client.commands.get('help').run(message, [this.name]);
|
||||
/*
|
||||
args[1] should be the user's ID OR account username; required
|
||||
args[2] should be the domain; required
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
import { Message, PrivateChannel } from 'eris';
|
||||
import uuid from 'uuid/v4';
|
||||
import { Command, RichEmbed } from '../class';
|
||||
import { Client, config } from '..';
|
||||
|
||||
export default class DeleteAccount extends Command {
|
||||
constructor(client: Client) {
|
||||
super(client);
|
||||
this.name = 'deleteaccount';
|
||||
this.description = 'Delete an account on the Cloud VM';
|
||||
this.usage = `${config.prefix}deleteaccount [User ID] [Reason] | ${config.prefix}deleteaccount [Username] [Reason] | ${config.prefix}deleteaccount [Email] [Reason]`;
|
||||
this.aliases = ['deleteacc', 'dacc', 'daccount', 'delete'];
|
||||
this.permissions = { roles: ['475817826251440128', '525441307037007902'] };
|
||||
this.enabled = true;
|
||||
}
|
||||
|
||||
public async run(message: Message, args: string[]) {
|
||||
try {
|
||||
if (!args[1]) return this.client.commands.get('help').run(message, [this.name]);
|
||||
const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }, { emailAddress: args[0] }] });
|
||||
if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`);
|
||||
const { root, username, userID, emailAddress } = account;
|
||||
if (root) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Permission denied***`);
|
||||
|
||||
const pad = (number: number, amount: number): string => '0'.repeat(amount - number.toString().length) + number;
|
||||
const randomNumber = Math.floor(Math.random() * 9999);
|
||||
const verify = pad(randomNumber, 4);
|
||||
try {
|
||||
await this.client.util.messageCollector(message,
|
||||
`***Please confirm that you are permanently deleting ${username}'s account by entering ${verify}. This action cannot be reversed.***`,
|
||||
15000, true, [verify], (msg) => !(message.channel instanceof PrivateChannel && msg.author.id === message.author.id));
|
||||
} catch (error) {
|
||||
if (error.message.includes('Did not supply')) return message;
|
||||
throw error;
|
||||
}
|
||||
|
||||
const deleting = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Deleteing account, please wait...***`);
|
||||
await this.client.util.deleteAccount(username);
|
||||
const reason = args.slice(1).join(' ');
|
||||
const logInput = { username, userID, logID: uuid(), moderatorID: message.author.id, type: 4, date: new Date(), reason: null };
|
||||
if (reason) logInput.reason = reason;
|
||||
const log = await new this.client.db.Moderation(logInput);
|
||||
await log.save();
|
||||
|
||||
const embed = new RichEmbed();
|
||||
embed.setTitle('Cloud Account | Delete');
|
||||
embed.setColor('ff0000');
|
||||
embed.addField('User', `${username} | <@${userID}>`);
|
||||
embed.addField('Engineer', `<@${message.author.id}>`, true);
|
||||
if (reason) embed.addField('Reason', reason);
|
||||
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
|
||||
embed.setTimestamp();
|
||||
// @ts-ignore
|
||||
this.client.createMessage('580950455581147146', { embed });
|
||||
this.client.getDMChannel(userID).then((user) => {
|
||||
// @ts-ignore
|
||||
user.createMessage({ embed }).catch();
|
||||
});
|
||||
|
||||
this.client.util.transport.sendMail({
|
||||
to: account.emailAddress,
|
||||
from: 'Library of Code sp-us | Cloud Services <support@libraryofcode.org>',
|
||||
subject: 'Your account has been deleted',
|
||||
html: `
|
||||
<h1>Library of Code | Cloud Services</h1>
|
||||
<p>Your Cloud Account has been deleted by our Engineers. There is no way to recover your files and this desicion cannot be appealed. We're sorry to see you go.</p>
|
||||
<p><b>Reason:</b> ${reason}</p>
|
||||
<p><b>Engineer:</b> ${message.author.username}</p>
|
||||
|
||||
<b><i>Library of Code sp-us | Support Team</i></b>
|
||||
`,
|
||||
});
|
||||
|
||||
return deleting.edit(`${this.client.stores.emojis.success} ***Account ${username} has been deleted by Engineer ${message.author.username}#${message.author.discriminator}***`);
|
||||
} catch (error) {
|
||||
return this.client.util.handleError(error, message, this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
import { Message } from 'eris';
|
||||
import { inspect } from 'util';
|
||||
import axios from 'axios';
|
||||
import { Client, config } from '..';
|
||||
import { Client } from '..';
|
||||
import { Command } from '../class';
|
||||
|
||||
export default class Eval extends Command {
|
||||
|
@ -15,26 +15,32 @@ export default class Eval extends Command {
|
|||
this.permissions = { users: ['253600545972027394', '278620217221971968'] };
|
||||
}
|
||||
|
||||
public async run(message: Message) {
|
||||
public async run(message: Message, args: string[]) {
|
||||
try {
|
||||
const evalMessage = message.content.slice(config.prefix.length).split(' ').slice(1).join(' ');
|
||||
// const evalMessage = message.content.slice(this.client.config.prefix.length).split(' ').slice(1).join(' ');
|
||||
let evaled: any;
|
||||
let output: string;
|
||||
|
||||
try {
|
||||
evaled = await eval(evalMessage);
|
||||
if (typeof evaled !== 'string') output = output && inspect(evaled, { depth: 1 });
|
||||
evaled = await eval(args.join(' ').trim());
|
||||
if (typeof evaled !== 'string') {
|
||||
evaled = inspect(evaled, { depth: 0 });
|
||||
}
|
||||
if (evaled === undefined) {
|
||||
evaled = 'undefined';
|
||||
}
|
||||
} catch (error) {
|
||||
output = error.stack;
|
||||
evaled = error.stack;
|
||||
}
|
||||
|
||||
/*
|
||||
if (output) {
|
||||
output = output.replace(RegExp(config.prefix, 'gi'), 'juul');
|
||||
output = output.replace(RegExp(config.emailPass, 'gi'), 'juul');
|
||||
output = output.replace(RegExp(config.cloudflare, 'gi'), 'juul');
|
||||
output = output.replace(RegExp(this.client.config.prefix, 'gi'), 'juul');
|
||||
output = output.replace(RegExp(this.client.config.emailPass, 'gi'), 'juul');
|
||||
output = output.replace(RegExp(this.client.config.cloudflare, 'gi'), 'juul');
|
||||
}
|
||||
*/
|
||||
|
||||
const display = this.client.util.splitString(output, 1975);
|
||||
const display = this.client.util.splitString(evaled, 1975);
|
||||
if (display[5]) {
|
||||
try {
|
||||
const { data } = await axios.post('https://snippets.cloud.libraryofcode.org/documents', display.join(''));
|
||||
|
|
|
@ -28,7 +28,7 @@ export default class Help extends Command {
|
|||
let allowedUsers = c.permissions && c.permissions.users && c.permissions.users.map((u) => `<@${u}>`).join(', ');
|
||||
if (allowedUsers) { allowedUsers = `**Users:** ${allowedUsers}`; perms.push(allowedUsers); }
|
||||
const displayedPerms = perms.length ? `**Permissions:**\n${perms.join('\n')}` : '';
|
||||
return { name: `${this.client.config.prefix}${c.name}`, value: `**Description:** ${c.description}\n**Aliases:** ${aliases}\n**Usage:** ${c.usage}\n${displayedPerms}`, inline: true };
|
||||
return { name: `${this.client.config.prefix}${c.name}`, value: `**Description:** ${c.description}\n**Aliases:** ${aliases}\n**Usage:** ${c.usage}\n${displayedPerms}`, inline: false };
|
||||
});
|
||||
|
||||
const splitCommands = this.client.util.splitFields(commands);
|
||||
|
|
|
@ -16,22 +16,26 @@ export default class Lock extends Command {
|
|||
|
||||
public async run(message: Message, args: string[]) { // eslint-disable-line
|
||||
try {
|
||||
const account = await this.client.db.Account.findOne({ $or: [{ account: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] });
|
||||
if (!args.length) return this.client.commands.get('help').run(message, [this.name]);
|
||||
const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] });
|
||||
if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot find user.***`);
|
||||
if (account.locked) return message.channel.createMessage(`***${this.client.stores.emojis.error} This account is already locked.***`);
|
||||
const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Locking account...***`);
|
||||
if (account.username === 'matthew' || account.root) return edit.edit(`***${this.client.stores.emojis.error} Permission denied.***`);
|
||||
await this.client.util.exec(`lock ${account.username}`);
|
||||
await account.update({ locked: true });
|
||||
await account.updateOne({ locked: true });
|
||||
|
||||
const expiry = new Date();
|
||||
const lockLength = args[1].match(/[a-z]+|[^a-z]+/gi);
|
||||
// @ts-ignore
|
||||
const momentMilliseconds = moment.duration(Number(lockLength[0]), lockLength[1]).asMilliseconds;
|
||||
const momentMilliseconds = moment.duration(Number(lockLength[0]), lockLength[1]).asMilliseconds();
|
||||
expiry.setMilliseconds(momentMilliseconds);
|
||||
let processed: boolean = false;
|
||||
if (!momentMilliseconds) processed = true;
|
||||
|
||||
this.client.signale.debug(lockLength);
|
||||
this.client.signale.debug(expiry);
|
||||
this.client.signale.debug(momentMilliseconds);
|
||||
const moderation = new this.client.db.Moderation({
|
||||
username: account.username,
|
||||
userID: account.userID,
|
||||
|
@ -41,7 +45,7 @@ export default class Lock extends Command {
|
|||
type: 2,
|
||||
date: new Date(),
|
||||
expiration: {
|
||||
expirationDate: momentMilliseconds ? expiry : null,
|
||||
date: momentMilliseconds ? expiry : null,
|
||||
processed,
|
||||
},
|
||||
});
|
||||
|
@ -53,8 +57,10 @@ export default class Lock extends Command {
|
|||
embed.addField('User', `${account.username} | <@${account.userID}>`, true);
|
||||
embed.addField('Supervisor', `<@${message.author.id}>`, true);
|
||||
if ((momentMilliseconds ? args.slice(2).join(' ') : args.slice(1).join(' ')).length > 0) embed.addField('Reason', momentMilliseconds ? args.slice(2).join(' ') : args.slice(1).join(' '), true);
|
||||
embed.addField('Lock Expiration', `${momentMilliseconds ? moment(expiry).format('dddd, MMMM Do YYYY, h:mm:ss A') : 'Indefinitely'}`, true);
|
||||
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
|
||||
embed.setTimestamp();
|
||||
message.delete();
|
||||
this.client.getDMChannel(account.userID).then((user) => {
|
||||
// @ts-ignore
|
||||
user.createMessage({ embed }).catch();
|
||||
|
|
|
@ -16,6 +16,7 @@ export default class Modlogs extends Command {
|
|||
|
||||
public async run(message: Message, args: string[]) {
|
||||
try {
|
||||
if (!args.length) return this.client.commands.get('help').run(message, [this.name]);
|
||||
const msg: Message = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Locating modlogs...***`);
|
||||
const query = await this.client.db.Moderation.find({ $or: [{ username: args.join(' ') }, { userID: args.filter((a) => a)[0].replace(/[<@!>]/g, '') }] });
|
||||
if (!query.length) return msg.edit(`***${this.client.stores.emojis.error} Cannot locate modlogs for ${args.join(' ')}***`);
|
||||
|
@ -45,7 +46,7 @@ export default class Modlogs extends Command {
|
|||
const embeds = logs.map((l) => {
|
||||
const embed = new RichEmbed();
|
||||
embed.setDescription(`List of Cloud moderation logs for ${users.join(', ')}`);
|
||||
embed.setAuthor('Library of Code | Cloud Services', this.client.user.avatarURL, 'https://libraryofcode.us');
|
||||
embed.setAuthor('Library of Code | Cloud Services', this.client.user.avatarURL, 'https://libraryofcode.org/');
|
||||
embed.setTitle('Cloud Modlogs/Infractions');
|
||||
embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL);
|
||||
l.forEach((f) => embed.addField(f.name, f.value, f.inline));
|
||||
|
@ -54,7 +55,12 @@ export default class Modlogs extends Command {
|
|||
return embed;
|
||||
});
|
||||
|
||||
createPaginationEmbed(message, this.client, embeds, {}, msg);
|
||||
if (embeds.length === 1) {
|
||||
// @ts-ignore
|
||||
message.channel.createMessage({ embed: embeds[0] });
|
||||
} else {
|
||||
createPaginationEmbed(message, this.client, embeds, {}, msg);
|
||||
}
|
||||
return msg;
|
||||
} catch (error) {
|
||||
return this.client.util.handleError(error, message, this);
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import moment from 'moment';
|
||||
import { Message } from 'eris';
|
||||
import os, { totalmem } from 'os';
|
||||
import { Command, RichEmbed } from '../class';
|
||||
import { dataConversion } from '../functions';
|
||||
import { Client } from '..';
|
||||
|
||||
export default class SysInfo extends Command {
|
||||
constructor(client: Client) {
|
||||
super(client);
|
||||
this.name = 'sysinfo';
|
||||
this.description = 'Provides system information.';
|
||||
this.enabled = true;
|
||||
}
|
||||
|
||||
public async run(message: Message) {
|
||||
const availableMemory: string = await this.client.util.exec('free -b');
|
||||
const usedMemory = dataConversion(totalmem() - Number(availableMemory.split('\n')[1].split(' ').slice(-1)[0]));
|
||||
const date = new Date();
|
||||
date.setMilliseconds(-(moment.duration(os.uptime(), 's').asMilliseconds()));
|
||||
|
||||
const embed = new RichEmbed();
|
||||
embed.setTitle('System Information & Statistics');
|
||||
embed.addField('Hostname', os.hostname(), true);
|
||||
embed.addField('Uptime', `${moment.duration(os.uptime(), 's').humanize()} | Last restart was on ${moment(date).format('dddd, MMMM Do YYYY, h:mm:ss A')} EST`, true);
|
||||
embed.addField('CPU', `${os.cpus()[0].model} ${os.cpus()[0].speed / 1000}GHz | ${os.cpus().length} Cores | ${os.arch()}`, true);
|
||||
embed.addField('Load Average (last 15 minutes)', os.loadavg()[2].toFixed(3), true);
|
||||
embed.addField('Memory/RAM', `${usedMemory} / ${dataConversion(totalmem())}`, true);
|
||||
embed.addField('Network Interfaces (IPv4)', os.networkInterfaces().eth0.filter((r) => r.family === 'IPv4')[0].address, true);
|
||||
embed.addField('Network Interfaces (IPv6)', os.networkInterfaces().eth0.filter((r) => r.family === 'IPv6')[0].address.replace(/:/gi, '\:'), true); // eslint-disable-line
|
||||
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
|
||||
embed.setTimestamp();
|
||||
// @ts-ignore
|
||||
message.channel.createMessage({ embed });
|
||||
}
|
||||
}
|
|
@ -14,12 +14,14 @@ export default class Unlock extends Command {
|
|||
|
||||
public async run(message: Message, args: string[]) { // eslint-disable-line
|
||||
try {
|
||||
const account = await this.client.db.Account.findOne({ $or: [{ account: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] });
|
||||
if (!args.length) return this.client.commands.get('help').run(message, [this.name]);
|
||||
const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] });
|
||||
if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot find user.***`);
|
||||
if (!account.locked) return message.channel.createMessage(`***${this.client.stores.emojis.error} This account is already unlocked.***`);
|
||||
const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Unlocking account...***`);
|
||||
if (account.username === 'matthew' || account.root) return edit.edit(`***${this.client.stores.emojis.error} Permission denied.***`);
|
||||
await this.client.util.exec(`unlock ${account.username}`);
|
||||
await account.updateOne({ locked: false });
|
||||
|
||||
const moderation = new this.client.db.Moderation({
|
||||
username: account.username,
|
||||
|
@ -33,13 +35,14 @@ export default class Unlock extends Command {
|
|||
await moderation.save();
|
||||
edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been unlocked by Supervisor ${message.author.username}#${message.author.discriminator}.***`);
|
||||
const embed = new RichEmbed();
|
||||
embed.setTitle('Account Infraction | UnLock');
|
||||
embed.setTitle('Account Infraction | Unlock');
|
||||
embed.setColor(15158332);
|
||||
embed.addField('User', `${account.username} | <@${account.userID}>`, true);
|
||||
embed.addField('Supervisor', `<@${message.author.id}>`, true);
|
||||
if (args.slice(1).join(' ').length > 0) embed.addField('Reason', args.slice(1).join(' '), true);
|
||||
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
|
||||
embed.setTimestamp();
|
||||
message.delete();
|
||||
this.client.getDMChannel(account.userID).then((user) => {
|
||||
// @ts-ignore
|
||||
user.createMessage({ embed }).catch();
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { Message, TextChannel } from 'eris';
|
||||
import { Client, config } from '..';
|
||||
import { Client } from '..';
|
||||
import Command from '../class/Command';
|
||||
|
||||
const { prefix } = config;
|
||||
|
||||
export default class {
|
||||
public client: Client
|
||||
|
||||
|
@ -13,18 +11,30 @@ export default class {
|
|||
|
||||
public async run(message: Message) {
|
||||
try {
|
||||
const noPrefix: string[] = message.content.slice(prefix.length).trim().split(/ +/g);
|
||||
if (message.author.bot) return;
|
||||
if (message.content.indexOf(this.client.config.prefix) !== 0) return;
|
||||
const noPrefix: string[] = message.content.slice(this.client.config.prefix.length).trim().split(/ +/g);
|
||||
const command: string = noPrefix[0].toLowerCase();
|
||||
const resolved: Command = this.client.util.resolveCommand(command);
|
||||
if (!resolved) return;
|
||||
if (resolved.guildOnly && !(message.channel instanceof TextChannel)) return;
|
||||
const hasUserPerms: boolean = resolved.permissions.users.includes(message.author.id);
|
||||
let hasUserPerms: boolean;
|
||||
if (resolved.permissions.users) {
|
||||
hasUserPerms = resolved.permissions.users.includes(message.author.id);
|
||||
}
|
||||
let hasRolePerms: boolean = false;
|
||||
for (const role of resolved.permissions.roles) {
|
||||
if (message.member && message.member.roles.includes(role)) {
|
||||
hasRolePerms = true; break;
|
||||
if (resolved.permissions.roles) {
|
||||
for (const role of resolved.permissions.roles) {
|
||||
if (message.member && message.member.roles.includes(role)) {
|
||||
// this.client.signale.debug(message.member.roles.includes(role));
|
||||
hasRolePerms = true; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!resolved.permissions.users && !resolved.permissions.roles) {
|
||||
hasUserPerms = true;
|
||||
hasRolePerms = true;
|
||||
}
|
||||
if (!hasRolePerms && !hasUserPerms) return;
|
||||
if (!resolved.enabled) { message.channel.createMessage(`***${this.client.stores.emojis.error} This command has been disabled***`); return; }
|
||||
const args: string[] = noPrefix.slice(1);
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Client } from '..';
|
|||
import { RichEmbed } from '../class';
|
||||
|
||||
export default function checkLock(client: Client) {
|
||||
setTimeout(async () => {
|
||||
setInterval(async () => {
|
||||
try {
|
||||
const moderations = await client.db.Moderation.find();
|
||||
moderations.forEach(async (moderation) => {
|
||||
|
@ -13,7 +13,8 @@ export default function checkLock(client: Client) {
|
|||
const account = await client.db.Account.findOne({ username: moderation.username });
|
||||
if (!account) return;
|
||||
await client.util.exec(`unlock ${account.username}`);
|
||||
await moderation.update({ 'expiration.processed': true });
|
||||
await moderation.updateOne({ 'expiration.processed': true });
|
||||
await account.updateOne({ locked: false });
|
||||
const mod = new client.db.Moderation({
|
||||
username: account.username,
|
||||
userID: account.userID,
|
||||
|
@ -38,10 +39,11 @@ export default function checkLock(client: Client) {
|
|||
});
|
||||
// @ts-ignore
|
||||
client.createMessage('580950455581147146', { embed });
|
||||
client.signale.complete(`Unlocked account ${account.username} | Queue date at ${moderation.expiration.date.toLocaleString('en-us')}`);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
await client.util.handleError(error);
|
||||
}
|
||||
});
|
||||
}, 10000);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export default function dataConversion(bytes: number) {
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
return `${(bytes / 1024 ** i).toFixed(2)} ${sizes[i]}`;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export { default as checkLock } from './checkLock';
|
||||
export { default as dataConversion } from './dataConversion';
|
|
@ -5,4 +5,3 @@ export { default as Commands } from './commands';
|
|||
export { default as Events } from './events';
|
||||
export { default as Models } from './models';
|
||||
export { default as Stores } from './stores';
|
||||
export { default as Util } from './Util';
|
||||
|
|
|
@ -25,10 +25,10 @@ export interface ModerationInterface extends Document {
|
|||
const Moderation: Schema = new Schema({
|
||||
username: String,
|
||||
userID: String,
|
||||
logID: Number,
|
||||
logID: String,
|
||||
moderatorID: String,
|
||||
reason: String,
|
||||
type: String,
|
||||
type: Number,
|
||||
date: Date,
|
||||
expiration: {
|
||||
date: Date,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
export default {
|
||||
success: '<:modSuccess:578750988907970567>',
|
||||
loading: '<a:modloading:588607353935364106>',
|
||||
error: '<:modError:578750737920688128',
|
||||
error: '<:modError:578750737920688128>',
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue