1
0
Fork 0

Merge branch 'eirk/cloudservices-master'

master
Hiroyuki 2021-09-10 19:05:44 -04:00
commit b40b39ca12
No known key found for this signature in database
GPG Key ID: AF65958B7B7362E6
71 changed files with 2231 additions and 2042 deletions

61
.gitignore vendored
View File

@ -1,10 +1,57 @@
node_modules # Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-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
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Serverless directories
.serverless/
# macOS files
.DS_Store
*.DS_Store
# Database files
*.sqlite
# IDE and text editor configuration files
.vscode/
.idea/
# other files
dist/
src/config.json src/config.json
package-lock.json
htmlEmail_templates
yarn-error.log
src/keys.json src/keys.json
dist htmlEmail_templates
securesign_genrsa.ts securesign_genrsa.ts
.idea
.vscode

10
.vscode/settings.json vendored
View File

@ -1,10 +0,0 @@
{
"eslint.enable": true,
"eslint.validate": [
{
"language": "typescript",
"autoFix": true
}
],
"editor.tabSize": 2
}

View File

@ -629,7 +629,7 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found. the "copyright" line and a pointer to where the full notice is found.
Cloud Services Cloud Services
Copyright (C) 2019 Library of Code sp-us Engineering Team Copyright (C) 2019 Library of Code sp-us Engineering Team
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@ -7,7 +7,7 @@ get_user_by_uid_files := $(wildcard src/go/getUserByUid/*.go)
all: check_certificate check_cert_signatures storage getUserByUid typescript all: check_certificate check_cert_signatures storage getUserByUid typescript
check_certificate: check_certificate:
HOME=/root go build -ldflags="-s -w" -o dist/bin/checkCertificate ${check_certificate_files} HOME=/root go build -ldflags="-s -w" -o dist/bin/checkCertificate ${check_certificate_files}
@chmod 740 dist/bin/checkCertificate @chmod 740 dist/bin/checkCertificate
@file dist/bin/checkCertificate @file dist/bin/checkCertificate

View File

@ -1,7 +1,7 @@
{ {
"name": "cloudservices-rewrite", "name": "cloudservices-rewrite",
"version": "1.2.0", "version": "2.0",
"description": "The official LOC Cloud Services system, this is a rewrite of the original version. ", "description": "The official LOC Cloud Services system, this is a rewrite the original version, using discord.js.",
"main": "dist/Client.js", "main": "dist/Client.js",
"scripts": { "scripts": {
"lint": "eslint ./ --ext ts --fix", "lint": "eslint ./ --ext ts --fix",
@ -12,40 +12,37 @@
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"private": false, "private": false,
"dependencies": { "dependencies": {
"axios": "^0.19.0", "axios": "^0.21.1",
"body-parser": "^1.19.0", "body-parser": "^1.19.0",
"eris": "bsian03/eris#dev", "discord.js": "^13.0.0",
"eris-pagination": "git+https://github.com/bsian03/eris-pagination#c0f77b118e98309e89e6522ef545f9d121601f21",
"express": "^4.17.1", "express": "^4.17.1",
"fs-extra": "^8.1.0", "fs-extra": "^10.0.0",
"hastebin-gen": "^2.0.5", "hastebin-gen": "^2.0.5",
"helmet": "^3.21.2", "helmet": "^4.6.0",
"ioredis": "^4.14.1", "ioredis": "^4.27.7",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"moment": "^2.27.0", "moment": "^2.29.1",
"moment-precise-range-plugin": "^1.3.0", "mongoose": "^5.13.5",
"mongoose": "^5.7.4", "nodemailer": "^6.6.3",
"nodemailer": "^6.3.1",
"signale": "^1.4.0", "signale": "^1.4.0",
"uuid": "^3.3.3" "uuid": "^8.3.2"
}, },
"devDependencies": { "devDependencies": {
"@types/express": "^4.17.6", "@types/express": "^4.17.13",
"@types/express-serve-static-core": "^4.17.5", "@types/express-serve-static-core": "^4.17.24",
"@types/fs-extra": "^8.0.0", "@types/fs-extra": "^9.0.12",
"@types/helmet": "^0.0.45", "@types/ioredis": "^4.26.7",
"@types/ioredis": "^4.0.18", "@types/jsonwebtoken": "^8.5.4",
"@types/jsonwebtoken": "^8.5.0", "@types/node": "^16.4.13",
"@types/mongoose": "^5.7.14", "@types/nodemailer": "^6.4.4",
"@types/nodemailer": "^6.2.1", "@types/signale": "^1.4.2",
"@types/signale": "^1.2.1", "@types/uuid": "^8.3.1",
"@types/uuid": "^3.4.5", "@typescript-eslint/eslint-plugin": "^4.29.0",
"@typescript-eslint/eslint-plugin": "2.31.0", "@typescript-eslint/parser": "^4.29.0",
"@typescript-eslint/parser": "2.31.0", "eslint": "^7.32.0",
"eslint": "^6.5.1", "eslint-config-airbnb-base": "^14.2.1",
"eslint-config-airbnb-base": "^14.0.0", "eslint-plugin-import": "^2.23.4",
"eslint-plugin-import": "^2.18.2", "madge": "^5.0.1",
"madge": "^3.9.2", "typescript": "^4.3.5"
"typescript": "^3.6.4"
} }
} }

View File

@ -1,8 +1,8 @@
import os from 'os'; import os from 'os';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { TextChannel } from 'eris'; import { TextChannel, MessageEmbed } from 'discord.js';
import { Server } from '..'; import { Server } from '..';
import { RichEmbed, Route } from '../../class'; import { Route } from '../../class';
export default class Root extends Route { export default class Root extends Route {
constructor(server: Server) { constructor(server: Server) {
@ -59,18 +59,18 @@ export default class Root extends Route {
const token = <any> jwt.verify(req.query.t.toString(), this.server.client.config.keyPair.privateKey); const token = <any> jwt.verify(req.query.t.toString(), this.server.client.config.keyPair.privateKey);
const check = await this.server.storage.get<boolean>(req.query.t.toString()); const check = await this.server.storage.get<boolean>(req.query.t.toString());
if (check) return res.sendStatus(401); if (check) return res.sendStatus(401);
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('Referral Authorization'); embed.setTitle('Referral Authorization');
embed.setDescription(req.query.t.toString()); embed.setDescription(req.query.t.toString());
embed.addField('Referred User', `${token.referredUserAndDiscrim} | ${token.referredUserID}`, true); embed.addField('Referred User', `${token.referredUserAndDiscrim} | ${token.referredUserID}`, true);
embed.addField('Referrer User', token.referrerUsername, true); embed.addField('Referrer User', token.referrerUsername, true);
embed.addField('Referral Code', token.referralCode, true); embed.addField('Referral Code', token.referralCode, true);
embed.setTimestamp(); embed.setTimestamp();
embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL); embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL());
const channel = <TextChannel> this.server.client.guilds.get('446067825673633794').channels.get('580950455581147146'); const channel = this.server.client.guilds.cache.get('446067825673633794').channels.cache.get('580950455581147146') as TextChannel;
res.sendStatus(200); res.sendStatus(200);
await this.server.storage.set(req.query.t.toString(), true); await this.server.storage.set(req.query.t.toString(), true);
return channel.createMessage({ content: `<@${token.staffUserID}>`, embed }); return channel.send({ content: `<@${token.staffUserID}>`, embeds: [embed] });
} catch { } catch {
return res.sendStatus(401); return res.sendStatus(401);
} }

View File

@ -1,7 +1,7 @@
/* eslint-disable no-continue */ /* eslint-disable no-continue */
import { TextChannel } from 'eris'; import { TextChannel, MessageEmbed, TextBasedChannel } from 'discord.js';
import { Server } from '..'; import { Server } from '..';
import { Route, RichEmbed } from '../../class'; import { Route } from '../../class';
export default class Webhook extends Route { export default class Webhook extends Route {
constructor(server: Server) { constructor(server: Server) {
@ -12,7 +12,7 @@ export default class Webhook extends Route {
this.router.post('/s1', async (req, res) => { this.router.post('/s1', async (req, res) => {
try { try {
if (req.headers.authorization !== this.server.security.keys.iv.toString('base64')) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.codes.UNAUTHORIZED }); if (req.headers.authorization !== this.server.security.keys.iv.toString('base64')) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.codes.UNAUTHORIZED });
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('Service Request'); embed.setTitle('Service Request');
embed.setDescription(`https://staff.libraryofcode.org/browse/${req.body.key}\n${req.body.url}`); embed.setDescription(`https://staff.libraryofcode.org/browse/${req.body.key}\n${req.body.url}`);
embed.setColor('#FF00FF'); embed.setColor('#FF00FF');
@ -20,10 +20,10 @@ export default class Webhook extends Route {
embed.addField('Reporter', req.body.reporter, true); embed.addField('Reporter', req.body.reporter, true);
embed.addField('Status', req.body.status, true); embed.addField('Status', req.body.status, true);
embed.addField('Summary', req.body.summary); embed.addField('Summary', req.body.summary);
embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL); embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL());
embed.setTimestamp(); embed.setTimestamp();
const chan = <TextChannel> this.server.client.getChannel('780513128240382002'); const channel = this.server.client.channels.cache.get('780513128240382002') as TextChannel;
chan.createMessage({ content: '<@&741797822940315650>', embed }); channel.send({ content: '<@&741797822940315650>', embeds: [embed] });
return res.status(200).json({ code: this.constants.codes.SUCCESS, message: this.constants.codes.SUCCESS }); return res.status(200).json({ code: this.constants.codes.SUCCESS, message: this.constants.codes.SUCCESS });
} catch (err) { } catch (err) {
return this.handleError(err, res); return this.handleError(err, res);
@ -47,17 +47,18 @@ export default class Webhook extends Route {
} else { } else {
await account.updateOne({ $set: { tier: 3 } }); await account.updateOne({ $set: { tier: 3 } });
} }
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('Cloud Account | Tier Change'); embed.setTitle('Cloud Account | Tier Change');
embed.setColor('#0099ff'); embed.setColor('#0099ff');
embed.addField('User', `${account.username} | <@${account.userID}>`, true); embed.addField('User', `${account.username} | <@${account.userID}>`, true);
embed.addField('Technician', 'SYSTEM', true); embed.addField('Technician', 'SYSTEM', true);
embed.addField('Old Tier -> New Tier', `${account.tier} -> 3`, true); embed.addField('Old Tier -> New Tier', `${account.tier} -> 3`, true);
embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL); embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL());
embed.setTimestamp(); embed.setTimestamp();
await this.server.client.util.sendMessageToUserTerminal(account.username, 'A technician has changed your tier to 3').catch(() => { }); await this.server.client.util.sendMessageToUserTerminal(account.username, 'A technician has changed your tier to 3').catch(() => { });
this.server.client.createMessage('580950455581147146', { embed }); const channel = this.server.client.channels.cache.get('580950455581147146') as TextChannel;
this.server.client.getDMChannel(account.userID).then((channel) => channel.createMessage({ embed })).catch(); channel.send({ embeds: [embed] });
this.server.client.users.cache.get(account.userID).send({ embeds: [embed] });
return res.sendStatus(200); return res.sendStatus(200);
}); });
@ -74,17 +75,18 @@ export default class Webhook extends Route {
} else { } else {
await account.updateOne({ $set: { tier: 1 } }); await account.updateOne({ $set: { tier: 1 } });
} }
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('Cloud Account | Tier Change'); embed.setTitle('Cloud Account | Tier Change');
embed.setColor('#0099ff'); embed.setColor('#0099ff');
embed.addField('User', `${account.username} | <@${account.userID}>`, true); embed.addField('User', `${account.username} | <@${account.userID}>`, true);
embed.addField('Technician', 'SYSTEM', true); embed.addField('Technician', 'SYSTEM', true);
embed.addField('Old Tier -> New Tier', `${account.tier} -> 1`, true); embed.addField('Old Tier -> New Tier', `${account.tier} -> 1`, true);
embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL); embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL());
embed.setTimestamp(); embed.setTimestamp();
await this.server.client.util.sendMessageToUserTerminal(account.username, 'A technician has changed your tier.').catch(() => { }); await this.server.client.util.sendMessageToUserTerminal(account.username, 'A technician has changed your tier.').catch(() => { });
this.server.client.createMessage('580950455581147146', { embed }); const ch = this.server.client.channels.cache.get('580950455581147146') as TextChannel;
this.server.client.getDMChannel(account.userID).then((channel) => channel.createMessage({ embed })).catch(); ch.send({ embeds: [embed] });
this.server.client.users.cache.get(account.userID).send({ embeds: [embed] });
return res.sendStatus(200); return res.sendStatus(200);
}); });
@ -105,17 +107,18 @@ export default class Webhook extends Route {
} else { } else {
await account.updateOne({ $set: { tier: 2 } }); await account.updateOne({ $set: { tier: 2 } });
} }
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('Cloud Account | Tier Change'); embed.setTitle('Cloud Account | Tier Change');
embed.setColor('#0099ff'); embed.setColor('#0099ff');
embed.addField('User', `${account.username} | <@${account.userID}>`, true); embed.addField('User', `${account.username} | <@${account.userID}>`, true);
embed.addField('Technician', 'SYSTEM', true); embed.addField('Technician', 'SYSTEM', true);
embed.addField('Old Tier -> New Tier', `${account.tier} -> 2`, true); embed.addField('Old Tier -> New Tier', `${account.tier} -> 2`, true);
embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL); embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL());
embed.setTimestamp(); embed.setTimestamp();
await this.server.client.util.sendMessageToUserTerminal(account.username, 'A technician has changed your tier to 2').catch(() => { }); await this.server.client.util.sendMessageToUserTerminal(account.username, 'A technician has changed your tier to 2').catch(() => { });
this.server.client.createMessage('580950455581147146', { embed }); const ch = this.server.client.channels.cache.get('580950455581147146') as TextChannel;
this.server.client.getDMChannel(account.userID).then((channel) => channel.createMessage({ embed })).catch(); ch.send({ embeds: [embed] });
this.server.client.users.cache.get(account.userID).send({ embeds: [embed] });
return res.sendStatus(200); return res.sendStatus(200);
}); });
@ -132,17 +135,18 @@ export default class Webhook extends Route {
} else { } else {
await account.updateOne({ $set: { tier: 1 } }); await account.updateOne({ $set: { tier: 1 } });
} }
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('Cloud Account | Tier Change'); embed.setTitle('Cloud Account | Tier Change');
embed.setColor('#0099ff'); embed.setColor('#0099ff');
embed.addField('User', `${account.username} | <@${account.userID}>`, true); embed.addField('User', `${account.username} | <@${account.userID}>`, true);
embed.addField('Technician', 'SYSTEM', true); embed.addField('Technician', 'SYSTEM', true);
embed.addField('Old Tier -> New Tier', `${account.tier} -> 1`, true); embed.addField('Old Tier -> New Tier', `${account.tier} -> 1`, true);
embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL); embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL());
embed.setTimestamp(); embed.setTimestamp();
await this.server.client.util.sendMessageToUserTerminal(account.username, 'A technician has changed your tier.').catch(() => { }); await this.server.client.util.sendMessageToUserTerminal(account.username, 'A technician has changed your tier.').catch(() => { });
this.server.client.createMessage('580950455581147146', { embed }); const ch = this.server.client.channels.cache.get('580950455581147146') as TextChannel;
this.server.client.getDMChannel(account.userID).then((channel) => channel.createMessage({ embed })).catch(); ch.send({ embeds: [embed] });
this.server.client.users.cache.get(account.userID).send({ embeds: [embed] });
return res.sendStatus(200); return res.sendStatus(200);
}); });

View File

@ -20,15 +20,15 @@ export default class AccountUtil {
* @param moderator The Discord user ID for the Staff member that created the account. * @param moderator The Discord user ID for the Staff member that created the account.
*/ */
public async createAccount(data: { userID: string, username: string, emailAddress: string }, moderator: string): Promise<{ account: AccountInterface, tempPass: string }> { public async createAccount(data: { userID: string, username: string, emailAddress: string }, moderator: string): Promise<{ account: AccountInterface, tempPass: string }> {
const moderatorMember = this.client.guilds.get('446067825673633794').members.get(moderator); const moderatorMember = this.client.guilds.cache.get('446067825673633794').members.cache.get(moderator);
const tempPass = this.client.util.randomPassword(); const tempPass = this.client.util.randomPassword();
let passHash = await this.client.util.createHash(tempPass); passHash = passHash.replace(/[$]/g, '\\$').replace('\n', ''); const passHash = (await this.client.util.createHash(tempPass)).replace(/[$]/g, '\\$').replace('\n', '');
const acctName = this.client.users.get(data.userID).username.replace(/[!@#$%^&*(),.?":{}|<>]/g, '-').replace(/\s/g, '-'); const acctName = this.client.users.cache.get(data.userID).username.replace(/[!@#$%^&*(),.?":{}|<>]/g, '-').replace(/\s/g, '-');
const etcPasswd = `${acctName},${data.userID},,`; const etcPasswd = `${acctName},${data.userID},,`;
const code = randomBytes(3).toString('hex').toUpperCase(); const code = randomBytes(3).toString('hex').toUpperCase();
const accountInterface = await this.client.util.createAccount(passHash, etcPasswd, data.username, data.userID, data.emailAddress, moderator, code); const accountInterface = await this.client.util.createAccount(passHash, etcPasswd, data.username, data.userID, data.emailAddress, moderator, code);
await this.client.util.createModerationLog(data.userID, moderatorMember, 0); await this.client.util.createModerationLog(data.userID, moderatorMember.user, 0);
const req = await axios.get('https://loc.sh/int/directory'); const req = await axios.get('https://loc.sh/int/directory');
const find = req.data.find((mem) => mem.userID === moderator); const find = req.data.find((mem) => mem.userID === moderator);
@ -67,13 +67,14 @@ export default class AccountUtil {
<h3>Want to support us?</h3> <h3>Want to support us?</h3>
<p>You can support us by purchasing a Tier 3 subscription! <a target="_blank" href="https://canary.discord.com/channels/446067825673633794/620355063088414769/774938174001774592">this site</a> for more information.</p> <p>You can support us by purchasing a Tier 3 subscription! <a target="_blank" href="https://canary.discord.com/channels/446067825673633794/620355063088414769/774938174001774592">this site</a> for more information.</p>
<b><i>Library of Code sp-us | Support Team</i></b> <b><i>Library of Code sp-us | Support Team</i></b>
</body> </body>
`, `,
}); });
const guild = this.client.guilds.cache.get('446067825673633794');
this.client.guilds.get('446067825673633794').members.get(data.userID).addRole('546457886440685578'); const member = guild.members.cache.get(data.userID);
const dmChannel = await this.client.getDMChannel(data.userID).catch(); await member.roles.add('546457886440685578');
dmChannel.createMessage('<:loc:607695848612167700> **Thank you for creating an account with us!** <:loc:607695848612167700>\n' const user = this.client.users.cache.get(data.userID);
user.send('<:loc:607695848612167700> **Thank you for creating an account with us!** <:loc:607695848612167700>\n'
+ `Please log into your account by running \`ssh ${data.username}@cloud.libraryofcode.org\` in your terminal, then use the password \`${tempPass}\` to log in.\n` + `Please log into your account by running \`ssh ${data.username}@cloud.libraryofcode.org\` 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` + `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\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\n'
@ -90,7 +91,7 @@ export default class AccountUtil {
await this.client.util.exec(`lock ${account.username}`); await this.client.util.exec(`lock ${account.username}`);
await account.updateOne({ locked: true }); await account.updateOne({ locked: true });
await this.client.util.createModerationLog(account.userID, this.client.users.get(moderatorID), 2, data?.reason, data?.time); await this.client.util.createModerationLog(account.userID, this.client.users.cache.get(moderatorID), 2, data?.reason, data?.time);
this.client.util.transport.sendMail({ this.client.util.transport.sendMail({
to: account.emailAddress, to: account.emailAddress,
@ -101,9 +102,9 @@ export default class AccountUtil {
<h1>Library of Code | Cloud Services</h1> <h1>Library of Code | Cloud Services</h1>
<p>Your Cloud Account has been locked until ${data?.time ? moment(data?.time).calendar() : 'indefinitely'} under the EULA.</p> <p>Your Cloud Account has been locked until ${data?.time ? moment(data?.time).calendar() : 'indefinitely'} under the EULA.</p>
<p><b>Reason:</b> ${data?.reason ? data.reason : 'none provided'}</p> <p><b>Reason:</b> ${data?.reason ? data.reason : 'none provided'}</p>
<p><b>Technician:</b> ${moderatorID !== this.client.user.id ? this.client.users.get(moderatorID).username : 'SYSTEM'}</p> <p><b>Technician:</b> ${moderatorID !== this.client.user.id ? (this.client.users.cache.get(moderatorID).username) : 'SYSTEM'}</p>
<p><b>Expiration:</b> ${data?.time ? moment(data?.time).format('dddd, MMMM Do YYYY, h:mm:ss A') : 'N/A'}</p> <p><b>Expiration:</b> ${data?.time ? moment(data?.time).format('dddd, MMMM Do YYYY, h:mm:ss A') : 'N/A'}</p>
<b><i>Library of Code sp-us | Support Team</i></b> <b><i>Library of Code sp-us | Support Team</i></b>
`, `,
}); });

View File

@ -1,4 +1,4 @@
import Eris from 'eris'; import { Client as DiscordClient, Intents } from 'discord.js';
import Redis from 'ioredis'; import Redis from 'ioredis';
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import signale from 'signale'; import signale from 'signale';
@ -8,8 +8,7 @@ import { Account, AccountInterface, Moderation, ModerationInterface, Domain, Dom
import { emojis } from '../stores'; import { emojis } from '../stores';
import { Command, CSCLI, Util, Collection, Server, Event } from '.'; import { Command, CSCLI, Util, Collection, Server, Event } from '.';
export default class Client extends DiscordClient {
export default class Client extends Eris.Client {
public config: { 'token': string; 'cloudflare': string; 'prefix': string; 'emailPass': string; 'mongoURL': string; 'port': number; 'keyPair': { 'publicKey': string; 'privateKey': string; }; vendorKey: string; internalKey: string; }; public config: { 'token': string; 'cloudflare': string; 'prefix': string; 'emailPass': string; 'mongoURL': string; 'port': number; 'keyPair': { 'publicKey': string; 'privateKey': string; }; vendorKey: string; internalKey: string; };
public util: Util; public util: Util;
@ -35,7 +34,36 @@ export default class Client extends Eris.Client {
public buildError: boolean public buildError: boolean
constructor() { constructor() {
super(config.token, { getAllUsers: true, restMode: true, defaultImageFormat: 'png', intents: ['guildBans', 'guildEmojis', 'guildInvites', 'guildMembers', 'guildMessageReactions', 'guildMessages', 'guildPresences', 'guildWebhooks', 'guilds', 'directMessages'] }); super({
shards: 'auto',
intents: [
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MEMBERS,
Intents.FLAGS.GUILD_BANS,
Intents.FLAGS.GUILD_EMOJIS_AND_STICKERS,
Intents.FLAGS.GUILD_WEBHOOKS,
Intents.FLAGS.GUILD_INVITES,
Intents.FLAGS.GUILD_INTEGRATIONS,
Intents.FLAGS.GUILD_PRESENCES,
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
Intents.FLAGS.DIRECT_MESSAGES,
],
partials: [
'USER',
'CHANNEL',
'GUILD_MEMBER',
'MESSAGE',
'REACTION',
],
allowedMentions: {
parse: [
'users',
'roles',
],
repliedUser: false,
},
});
process.title = 'cloudservices'; process.title = 'cloudservices';
this.config = config; this.config = config;
@ -74,7 +102,7 @@ export default class Client extends Eris.Client {
const funcRequire: Function = require(`${__dirname}/../functions/${func}`).default; const funcRequire: Function = require(`${__dirname}/../functions/${func}`).default;
this.functions.set(func.split('.')[0], funcRequire); this.functions.set(func.split('.')[0], funcRequire);
} catch (error) { } catch (error) {
this.signale.error(`Error occured loading ${func}`); this.signale.error(`Error occurred loading ${func}`);
await this.util.handleError(error); await this.util.handleError(error);
} }
}); });
@ -83,7 +111,6 @@ export default class Client extends Eris.Client {
public loadCommand(CommandFile: any) { public loadCommand(CommandFile: any) {
// eslint-disable-next-line no-useless-catch // eslint-disable-next-line no-useless-catch
try { try {
// eslint-disable-next-line
const command: Command = new CommandFile(this); const command: Command = new CommandFile(this);
if (command.subcmds.length) { if (command.subcmds.length) {
command.subcmds.forEach((C) => { command.subcmds.forEach((C) => {
@ -126,19 +153,17 @@ export default class Client extends Eris.Client {
public async init() { public async init() {
await mongoose.connect(config.mongoURL, { useNewUrlParser: true, useUnifiedTopology: true }); await mongoose.connect(config.mongoURL, { useNewUrlParser: true, useUnifiedTopology: true });
await this.connect(); await this.login(config.token);
this.on('ready', () => { this.on('ready', () => {
this.signale.info(`Connected to Discord as ${this.user.username}#${this.user.discriminator}`); this.signale.info(`Connected to Discord as ${this.user.username}#${this.user.discriminator}`);
}); });
const intervals = await fs.readdir(`${__dirname}/../intervals`); const intervals = await fs.readdir(`${__dirname}/../intervals`);
intervals.forEach((interval) => { intervals.forEach((interval) => {
// eslint-disable-next-line
if (interval === 'index.js') return; if (interval === 'index.js') return;
require(`${__dirname}/../intervals/${interval}`).default(this); require(`${__dirname}/../intervals/${interval}`).default(this);
this.signale.complete(`Loaded interval ${interval.split('.')[0]}`); this.signale.complete(`Loaded interval ${interval.split('.')[0]}`);
}); });
this.server = new Server(this, { port: this.config.port }); this.server = new Server(this, { port: this.config.port });
// eslint-disable-next-line no-new
const corepath = '/opt/CloudServices/dist'; const corepath = '/opt/CloudServices/dist';
const cmdFiles = await fs.readdir('/opt/CloudServices/dist/commands'); const cmdFiles = await fs.readdir('/opt/CloudServices/dist/commands');

View File

@ -1,4 +1,4 @@
import { Message, TextableChannel } from 'eris'; import { Message, TextBasedChannels } from 'discord.js';
import { Client, Collection } from '.'; import { Client, Collection } from '.';
export default class Command { export default class Command {
@ -39,15 +39,15 @@ export default class Command {
this.permissions = {}; this.permissions = {};
} }
public success(channel: TextableChannel, txt: string) { public success(channel: TextBasedChannels, txt: string) {
return channel.createMessage(`***${this.client.stores.emojis.success} ${txt}***`); return channel.send(`***${this.client.stores.emojis.success} ${txt}***`);
} }
public loading(channel: TextableChannel, txt: string) { public loading(channel: TextBasedChannels, txt: string) {
return channel.createMessage(`***${this.client.stores.emojis.loading} ${txt}***`); return channel.send(`***${this.client.stores.emojis.loading} ${txt}***`);
} }
public error(channel: TextableChannel, txt: string) { public error(channel: TextBasedChannels, txt: string) {
return channel.createMessage(`***${this.client.stores.emojis.error} ${txt}***`); return channel.send(`***${this.client.stores.emojis.error} ${txt}***`);
} }
} }

View File

@ -5,9 +5,8 @@ import { gzip, gzipSync, unzip } from 'zlib';
type JSONData = [{key: string, value: any}?]; type JSONData = [{key: string, value: any}?];
/** /**
* Persistant local JSON-based storage. * Persistent local JSON-based storage.
* - auto-locking system to prevent corrupted data * - auto-locking system to prevent corrupted data
* - uses gzip compression to keep DB storage space utilization low * - uses gzip compression to keep DB storage space utilization low
* @author Matthew <matthew@staff.libraryofcode.org> * @author Matthew <matthew@staff.libraryofcode.org>

View File

@ -0,0 +1,56 @@
import { Message, MessageEmbed, EmojiResolvable, User, MessageReaction } from 'discord.js';
export default async function PaginationEmbed(message: Message, pages: MessageEmbed[], options?: {leftArrow?: EmojiResolvable, rightArrow?: EmojiResolvable, timeout?: number }) {
// eslint-disable-next-line no-param-reassign
options = {
leftArrow: options?.leftArrow ?? '⬅️',
rightArrow: options?.rightArrow ?? '➡️',
timeout: options?.timeout ?? 120000,
};
let pageNumber: number = 0;
const paginationMessage = await message.channel.send({ content: `Page ${pageNumber + 1} of ${pages.length}`, embeds: [pages[pageNumber]] });
await paginationMessage.react(options.leftArrow);
await paginationMessage.react(options.rightArrow);
const filter = (reaction: MessageReaction, user: User) => {
if ([options.leftArrow, options.rightArrow].includes(reaction.emoji.name)
&& !user.bot
&& user.id === message.author.id) {
return true;
}
return false;
};
const reactionCollector = paginationMessage.createReactionCollector({
filter,
time: options.timeout,
dispose: true,
});
reactionCollector.on('collect', (reaction, user) => {
reaction.users.remove(user);
if (reaction.emoji.name === options.leftArrow) {
if (pageNumber > 0) {
pageNumber -= 1;
} else {
pageNumber = pages.length - 1;
}
} else if (reaction.emoji.name === options.rightArrow) {
if (pageNumber + 1 < pages.length) {
pageNumber += 1;
} else {
pageNumber = 0;
}
}
paginationMessage.edit({ content: `Page ${pageNumber + 1} / ${pages.length}`, embeds: [pages[pageNumber]] });
});
reactionCollector.on('end', () => {
if (!paginationMessage.deleted) {
paginationMessage.reactions.removeAll();
}
});
return paginationMessage;
}

View File

@ -104,7 +104,7 @@ export default class Report {
* @param pin The last 4 digits of the member's PIN number. * @param pin The last 4 digits of the member's PIN number.
* @param reason A reason for the hard inquiry. * @param reason A reason for the hard inquiry.
* ```ts * ```ts
* Report.hard('253600545972027394', 1102, 'Verification and Elibility for Personal Account'); * Report.hard('253600545972027394', 1102, 'Verification and Eligibility for Personal Account');
* ``` * ```
*/ */
public static async hard(userID: string, pin: number, reason: string, auth: string): Promise<HardReport> { public static async hard(userID: string, pin: number, reason: string, auth: string): Promise<HardReport> {

View File

@ -1,176 +0,0 @@
/* eslint-disable no-param-reassign */
export default class RichEmbed {
title?: string
type?: string
description?: string
url?: string
timestamp?: Date
color?: number
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}
fields?: {name: string, value: string, inline?: boolean}[]
constructor(data: {
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},
} = {}) {
/*
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.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;
}
/**
* Sets the title of this embed.
*/
setTitle(title: string) {
if (typeof title !== 'string') throw new TypeError('RichEmbed titles must be a string.');
if (title.length > 256) throw new RangeError('RichEmbed titles may not exceed 256 characters.');
this.title = title;
return this;
}
/**
* Sets the description of this embed.
*/
setDescription(description: string) {
if (typeof description !== 'string') throw new TypeError('RichEmbed descriptions must be a string.');
if (description.length > 2048) throw new RangeError('RichEmbed descriptions may not exceed 2048 characters.');
this.description = description;
return this;
}
/**
* Sets the URL of this embed.
*/
setURL(url: string) {
if (typeof url !== 'string') throw new TypeError('RichEmbed URLs must be a string.');
if (!url.startsWith('http://') || !url.startsWith('https://')) url = `https://${url}`;
this.url = url;
return this;
}
/**
* Sets the color of this embed.
*/
setColor(color: string | number) {
if (typeof color === 'string' || typeof color === 'number') {
if (typeof color === 'string') {
const regex = /[^a-f0-9]/gi;
color = color.replace(/#/g, '');
if (regex.test(color)) throw new RangeError('Hexadecimal colours must not contain characters other than 0-9 and a-f.');
color = parseInt(color, 16);
} else if (color < 0 || color > 16777215) throw new RangeError('Base 10 colours must not be less than 0 or greater than 16777215.');
this.color = color;
return this;
}
throw new TypeError('RichEmbed colours must be hexadecimal as string or number.');
}
/**
* Sets the author of this embed.
*/
setAuthor(name: string, icon_url?: string, url?: string) {
if (typeof name !== 'string') throw new TypeError('RichEmbed Author names must be a string.');
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;
}
/**
* Sets the timestamp of this embed.
*/
setTimestamp(timestamp = new Date()) {
// eslint-disable-next-line no-restricted-globals
if (isNaN(timestamp.getTime())) throw new TypeError('Expecting ISO8601 (Date constructor)');
this.timestamp = timestamp;
return this;
}
/**
* Adds a field to the embed (max 25).
*/
addField(name: string, value: string, inline = false) {
if (typeof name !== 'string') throw new TypeError('RichEmbed Field names must be a string.');
if (typeof value !== 'string') throw new TypeError('RichEmbed Field values must be a string.');
if (typeof inline !== 'boolean') throw new TypeError('RichEmbed Field inlines must be a boolean.');
if (this.fields.length >= 25) throw new RangeError('RichEmbeds may not exceed 25 fields.');
if (name.length > 256) throw new RangeError('RichEmbed field names may not exceed 256 characters.');
if (!/\S/.test(name)) throw new RangeError('RichEmbed field names may not be empty.');
if (value.length > 1024) throw new RangeError('RichEmbed field values may not exceed 1024 characters.');
if (!/\S/.test(value)) throw new RangeError('RichEmbed field values may not be empty.');
this.fields.push({ name, value, inline });
return this;
}
/**
* Convenience function for `<RichEmbed>.addField('\u200B', '\u200B', inline)`.
*/
addBlankField(inline = false) {
return this.addField('\u200B', '\u200B', inline);
}
/**
* Set the thumbnail of this embed.
*/
setThumbnail(url: string) {
if (typeof url !== 'string') throw new TypeError('RichEmbed Thumbnail URLs must be a string.');
this.thumbnail = { url };
return this;
}
/**
* Set the image of this embed.
*/
setImage(url: string) {
if (typeof url !== 'string') throw new TypeError('RichEmbed Image URLs must be a string.');
if (!url.startsWith('http://') || !url.startsWith('https://')) url = `https://${url}`;
this.image = { url };
return this;
}
/**
* Sets the footer of this embed.
*/
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 (text.length > 2048) throw new RangeError('RichEmbed footer text may not exceed 2048 characters.');
this.footer = { text, icon_url };
return this;
}
}

View File

@ -1,152 +1,152 @@
/* eslint-disable consistent-return */ /* eslint-disable consistent-return */
import { Request, Response, NextFunction, Router as router } from 'express'; import { Request, Response, NextFunction, Router as router } from 'express';
import { Server } from '.'; import { Server } from '.';
export default class Route { export default class Route {
public server: Server; public server: Server;
public router: router; public router: router;
public conf: { path: string, deprecated?: boolean, maintenance?: boolean }; public conf: { path: string, deprecated?: boolean, maintenance?: boolean };
protected constructor(server: Server, conf: { path: string, deprecated?: boolean, maintenance?: boolean }) { protected constructor(server: Server, conf: { path: string, deprecated?: boolean, maintenance?: boolean }) {
this.conf = { this.conf = {
path: null, path: null,
deprecated: false, deprecated: false,
maintenance: false, maintenance: false,
}; };
this.server = server; this.server = server;
this.router = router(); this.router = router();
this.conf = conf; this.conf = conf;
} }
public bind() {} public bind() {}
public deprecated(): void { public deprecated(): void {
this.router.all('*', (_req, res) => { this.router.all('*', (_req, res) => {
res.status(501).json({ code: this.constants.codes.DEPRECATED, message: this.constants.messages.DEPRECATED }); res.status(501).json({ code: this.constants.codes.DEPRECATED, message: this.constants.messages.DEPRECATED });
}); });
} }
public maintenance(): void { public maintenance(): void {
this.router.all('*', (_req, res) => { this.router.all('*', (_req, res) => {
res.status(503).json({ code: this.constants.codes.MAINTENANCE_OR_UNAVAILABLE, message: this.constants.messages.MAINTENANCE_OR_UNAVAILABLE }); res.status(503).json({ code: this.constants.codes.MAINTENANCE_OR_UNAVAILABLE, message: this.constants.messages.MAINTENANCE_OR_UNAVAILABLE });
}); });
} }
public init(): void { public init(): void {
this.router.all('*', (req, res, next) => { this.router.all('*', (req, res, next) => {
// this.server.client.signale.log(`'${req.method}' request from '${req.ip}' to '${req.hostname}${req.path}'.`); this.server.client.signale.log(`'${req.method}' request from '${req.ip}' to '${req.hostname}${req.path}'.`);
if (this.conf.maintenance === true) res.status(503).json({ code: this.constants.codes.MAINTENANCE_OR_UNAVAILABLE, message: this.constants.messages.MAINTENANCE_OR_UNAVAILABLE }); if (this.conf.maintenance === true) res.status(503).json({ code: this.constants.codes.MAINTENANCE_OR_UNAVAILABLE, message: this.constants.messages.MAINTENANCE_OR_UNAVAILABLE });
else if (this.conf.deprecated === true) res.status(501).json({ code: this.constants.codes.DEPRECATED, message: this.constants.messages.DEPRECATED }); else if (this.conf.deprecated === true) res.status(501).json({ code: this.constants.codes.DEPRECATED, message: this.constants.messages.DEPRECATED });
else next(); else next();
}); });
} }
/** /**
* This function checks for the presense of a Bearer token with Security.extractBearer(), * This function checks for the presence of a Bearer token with Security.extractBearer(),
* then it will attempt to validate it with Security.checkBearer(). * then it will attempt to validate it with Security.checkBearer().
* If it can authenticate the request, it'll add a custom property on Request called * If it can authenticate the request, it'll add a custom property on Request called
* `account`, which will hold an the bearer token's account owner. The account is of the * `account`, which will hold an the bearer token's account owner. The account is of the
* type `AccountInterface`. * type `AccountInterface`.
* @param req The Request object from Express. * @param req The Request object from Express.
* @param res The Response object from Express. * @param res The Response object from Express.
* @param next The NextFunction from Express. * @param next The NextFunction from Express.
* @example Security.authorize(req, res, next); * @example Security.authorize(req, res, next);
*/ */
public async authorize(req: Request, res: Response, next: NextFunction) { public async authorize(req: Request, res: Response, next: NextFunction) {
const account = await this.server.security.checkBearer(this.server.security.extractBearer(req)); const account = await this.server.security.checkBearer(this.server.security.extractBearer(req));
if (!account) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); if (!account) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED });
Object.defineProperty(req, 'account', { value: account, writable: true, enumerable: true, configurable: true }); Object.defineProperty(req, 'account', { value: account, writable: true, enumerable: true, configurable: true });
next(); next();
} }
/** /**
* This function calls Util.handleError() internally, however it also sends a generic * This function calls Util.handleError() internally, however it also sends a generic
* response to the user. * response to the user.
* @param error The Error object. * @param error The Error object.
* @param res The Response object from Express. * @param res The Response object from Express.
*/ */
public handleError(error: Error, res: Response): void { public handleError(error: Error, res: Response): void {
this.server.client.util.handleError(error); this.server.client.util.handleError(error);
res.status(500).json({ code: this.constants.codes.SERVER_ERROR, message: this.constants.messages.SERVER_ERROR }); res.status(500).json({ code: this.constants.codes.SERVER_ERROR, message: this.constants.messages.SERVER_ERROR });
} }
get constants() { get constants() {
return { return {
codes: { codes: {
/** /**
* SUCCESS 100 * SUCCESS 100
* Used if the request was processed successfully. * Used if the request was processed successfully.
*/ */
SUCCESS: 100, SUCCESS: 100,
/** /**
* UNAUTHORIZED 101 * UNAUTHORIZED 101
* Used if the client calling the request couldn't be correctly authenticated. * Used if the client calling the request couldn't be correctly authenticated.
*/ */
UNAUTHORIZED: 101, UNAUTHORIZED: 101,
/** /**
* PERMISSION DENIED 103 * PERMISSION DENIED 103
* Used if the client calling the request doesn't have access to the resource specified. * Used if the client calling the request doesn't have access to the resource specified.
*/ */
PERMISSION_DENIED: 103, PERMISSION_DENIED: 103,
/** /**
* NOT FOUND 104 * NOT FOUND 104
* Used if the resource the client requested doesn't exist. * Used if the resource the client requested doesn't exist.
*/ */
NOT_FOUND: 104, NOT_FOUND: 104,
/** /**
* ACCOUNT NOT FOUND 1041 * ACCOUNT NOT FOUND 1041
* Used if the account specified by the client couldn't be found. * Used if the account specified by the client couldn't be found.
*/ */
ACCOUNT_NOT_FOUND: 1041, ACCOUNT_NOT_FOUND: 1041,
/** /**
* CLIENT ERROR 1044 * CLIENT ERROR 1044
* Used in cases of user error. Examples are incorrect parameters, incorrect headers, or an invalid request. * Used in cases of user error. Examples are incorrect parameters, incorrect headers, or an invalid request.
*/ */
CLIENT_ERROR: 1044, CLIENT_ERROR: 1044,
/** /**
* SERVER ERROR 105 * SERVER ERROR 105
* Used in cases of an internal error that caused the bind() function to throw. * Used in cases of an internal error that caused the bind() function to throw.
*/ */
SERVER_ERROR: 105, SERVER_ERROR: 105,
/** /**
* DEPRECATED 1051 * DEPRECATED 1051
* Returned back to the user if the resource requested is deprecated. * Returned back to the user if the resource requested is deprecated.
*/ */
DEPRECATED: 1051, DEPRECATED: 1051,
/** /**
* MAINTENANCE OR UNAVAILABLE 1053 * MAINTENANCE OR UNAVAILABLE 1053
* Used if the resource requested is currently in maintenance, not finished, or temporarily disabled. * Used if the resource requested is currently in maintenance, not finished, or temporarily disabled.
*/ */
MAINTENANCE_OR_UNAVAILABLE: 1053, MAINTENANCE_OR_UNAVAILABLE: 1053,
}, },
messages: { messages: {
/** /**
* The credentials you supplied are invalid. * The credentials you supplied are invalid.
*/ */
UNAUTHORIZED: ['CREDENTIALS_INVALID', 'The credentials you supplied are invalid.'], UNAUTHORIZED: ['CREDENTIALS_INVALID', 'The credentials you supplied are invalid.'],
/** /**
* You do not have valid credentials to access this resource. * You do not have valid credentials to access this resource.
*/ */
PERMISSION_DENIED: ['PERMISSION_DENIED', 'You do not have valid credentials to access this resource.'], PERMISSION_DENIED: ['PERMISSION_DENIED', 'You do not have valid credentials to access this resource.'],
/** /**
* The resource you requested cannot be located. * The resource you requested cannot be located.
*/ */
NOT_FOUND: ['NOT_FOUND', 'The resource you requested cannot be located.'], NOT_FOUND: ['NOT_FOUND', 'The resource you requested cannot be located.'],
/** /**
* An internal error has occurred, Engineers have been notified. * An internal error has occurred, Engineers have been notified.
*/ */
SERVER_ERROR: ['INTERNAL_ERROR', 'An internal error has occurred, Engineers have been notified.'], SERVER_ERROR: ['INTERNAL_ERROR', 'An internal error has occurred, Engineers have been notified.'],
/** /**
* The endpoint or resource you\'re trying to access has been deprecated. * The endpoint or resource you\'re trying to access has been deprecated.
*/ */
DEPRECATED: ['ENDPOINT_OR_RESOURCE_DEPRECATED', 'The endpoint or resource you\'re trying to access has been deprecated.'], DEPRECATED: ['ENDPOINT_OR_RESOURCE_DEPRECATED', 'The endpoint or resource you\'re trying to access has been deprecated.'],
/** /**
* The endpoint or resource you\'re trying to access is either in maintenance or is not available. * The endpoint or resource you\'re trying to access is either in maintenance or is not available.
*/ */
MAINTENANCE_OR_UNAVAILABLE: ['SERVICE_UNAVAILABLE', 'The endpoint or resource you\'re trying to access is either in maintenance or is not available.'], MAINTENANCE_OR_UNAVAILABLE: ['SERVICE_UNAVAILABLE', 'The endpoint or resource you\'re trying to access is either in maintenance or is not available.'],
}, },
}; };
} }
} }

View File

@ -6,7 +6,6 @@ import fs from 'fs-extra';
import { Client, Collection, LocalStorage, Route } from '.'; import { Client, Collection, LocalStorage, Route } from '.';
import { Security } from '../api'; import { Security } from '../api';
export default class Server { export default class Server {
public routes: Collection<Route> public routes: Collection<Route>

View File

@ -5,14 +5,14 @@ import axios from 'axios';
import { randomBytes } from 'crypto'; import { randomBytes } from 'crypto';
import childProcess from 'child_process'; import childProcess from 'child_process';
import nodemailer from 'nodemailer'; import nodemailer from 'nodemailer';
import { Message, PrivateChannel, GroupChannel, Member, User } from 'eris'; import { Message, DMChannel, User, MessageEmbed, ColorResolvable, TextChannel } from 'discord.js';
import uuid from 'uuid/v4'; import { v4 as uuid } from 'uuid';
import moment from 'moment'; import moment from 'moment';
import fs from 'fs'; import fs from 'fs';
import hastebin from 'hastebin-gen'; import hastebin from 'hastebin-gen';
import { getUserByUid } from '../functions'; import { getUserByUid } from '../functions';
import { AccountUtil, Client, Command, RichEmbed } from '.'; import { AccountUtil, Client, Command, PaginationEmbed } from '.';
import { ModerationInterface, AccountInterface, Account } from '../models'; import { ModerationInterface, AccountInterface } from '../models';
import { Certificate } from '../../types/x509'; import { Certificate } from '../../types/x509';
export default class Util { export default class Util {
@ -96,7 +96,6 @@ export default class Util {
return returnArray; return returnArray;
} }
/** /**
* Resolves a command * Resolves a command
* @param query Command input * @param query Command input
@ -131,29 +130,32 @@ export default class Util {
this.client.signale.error(error); this.client.signale.error(error);
const info = { content: `\`\`\`js\n${error.stack}\n\`\`\``, embed: null }; const info = { content: `\`\`\`js\n${error.stack}\n\`\`\``, embed: null };
if (message) { if (message) {
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setColor('FF0000'); embed.setColor('#FF0000');
embed.setAuthor(`Error caused by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL); embed.setAuthor(`Error caused by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL());
embed.setTitle('Message content'); embed.setTitle('Message content');
embed.setDescription(message.content); embed.setDescription(message.content);
embed.addField('User', `${message.author.mention} (\`${message.author.id}\`)`, true); embed.addField('User', `${message.author.toString()} (\`${message.author.id}\`)`, true);
embed.addField('Channel', message.channel.mention, true); embed.addField('Channel', `<#${message.channel.id}>`, true);
let guild: string; let guild: string;
if (message.channel instanceof PrivateChannel || message.channel instanceof GroupChannel) guild = '@me'; if (message.channel instanceof DMChannel) guild = '@me';
else guild = message.channel.guild.id; else guild = message.guild.id;
embed.addField('Message link', `[Click here](https://discordapp.com/channels/${guild}/${message.channel.id}/${message.id})`, true); embed.addField('Message link', `[Click here](https://discordapp.com/channels/${guild}/${message.channel.id}/${message.id})`, true);
embed.setTimestamp(new Date(message.timestamp)); embed.setTimestamp(new Date(message.createdTimestamp));
info.embed = embed; info.embed = embed;
} }
await this.client.createMessage('595788220764127272', info); const ch = this.client.channels.cache.get('595788220764127272') as TextChannel;
await ch.send(info);
const msg = message.content.slice(this.client.config.prefix.length).trim().split(/ +/g); const msg = message.content.slice(this.client.config.prefix.length).trim().split(/ +/g);
if (command) this.resolveCommand(msg).then((c) => { c.cmd.enabled = false; }); if (command) this.resolveCommand(msg).then((c) => { c.cmd.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.' : ''}***`); if (message) message.channel.send(`***${this.client.stores.emojis.error} An unexpected error has occurred - please contact a member of the Engineering Team.${command ? ' This command has been disabled.' : ''}***`);
} catch (err) { } catch (err) {
this.client.signale.error(err); this.client.signale.error(err);
} }
} }
public createPaginationEmbed = PaginationEmbed;
public splitFields(fields: { name: string, value: string, inline?: boolean }[]): { name: string, value: string, inline?: boolean }[][] { public splitFields(fields: { name: string, value: string, inline?: boolean }[]): { name: string, value: string, inline?: boolean }[][] {
let index = 0; let index = 0;
const array: {name: string, value: string, inline?: boolean}[][] = [[]]; const array: {name: string, value: string, inline?: boolean}[][] = [[]];
@ -181,7 +183,6 @@ export default class Util {
return arrayString; return arrayString;
} }
public async createHash(password: string): Promise<string> { public async createHash(password: string): Promise<string> {
const hashed = await this.exec(`mkpasswd -m sha-512 "${password}"`); const hashed = await this.exec(`mkpasswd -m sha-512 "${password}"`);
return hashed; return hashed;
@ -220,13 +221,15 @@ export default class Util {
this.exec(`deluser ${username} --remove-home --backup-to /management/Archives && rm -rf -R ${account.homepath}`), this.exec(`deluser ${username} --remove-home --backup-to /management/Archives && rm -rf -R ${account.homepath}`),
this.client.db.Account.deleteOne({ username }), this.client.db.Account.deleteOne({ username }),
]; ];
this.client.removeGuildMemberRole('446067825673633794', account.userID, '546457886440685578', 'Cloud Account Deleted').catch(); const guild = this.client.guilds.cache.get('446067825673633794');
const member = await guild.members.fetch(account.userID);
await member.roles.remove('546457886440685578', 'Cloud Account Deleted');
// @ts-ignore // @ts-ignore
await Promise.all(tasks); await Promise.all(tasks);
} }
public async messageCollector(message: Message, question: string, timeout: number, shouldDelete = false, choices: string[] = null, filter = (msg: Message): boolean|void => {}): Promise<Message> { 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); const msg = await message.channel.send(question);
return new Promise((res, rej) => { return new Promise((res, rej) => {
const func = (Msg: Message) => { const func = (Msg: Message) => {
if (filter(Msg) === false) return; if (filter(Msg) === false) return;
@ -253,7 +256,7 @@ export default class Util {
* *
* `4` - Delete * `4` - Delete
*/ */
public async createModerationLog(user: string, moderator: Member|User, type: number, reason?: string, duration?: number): Promise<ModerationInterface> { public async createModerationLog(user: string, moderator: User, type: number, reason?: string, duration?: number): Promise<ModerationInterface> {
const moderatorID = moderator.id; const moderatorID = moderator.id;
const account = await this.client.db.Account.findOne({ $or: [{ username: user }, { userID: user }] }); const account = await this.client.db.Account.findOne({ $or: [{ username: user }, { userID: user }] });
if (!account) return Promise.reject(new Error(`Account ${user} not found`)); if (!account) return Promise.reject(new Error(`Account ${user} not found`));
@ -280,28 +283,30 @@ export default class Util {
await log.save(); await log.save();
let embedTitle: string; let embedTitle: string;
let color: string; let color: ColorResolvable;
let archType: string; let archType: string;
switch (type) { switch (type) {
default: archType = 'Staff'; embedTitle = 'Cloud Account | Generic'; color = '0892e1'; break; default: archType = 'Staff'; embedTitle = 'Cloud Account | Generic'; color = '#0892e1'; break;
case 0: archType = 'Technician'; embedTitle = 'Cloud Account | Create'; color = '00ff00'; break; case 0: archType = 'Technician'; embedTitle = 'Cloud Account | Create'; color = '#00ff00'; break;
case 1: archType = 'Technician'; embedTitle = 'Account Warning | Warn'; color = 'ffff00'; break; case 1: archType = 'Technician'; embedTitle = 'Account Warning | Warn'; color = '#ffff00'; break;
case 2: archType = 'Technician'; embedTitle = 'Account Infraction | Lock'; color = 'ff6600'; break; case 2: archType = 'Technician'; embedTitle = 'Account Infraction | Lock'; color = '#ff6600'; break;
case 3: archType = 'Technician'; embedTitle = 'Account Reclaim | Unlock'; color = '0099ff'; break; case 3: archType = 'Technician'; embedTitle = 'Account Reclaim | Unlock'; color = '#0099ff'; break;
case 4: archType = 'Director'; embedTitle = 'Cloud Account | Delete'; color = 'ff0000'; break; case 4: archType = 'Director'; embedTitle = 'Cloud Account | Delete'; color = '#ff0000'; break;
} }
const req = await axios.get('https://loc.sh/int/directory'); const req = await axios.get('https://loc.sh/int/directory');
const find = req.data.find((mem) => mem.userID === moderator.id); const find = req.data.find((mem) => mem.userID === moderator.id);
const embed = new RichEmbed() const embed = new MessageEmbed()
.setTitle(embedTitle) .setTitle(embedTitle)
.setColor(color) .setColor(color)
.addField('User', `${username} | <@${userID}>`, true) .addField('User', `${username} | <@${userID}>`, true)
.addField(archType, moderatorID === this.client.user.id ? 'SYSTEM' : `${moderator.username}, ${find.pn.join(', ')} (<@${moderatorID}>)`, true) .addField(archType, moderatorID === this.client.user.id ? 'SYSTEM' : `${moderator.username}, ${find.pn.join(', ')} (<@${moderatorID}>)`, true)
.setFooter(this.client.user.username, this.client.user.avatarURL) .setFooter(this.client.user.username, this.client.user.avatarURL())
.setTimestamp(); .setTimestamp();
if (reason) embed.addField('Reason', reason || 'Not specified'); if (reason) embed.addField('Reason', reason || 'Not specified');
if (type === 2) embed.addField('Lock Expiration', `${date ? moment(date).format('dddd, MMMM Do YYYY, h:mm:ss A') : 'Indefinitely'}`); if (type === 2) embed.addField('Lock Expiration', `${date ? moment(date).format('dddd, MMMM Do YYYY, h:mm:ss A') : 'Indefinitely'}`);
this.client.createMessage('580950455581147146', { embed }); this.client.getDMChannel(userID).then((channel) => channel.createMessage({ embed })).catch(); const ch = this.client.channels.cache.get('580950455581147146') as TextChannel;
ch.send({ embeds: [embed] });
this.client.users.fetch(userID).then((channel) => channel.send({ embeds: [embed] })).catch();
return Promise.resolve(log); return Promise.resolve(log);
} }

View File

@ -8,8 +8,8 @@ export { default as Event } from './Event';
export { default as Handler } from './Handler'; export { default as Handler } from './Handler';
export { default as LocalStorage } from './LocalStorage'; export { default as LocalStorage } from './LocalStorage';
export { default as Report } from './Report'; export { default as Report } from './Report';
export { default as RichEmbed } from './RichEmbed';
export { default as Route } from './Route'; export { default as Route } from './Route';
export { default as Security } from './Security'; export { default as Security } from './Security';
export { default as Server } from './Server'; export { default as Server } from './Server';
export { default as Util } from './Util'; export { default as Util } from './Util';
export { default as PaginationEmbed } from './PaginationEmbed';

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message, TextChannel } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class AddReferral extends Command { export default class AddReferral extends Command {
@ -19,10 +19,10 @@ export default class AddReferral extends Command {
if (!account) return this.error(message.channel, 'Cannot find user.'); if (!account) return this.error(message.channel, 'Cannot find user.');
await account.updateOne({ $inc: { totalReferrals: 1 } }); await account.updateOne({ $inc: { totalReferrals: 1 } });
this.client.getDMChannel(account.userID).then((chan) => { this.client.users.fetch(account.userID).then((chan) => {
chan.createMessage('__**Referral - Application Approval**__\nAn applicant who used your referral code during the application process has been approved. Your referral count has been increased.'); chan.send('__**Referral - Application Approval**__\nAn applicant who used your referral code during the application process has been approved. Your referral count has been increased.');
}).catch(() => {}); }).catch(() => {});
return this.success(message.channel, `Added referral value to account.\nReferrer: \`${account.username}\` | <@${account.userID}>`); return this.success(message.channel as TextChannel, `Added referral value to account.\nReferrer: \`${account.username}\` | <@${account.userID}>`);
} catch (error) { } catch (error) {
return this.client.util.handleError(error, message, this); return this.client.util.handleError(error, message, this);
} }

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class Announce extends Command { export default class Announce extends Command {

View File

@ -1,6 +1,6 @@
/* eslint-disable no-useless-escape */ /* eslint-disable no-useless-escape */
import { Message } from 'eris'; import { Message, MessageEmbed, TextChannel } from 'discord.js';
import { Client, Command, Report, RichEmbed } from '../class'; import { Client, Command, Report } from '../class';
export default class ApplyT2 extends Command { export default class ApplyT2 extends Command {
constructor(client: Client) { constructor(client: Client) {
@ -24,7 +24,7 @@ export default class ApplyT2 extends Command {
const decision = await Report.tier2(account.userID, this.client.config.internalKey); const decision = await Report.tier2(account.userID, this.client.config.internalKey);
if (decision.status === 'SUCCESS') { if (decision.status === 'SUCCESS') {
await loading.delete(); await loading.delete();
message.channel.createMessage(`__**Decision**__\n\n**Status:** ${decision.decision}\n**Processed by:** EDS (A\*01)`); message.channel.send(`__**Decision**__\n\n**Status:** ${decision.decision}\n**Processed by:** EDS (A\*01)`);
if (decision.decision === 'APPROVED') { if (decision.decision === 'APPROVED') {
const tier = await this.client.db.Tier.findOne({ id: 2 }); const tier = await this.client.db.Tier.findOne({ id: 2 });
@ -33,21 +33,23 @@ export default class ApplyT2 extends Command {
} else { } else {
await account.updateOne({ $set: { tier: 2 } }); await account.updateOne({ $set: { tier: 2 } });
} }
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('Cloud Account | Tier Change'); embed.setTitle('Cloud Account | Tier Change');
embed.setColor('#0099ff'); embed.setColor('#0099ff');
embed.addField('User', `${account.username} | <@${account.userID}>`, true); embed.addField('User', `${account.username} | <@${account.userID}>`, true);
embed.addField('Technician', 'SYSTEM', true); embed.addField('Technician', 'SYSTEM', true);
embed.addField('Old Tier -> New Tier', `${account.tier} -> 2`, true); embed.addField('Old Tier -> New Tier', `${account.tier} -> 2`, true);
embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setFooter(this.client.user.username, this.client.user.avatarURL());
embed.setTimestamp(); embed.setTimestamp();
await this.client.util.sendMessageToUserTerminal(account.username, 'A technician has changed your tier to 2').catch(() => { }); await this.client.util.sendMessageToUserTerminal(account.username, 'A technician has changed your tier to 2').catch(() => { });
this.client.createMessage('580950455581147146', { embed }); return this.client.getDMChannel(account.userID).then((channel) => channel.createMessage({ embed })).catch(); const ch = this.client.channels.cache.get('580950455581147146') as TextChannel;
ch.send({ embeds: [embed] });
return this.client.users.fetch(account.userID).then((channel) => channel.send({ embeds: [embed] })).catch();
} }
return null; return null;
} }
await loading.delete(); await loading.delete();
return message.channel.createMessage(`__**Decision**__\n\n**Status:** ${decision.decision}\n**Processed by:** EDS (A*01)\n\n\n*Pre-Declines will not result in a hard pull, and they may be due to a server issue or insufficient information. You may want to contact a Staff member for further information.*`); return message.channel.send(`__**Decision**__\n\n**Status:** ${decision.decision}\n**Processed by:** EDS (A*01)\n\n\n*Pre-Declines will not result in a hard pull, and they may be due to a server issue or insufficient information. You may want to contact a Staff member for further information.*`);
} catch (error) { } catch (error) {
return this.client.util.handleError(error, message, this); return this.client.util.handleError(error, message, this);
} }

View File

@ -1,5 +1,5 @@
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class AuthReferral extends Command { export default class AuthReferral extends Command {
@ -18,13 +18,23 @@ export default class AuthReferral extends Command {
if (!args.length) return this.client.commands.get('help').run(message, [this.name]); if (!args.length) return this.client.commands.get('help').run(message, [this.name]);
const referrer = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { referralCode: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] }); const referrer = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { referralCode: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] });
if (!referrer) return this.error(message.channel, 'Cannot find referrer.'); if (!referrer) return this.error(message.channel, 'Cannot find referrer.');
const referred = await this.client.getRESTGuildMember('446067825673633794', args[1]); const referred = await message.guild.members.fetch(args[1]);
if (!referred) return this.error(message.channel, 'Cannot find referred member.'); if (!referred) return this.error(message.channel, 'Cannot find referred member.');
const token = jwt.sign({ staffUserID: message.author.id, referralCode: referrer.referralCode, referrerUserID: referrer.userID, referrerUsername: referrer.username, referredUserID: referred.id, referredUserAndDiscrim: `${referred.username}#${referred.discriminator}` }, this.client.config.keyPair.privateKey, { expiresIn: '24 hours', issuer: 'Library of Code sp-us | Cloud Services Daemon' }); const token = jwt.sign(
this.client.getDMChannel(referrer.userID).then(async (chan) => { { staffUserID: message.author.id,
await chan.createMessage(`__**Referral Request Authorization**__\nYour referral code has been used in an application recently submitted to us. We need to authorize this request, please visit https://loc.sh/rv and enter the authorization token below. This token expires in 24 hours. If you did not authorize this request, please contact us immediately by DMing Ramirez or opening a ticket at https://loc.sh/cs-help.\n**Referred User:** ${referred.username}#${referred.discriminator} | <@${referred.user.id}>`); referralCode: referrer.referralCode,
await chan.createMessage(`\`${token}\``); referrerUserID: referrer.userID,
referrerUsername: referrer.username,
referredUserID: referred.id,
referredUserAndDiscrim: `${referred.user.username}#${referred.user.discriminator}` },
this.client.config.keyPair.privateKey, { expiresIn: '24 hours', issuer: 'Library of Code sp-us | Cloud Services Daemon' },
);
this.client.users.fetch(referrer.userID).then(async (user) => {
await user.send('__**Referral Request Authorization**__\n'
+ 'Your referral code has been used in an application recently submitted to us. We need to authorize this request, please visit https://loc.sh/rv and enter the authorization token below. This token expires in 24 hours. If you did not authorize this request, please contact us immediately by DMing Ramirez or opening a ticket at https://loc.sh/cs-help.\n'
+ `**Referred User:** ${referred.user.username}#${referred.user.discriminator} | ${referred.user.toString()}`);
await user.send(`\`${token}\``);
}).catch(() => { }).catch(() => {
this.error(message.channel, 'Could not DM referrer.'); this.error(message.channel, 'Could not DM referrer.');
}); });

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
import Bearer_Revoke from './bearer_revoke'; import Bearer_Revoke from './bearer_revoke';
@ -19,8 +19,8 @@ export default class Bearer extends Command {
if (!account) return this.error(message.channel, 'Account not found.'); if (!account) return this.error(message.channel, 'Account not found.');
// eslint-disable-next-line no-underscore-dangle // eslint-disable-next-line no-underscore-dangle
const bearer = await this.client.server.security.createBearer(account._id); const bearer = await this.client.server.security.createBearer(account._id);
const dm = await this.client.getDMChannel(message.author.id); const dm = await this.client.users.fetch(message.author.id);
const msg = await dm.createMessage(`__**Library of Code sp-us | Cloud Services [API]**__\n*This message will automatically be deleted in 60 seconds, copy the token and save it. You cannot recover it.*\n\n${bearer}`); const msg = await dm.send(`__**Library of Code sp-us | Cloud Services [API]**__\n*This message will automatically be deleted in 60 seconds, copy the token and save it. You cannot recover it.*\n\n${bearer}`);
this.success(message.channel, 'Bearer token sent to direct messages.'); this.success(message.channel, 'Bearer token sent to direct messages.');
return setTimeout(() => { return setTimeout(() => {
msg.delete(); msg.delete();

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class Bearer_Revoke extends Command { export default class Bearer_Revoke extends Command {

View File

@ -1,5 +1,5 @@
import axios from 'axios'; import axios from 'axios';
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class Cloudflare extends Command { export default class Cloudflare extends Command {

View File

@ -1,4 +1,4 @@
import { Message, PrivateChannel, GroupChannel } from 'eris'; import { GuildMember, Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class CreateAccount extends Command { export default class CreateAccount extends Command {
@ -20,10 +20,10 @@ export default class CreateAccount extends Command {
public async run(message: Message, args: string[]) { public async run(message: Message, args: string[]) {
try { try {
if (message.channel instanceof PrivateChannel || message.channel instanceof GroupChannel) return message; // Stop TS being gay
if (!args[2]) return this.client.commands.get('help').run(message, [this.name]); if (!args[2]) return this.client.commands.get('help').run(message, [this.name]);
if (!message.channel.guild.members.has(args[0])) return this.error(message.channel, 'User not found.'); const member: GuildMember = await message.guild.members.fetch(args[0]);
if (message.channel.guild.members.get(args[0]).bot) return this.error(message.channel, 'I cannot create accounts for bots.'); if (!member) return this.error(message.channel, 'User not found.');
if (member.user.bot) return this.error(message.channel, 'I cannot create accounts for bots.');
const checkUser = await this.client.db.Account.findOne({ userID: args[0] }); const checkUser = await this.client.db.Account.findOne({ userID: args[0] });
if (checkUser) return this.error(message.channel, `<@${args[0]}> already has an account.`); if (checkUser) return this.error(message.channel, `<@${args[0]}> already has an account.`);
const checkEmail = await this.client.db.Account.findOne({ emailAddress: args[1] }); const checkEmail = await this.client.db.Account.findOne({ emailAddress: args[1] });

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
import Create from './cwg_create'; import Create from './cwg_create';
import Data from './cwg_data'; import Data from './cwg_data';

View File

@ -1,9 +1,9 @@
import fs, { writeFile, unlink } from 'fs-extra'; import fs, { writeFile, unlink } from 'fs-extra';
import axios from 'axios'; import axios from 'axios';
import { randomBytes } from 'crypto'; import { randomBytes } from 'crypto';
import { Message } from 'eris'; import { Message, MessageEmbed, TextChannel } from 'discord.js';
import { AccountInterface } from '../models'; import { AccountInterface } from '../models';
import { Client, Command, RichEmbed } from '../class'; import { Client, Command } from '../class';
import { parseCertificate } from '../functions'; import { parseCertificate } from '../functions';
export default class CWG_Create extends Command { export default class CWG_Create extends Command {
@ -45,7 +45,7 @@ export default class CWG_Create extends Command {
try { try {
answer = await this.client.util.messageCollector( answer = await this.client.util.messageCollector(
message, message,
`***${this.client.stores.emojis.error} This port is already binded to a domain. Do you wish to continue? (y/n)***`, `***${this.client.stores.emojis.error} This port is already bound to a domain. Do you wish to continue? (y/n)***`,
30000, true, ['y', 'n'], (msg) => msg.author.id === message.author.id && msg.channel.id === message.channel.id, 30000, true, ['y', 'n'], (msg) => msg.author.id === message.author.id && msg.channel.id === message.channel.id,
); );
} catch (error) { } catch (error) {
@ -80,12 +80,12 @@ export default class CWG_Create extends Command {
// @ts-ignore // @ts-ignore
await Promise.all(tasks); await Promise.all(tasks);
const embed = new RichEmbed() const embed = new MessageEmbed()
.setTitle('Domain Creation') .setTitle('Domain Creation')
.setColor(3066993) .setColor(3066993)
.addField('Account Username', `${account.username} | <@${account.userID}>`, true) .addField('Account Username', `${account.username} | <@${account.userID}>`, true)
.addField('Account ID', account.id, true) .addField('Account ID', account.id, true)
.addField('Technician', `<@${message.author.id}>`, true) .addField('Technician', message.author.toString(), true)
.addField('Domain', domain.domain, true) .addField('Domain', domain.domain, true)
.addField('Port', String(domain.port), true); .addField('Port', String(domain.port), true);
@ -95,37 +95,37 @@ export default class CWG_Create extends Command {
embed.addField('Certificate Issuer', cert.issuer.organizationName, true) embed.addField('Certificate Issuer', cert.issuer.organizationName, true)
.addField('Certificate Subject', cert.subject.commonName, true) .addField('Certificate Subject', cert.subject.commonName, true)
.setFooter(this.client.user.username, this.client.user.avatarURL) .setFooter(this.client.user.username, this.client.user.avatarURL())
.setTimestamp(new Date(message.timestamp)); .setTimestamp(new Date(message.createdTimestamp));
const completed = [ const completed = [
edit.edit(`***${this.client.stores.emojis.success} Successfully binded ${domain.domain} to port ${domain.port} for ${account.username}.***`), edit.edit(`***${this.client.stores.emojis.success} Successfully bound ${domain.domain} to port ${domain.port} for ${account.username}.***`),
this.client.createMessage('580950455581147146', { embed }), (this.client.channels.cache.get('580950455581147146') as TextChannel).send({ embeds: [embed] }),
this.client.getDMChannel(account.userID).then((r) => r.createMessage({ embed })), this.client.users.fetch(account.userID).then((r) => r.send({ embeds: [embed] })),
this.client.util.transport.sendMail({ this.client.util.transport.sendMail({
to: account.emailAddress, to: account.emailAddress,
from: 'Library of Code sp-us | Support Team <help@libraryofcode.org>', from: 'Library of Code sp-us | Support Team <help@libraryofcode.org>',
subject: 'Your domain has been binded', subject: 'Your domain has been bound',
html: ` html: `
<h1>Library of Code sp-us | Cloud Services</h1> <h1>Library of Code sp-us | Cloud Services</h1>
<p>Hello, this is an email informing you that a new domain under your account has been binded. <p>Hello, this is an email informing you that a new domain under your account has been bound.
Information is below.</p> Information is below.</p>
<b>Domain:</b> ${domain.domain}<br> <b>Domain:</b> ${domain.domain}<br>
<b>Port:</b> ${domain.port}<br> <b>Port:</b> ${domain.port}<br>
<b>Certificate Issuer:</b> ${cert.issuer.organizationName}<br> <b>Certificate Issuer:</b> ${cert.issuer.organizationName}<br>
<b>Certificate Subject:</b> ${cert.subject.commonName}<br> <b>Certificate Subject:</b> ${cert.subject.commonName}<br>
<b>Responsible Engineer:</b> ${message.author.username}#${message.author.discriminator}<br><br> <b>Responsible Engineer:</b> ${message.author.username}#${message.author.discriminator}<br><br>
If you have any questions about additional setup, you can reply to this email or send a message in #cloud-support in our Discord server.<br> If you have any questions about additional setup, you can reply to this email or send a message in #cloud-support in our Discord server.<br>
<b><i>Library of Code sp-us | Support Team</i></b> <b><i>Library of Code sp-us | Support Team</i></b>
`, `,
}), }),
]; ];
if (!domain.domain.includes('cloud.libraryofcode.org')) { if (!domain.domain.includes('cloud.libraryofcode.org')) {
const content = `__**DNS Record Setup**__\nYou recently a binded a custom domain to your Library of Code sp-us Account. You'll have to update your DNS records. We've provided the records below.\n\n\`${domain.domain} IN CNAME cloud.libraryofcode.org AUTO/500\`\nThis basically means you need to make a CNAME record with the key/host of ${domain.domain} and the value/point to cloud.libraryofcode.org. If you have any questions, don't hesitate to ask us.`; const content = `__**DNS Record Setup**__\nYou recently a bound a custom domain to your Library of Code sp-us Account. You'll have to update your DNS records. We've provided the records below.\n\n\`${domain.domain} IN CNAME cloud.libraryofcode.org AUTO/500\`\nThis basically means you need to make a CNAME record with the key/host of ${domain.domain} and the value/point to cloud.libraryofcode.org. If you have any questions, don't hesitate to ask us.`;
completed.push(this.client.getDMChannel(account.userID).then((r) => r.createMessage(content))); completed.push(this.client.users.fetch(account.userID).then((r) => r.send(content)));
} }
return Promise.all(completed); return Promise.all(completed);
@ -194,23 +194,23 @@ export default class CWG_Create extends Command {
return { cert: `/etc/ssl/certs/cwg/${domain}.chain.crt`, key: `/etc/ssl/private/cwg/${domain}.key.pem` }; return { cert: `/etc/ssl/certs/cwg/${domain}.chain.crt`, key: `/etc/ssl/private/cwg/${domain}.key.pem` };
} }
public checkOccurance(text: string, query: string) { public checkOccurrence(text: string, query: string) {
return (text.match(new RegExp(query, 'g')) || []).length; return (text.match(new RegExp(query, 'g')) || []).length;
} }
public isValidCertificateChain(cert: string) { public isValidCertificateChain(cert: string) {
if (!cert.replace(/^\s+|\s+$/g, '').startsWith('-----BEGIN CERTIFICATE-----')) return false; if (!cert.replace(/^\s+|\s+$/g, '').startsWith('-----BEGIN CERTIFICATE-----')) return false;
if (!cert.replace(/^\s+|\s+$/g, '').endsWith('-----END CERTIFICATE-----')) return false; if (!cert.replace(/^\s+|\s+$/g, '').endsWith('-----END CERTIFICATE-----')) return false;
if (this.checkOccurance(cert.replace(/^\s+|\s+$/g, ''), '-----BEGIN CERTIFICATE-----') !== 2) return false; if (this.checkOccurrence(cert.replace(/^\s+|\s+$/g, ''), '-----BEGIN CERTIFICATE-----') !== 2) return false;
if (this.checkOccurance(cert.replace(/^\s+|\s+$/g, ''), '-----END CERTIFICATE-----') !== 2) return false; if (this.checkOccurrence(cert.replace(/^\s+|\s+$/g, ''), '-----END CERTIFICATE-----') !== 2) return false;
return true; return true;
} }
public isValidPrivateKey(key: string) { public isValidPrivateKey(key: string) {
if (!key.replace(/^\s+|\s+$/g, '').startsWith('-----BEGIN PRIVATE KEY-----') && !key.replace(/^\s+|\s+$/g, '').startsWith('-----BEGIN RSA PRIVATE KEY-----') && !key.replace(/^\s+|\s+$/g, '').startsWith('-----BEGIN ECC PRIVATE KEY-----')) return false; if (!key.replace(/^\s+|\s+$/g, '').startsWith('-----BEGIN PRIVATE KEY-----') && !key.replace(/^\s+|\s+$/g, '').startsWith('-----BEGIN RSA PRIVATE KEY-----') && !key.replace(/^\s+|\s+$/g, '').startsWith('-----BEGIN ECC PRIVATE KEY-----')) return false;
if (!key.replace(/^\s+|\s+$/g, '').endsWith('-----END PRIVATE KEY-----') && !key.replace(/^\s+|\s+$/g, '').endsWith('-----END RSA PRIVATE KEY-----') && !key.replace(/^\s+|\s+$/g, '').endsWith('-----END ECC PRIVATE KEY-----')) return false; if (!key.replace(/^\s+|\s+$/g, '').endsWith('-----END PRIVATE KEY-----') && !key.replace(/^\s+|\s+$/g, '').endsWith('-----END RSA PRIVATE KEY-----') && !key.replace(/^\s+|\s+$/g, '').endsWith('-----END ECC PRIVATE KEY-----')) return false;
if ((this.checkOccurance(key.replace(/^\s+|\s+$/g, ''), '-----BEGIN PRIVATE KEY-----') !== 1) && (this.checkOccurance(key.replace(/^\s+|\s+$/g, ''), '-----BEGIN RSA PRIVATE KEY-----') !== 1) && (this.checkOccurance(key.replace(/^\s+|\s+$/g, ''), '-----BEGIN ECC PRIVATE KEY-----') !== 1)) return false; if ((this.checkOccurrence(key.replace(/^\s+|\s+$/g, ''), '-----BEGIN PRIVATE KEY-----') !== 1) && (this.checkOccurrence(key.replace(/^\s+|\s+$/g, ''), '-----BEGIN RSA PRIVATE KEY-----') !== 1) && (this.checkOccurrence(key.replace(/^\s+|\s+$/g, ''), '-----BEGIN ECC PRIVATE KEY-----') !== 1)) return false;
if ((this.checkOccurance(key.replace(/^\s+|\s+$/g, ''), '-----END PRIVATE KEY-----') !== 1) && (this.checkOccurance(key.replace(/^\s+|\s+$/g, ''), '-----END RSA PRIVATE KEY-----') !== 1) && (this.checkOccurance(key.replace(/^\s+|\s+$/g, ''), '-----END ECC PRIVATE KEY-----') !== 1)) return false; if ((this.checkOccurrence(key.replace(/^\s+|\s+$/g, ''), '-----END PRIVATE KEY-----') !== 1) && (this.checkOccurrence(key.replace(/^\s+|\s+$/g, ''), '-----END RSA PRIVATE KEY-----') !== 1) && (this.checkOccurrence(key.replace(/^\s+|\s+$/g, ''), '-----END ECC PRIVATE KEY-----') !== 1)) return false;
return true; return true;
} }

View File

@ -1,8 +1,7 @@
import fs from 'fs'; import fs from 'fs';
import moment from 'moment'; import moment from 'moment';
import { createPaginationEmbed } from 'eris-pagination'; import { Message, MessageEmbed } from 'discord.js';
import { Message } from 'eris'; import { Client, Command, PaginationEmbed } from '../class';
import { Client, Command, RichEmbed } from '../class';
export default class CWG_Data extends Command { export default class CWG_Data extends Command {
constructor(client: Client) { constructor(client: Client) {
@ -32,7 +31,7 @@ export default class CWG_Data extends Command {
const embeds = await Promise.all(dom.map(async (domain) => { const embeds = await Promise.all(dom.map(async (domain) => {
const pem = fs.readFileSync(domain.x509.cert, { encoding: 'utf8' }); const pem = fs.readFileSync(domain.x509.cert, { encoding: 'utf8' });
const cert = await this.client.util.parseCertificate(pem); const cert = await this.client.util.parseCertificate(pem);
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('Domain Information'); embed.setTitle('Domain Information');
embed.addField('Account Username', domain.account.username, true); embed.addField('Account Username', domain.account.username, true);
embed.addField('Account ID', domain.account.userID, true); embed.addField('Account ID', domain.account.userID, true);
@ -41,13 +40,13 @@ export default class CWG_Data extends Command {
embed.addField('Certificate Issuer', cert.data.issuer.organization[0], true); embed.addField('Certificate Issuer', cert.data.issuer.organization[0], true);
embed.addField('Certificate Subject', cert.data.issuer.commonName, true); embed.addField('Certificate Subject', cert.data.issuer.commonName, true);
embed.addField('Certificate Expiration Date', moment(cert.data.notAfter).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); embed.addField('Certificate Expiration Date', moment(cert.data.notAfter).format('dddd, MMMM Do YYYY, h:mm:ss A'), true);
embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setFooter(this.client.user.username, this.client.user.avatarURL());
embed.setTimestamp(); embed.setTimestamp();
return embed; return embed;
})); }));
this.client.signale.log(embeds); this.client.signale.log(embeds);
if (embeds.length === 1) return message.channel.createMessage({ embed: embeds[0] }); if (embeds.length === 1) return message.channel.send({ embeds: [embeds[0]] });
return createPaginationEmbed(message, embeds); return this.client.util.createPaginationEmbed(message, embeds);
} catch (error) { } catch (error) {
return this.client.util.handleError(error, message, this); return this.client.util.handleError(error, message, this);
} }

View File

@ -1,7 +1,7 @@
import fs from 'fs-extra'; import fs from 'fs-extra';
import axios from 'axios'; import axios from 'axios';
import { Message } from 'eris'; import { Message, MessageEmbed, TextChannel } from 'discord.js';
import { Client, Command, RichEmbed } from '../class'; import { Client, Command } from '../class';
export default class CWG_Delete extends Command { export default class CWG_Delete extends Command {
constructor(client: Client) { constructor(client: Client) {
@ -20,13 +20,13 @@ export default class CWG_Delete extends Command {
const domain = await this.client.db.Domain.findOne({ $or: [{ domain: args[0] }, { port: Number(args[0]) || 0 }] }); const domain = await this.client.db.Domain.findOne({ $or: [{ domain: args[0] }, { port: Number(args[0]) || 0 }] });
if (!domain) return this.error(message.channel, 'The domain or port you provided could not be found.'); if (!domain) return this.error(message.channel, 'The domain or port you provided could not be found.');
const edit = await this.loading(message.channel, 'Deleting domain...'); const edit = await this.loading(message.channel, 'Deleting domain...');
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('Domain Deletion'); embed.setTitle('Domain Deletion');
embed.addField('Account Username', `${domain.account.username} | <@${domain.account.userID}>`, true); embed.addField('Account Username', `${domain.account.username} | <@${domain.account.userID}>`, true);
embed.addField('Account ID', domain.account.userID, true); embed.addField('Account ID', domain.account.userID, true);
embed.addField('Domain', domain.domain, true); embed.addField('Domain', domain.domain, true);
embed.addField('Port', String(domain.port), true); embed.addField('Port', String(domain.port), true);
embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setFooter(this.client.user.username, this.client.user.avatarURL());
embed.setTimestamp(); embed.setTimestamp();
if (domain.domain.includes('cloud.libraryofcode.org')) { if (domain.domain.includes('cloud.libraryofcode.org')) {
const resultID = await axios({ const resultID = await axios({
@ -51,8 +51,9 @@ export default class CWG_Delete extends Command {
await this.client.db.Domain.deleteOne({ domain: domain.domain }); await this.client.db.Domain.deleteOne({ domain: domain.domain });
await this.client.util.exec('systemctl reload nginx'); await this.client.util.exec('systemctl reload nginx');
edit.edit(`***${this.client.stores.emojis.success} Domain ${domain.domain} with port ${domain.port} has been successfully deleted.***`); edit.edit(`***${this.client.stores.emojis.success} Domain ${domain.domain} with port ${domain.port} has been successfully deleted.***`);
this.client.createMessage('580950455581147146', { embed }); const ch = this.client.channels.cache.get('580950455581147146') as TextChannel;
return this.client.getDMChannel(domain.account.userID).then((channel) => channel.createMessage({ embed })).catch(() => {}); ch.send({ embeds: [embed] });
return this.client.users.fetch(domain.account.userID).then((u) => u.send({ embeds: [embed] })).catch(() => {});
} catch (error) { } catch (error) {
return this.client.util.handleError(error, message, this); return this.client.util.handleError(error, message, this);
} }

View File

@ -1,6 +1,6 @@
import { writeFile, unlink } from 'fs-extra'; import { writeFile, unlink } from 'fs-extra';
import axios from 'axios'; import axios from 'axios';
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class CWG_UpdateCert extends Command { export default class CWG_UpdateCert extends Command {
@ -49,23 +49,23 @@ export default class CWG_UpdateCert extends Command {
} }
} }
public checkOccurance(text: string, query: string) { public checkOccurrence(text: string, query: string) {
return (text.match(new RegExp(query, 'g')) || []).length; return (text.match(new RegExp(query, 'g')) || []).length;
} }
public isValidCertificateChain(cert: string) { public isValidCertificateChain(cert: string) {
if (!cert.replace(/^\s+|\s+$/g, '').startsWith('-----BEGIN CERTIFICATE-----')) return false; if (!cert.replace(/^\s+|\s+$/g, '').startsWith('-----BEGIN CERTIFICATE-----')) return false;
if (!cert.replace(/^\s+|\s+$/g, '').endsWith('-----END CERTIFICATE-----')) return false; if (!cert.replace(/^\s+|\s+$/g, '').endsWith('-----END CERTIFICATE-----')) return false;
if (this.checkOccurance(cert.replace(/^\s+|\s+$/g, ''), '-----BEGIN CERTIFICATE-----') !== 2) return false; if (this.checkOccurrence(cert.replace(/^\s+|\s+$/g, ''), '-----BEGIN CERTIFICATE-----') !== 2) return false;
if (this.checkOccurance(cert.replace(/^\s+|\s+$/g, ''), '-----END CERTIFICATE-----') !== 2) return false; if (this.checkOccurrence(cert.replace(/^\s+|\s+$/g, ''), '-----END CERTIFICATE-----') !== 2) return false;
return true; return true;
} }
public isValidPrivateKey(key: string) { public isValidPrivateKey(key: string) {
if (!key.replace(/^\s+|\s+$/g, '').startsWith('-----BEGIN PRIVATE KEY-----')) return false; if (!key.replace(/^\s+|\s+$/g, '').startsWith('-----BEGIN PRIVATE KEY-----')) return false;
if (!key.replace(/^\s+|\s+$/g, '').endsWith('-----END PRIVATE KEY-----')) return false; if (!key.replace(/^\s+|\s+$/g, '').endsWith('-----END PRIVATE KEY-----')) return false;
if (this.checkOccurance(key.replace(/^\s+|\s+$/g, ''), '-----BEGIN PRIVATE KEY-----') !== 1) return false; if (this.checkOccurrence(key.replace(/^\s+|\s+$/g, ''), '-----BEGIN PRIVATE KEY-----') !== 1) return false;
if (this.checkOccurance(key.replace(/^\s+|\s+$/g, ''), '-----END PRIVATE KEY-----') !== 1) return false; if (this.checkOccurrence(key.replace(/^\s+|\s+$/g, ''), '-----END PRIVATE KEY-----') !== 1) return false;
return true; return true;
} }

View File

@ -1,5 +1,5 @@
import { Message, PrivateChannel } from 'eris'; import { Message } from 'discord.js';
import uuid from 'uuid/v4'; import { v4 as uuid } from 'uuid';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class DeleteAccount extends Command { export default class DeleteAccount extends Command {
@ -18,9 +18,9 @@ export default class DeleteAccount extends Command {
try { try {
if (!args[1]) return this.client.commands.get('help').run(message, [this.name]); 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] }] }); 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.***`); if (!account) return message.channel.send(`${this.client.stores.emojis.error} ***Account not found.***`);
const { root, username, userID, emailAddress, homepath } = account; const { root, username, userID, emailAddress, homepath } = account;
if (root) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Permission denied.***`); if (root) return message.channel.send(`${this.client.stores.emojis.error} ***Permission denied.***`);
const pad = (number: number, amount: number): string => '0'.repeat(amount - number.toString().length) + number; const pad = (number: number, amount: number): string => '0'.repeat(amount - number.toString().length) + number;
const randomNumber = Math.floor(Math.random() * 9999); const randomNumber = Math.floor(Math.random() * 9999);
@ -28,17 +28,17 @@ export default class DeleteAccount extends Command {
try { try {
await this.client.util.messageCollector(message, await this.client.util.messageCollector(message,
`***Please confirm that you are permanently deleting ${username}'s account by entering ${verify}. This action cannot be reversed.***`, `***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)); 15000, true, [verify], (msg) => !(msg.author.id === message.author.id));
} catch (error) { } catch (error) {
if (error.message.includes('Did not supply')) return message; if (error.message.includes('Did not supply')) return message;
throw error; throw error;
} }
const deleting = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Deleting account, please wait...***`); const deleting = await message.channel.send(`${this.client.stores.emojis.loading} ***Deleting account, please wait...***`);
const reason = args.slice(1).join(' '); const reason = args.slice(1).join(' ');
const logInput = { username, userID, logID: uuid(), moderatorID: message.author.id, type: 4, date: new Date(), reason: null }; const logInput = { username, userID, logID: uuid(), moderatorID: message.author.id, type: 4, date: new Date(), reason: null };
if (reason) logInput.reason = reason; if (reason) logInput.reason = reason;
await this.client.util.createModerationLog(args[0], message.member, 4, reason); await this.client.util.createModerationLog(args[0], message.author, 4, reason);
await this.client.util.deleteAccount(username); await this.client.util.deleteAccount(username);
message.delete().catch(() => {}); message.delete().catch(() => {});
@ -52,7 +52,7 @@ export default class DeleteAccount extends Command {
<p>Your Cloud Account has been deleted by a Director. If your account was deleted due to infractions, this will not be appealable. We're sorry to see you go.</p> <p>Your Cloud Account has been deleted by a Director. If your account was deleted due to infractions, this will not be appealable. We're sorry to see you go.</p>
<p><b>Reason:</b> ${reason}</p> <p><b>Reason:</b> ${reason}</p>
<p><b>Director:</b> ${message.author.username}</p> <p><b>Director:</b> ${message.author.username}</p>
<b><i>Library of Code sp-us | Support Team</i></b> <b><i>Library of Code sp-us | Support Team</i></b>
`, `,
}); });

View File

@ -1,5 +1,5 @@
import { randomBytes } from 'crypto'; import { randomBytes } from 'crypto';
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class EmailCode extends Command { export default class EmailCode extends Command {
@ -31,7 +31,7 @@ export default class EmailCode extends Command {
<h3>Want to support us?</h3> <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> <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> <b><i>Library of Code sp-us | Support Team</i></b>
</body> </body>
`, `,
}); });
return this.success(message.channel, `Code: \`${code}\` | Email Address: ${args[0]}`); return this.success(message.channel, `Code: \`${code}\` | Email Address: ${args[0]}`);

View File

@ -1,6 +1,6 @@
/* eslint-disable no-eval */ /* eslint-disable no-eval */
import axios from 'axios'; import axios from 'axios';
import { Message } from 'eris'; import { Message } from 'discord.js';
import { inspect } from 'util'; import { inspect } from 'util';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
@ -45,22 +45,21 @@ export default class Eval extends Command {
evaled = error.stack; evaled = error.stack;
} }
evaled = evaled.replace(new RegExp(this.client.config.token, 'gi'), 'juul'); evaled = evaled.replace(new RegExp(this.client.config.token, 'gi'), 'token');
evaled = evaled.replace(new RegExp(this.client.config.emailPass, 'gi'), 'juul'); evaled = evaled.replace(new RegExp(this.client.config.emailPass, 'gi'), 'emailPass');
evaled = evaled.replace(new RegExp(this.client.config.cloudflare, 'gi'), 'juul'); evaled = evaled.replace(new RegExp(this.client.config.cloudflare, 'gi'), 'cloudflare');
const display = this.client.util.splitString(evaled, 1975); const display = this.client.util.splitString(evaled, 1975);
if (display[5]) { if (display[5]) {
try { try {
const { data } = await axios.post('https://snippets.cloud.libraryofcode.org/documents', display.join('')); const { data } = await axios.post('https://snippets.cloud.libraryofcode.org/documents', display.join(''));
return message.channel.createMessage(`${this.client.stores.emojis.success} Your evaluation evaled can be found on https://snippets.cloud.libraryofcode.org/${data.key}`); return message.channel.send(`${this.client.stores.emojis.success} Your evaluation evaled can be found on https://snippets.cloud.libraryofcode.org/${data.key}`);
} catch (error) { } catch (error) {
return message.channel.createMessage(`${this.client.stores.emojis.error} ${error}`); return message.channel.send(`${this.client.stores.emojis.error} ${error}`);
} }
} }
return display.forEach((m) => message.channel.createMessage(`\`\`\`js\n${m}\n\`\`\``)); return display.forEach((m) => message.channel.send(`\`\`\`js\n${m}\n\`\`\``));
} catch (error) { } catch (error) {
return this.client.util.handleError(error, message, this); return this.client.util.handleError(error, message, this);
} }

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import axios from 'axios'; import axios from 'axios';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
@ -38,7 +38,7 @@ export default class Exec extends Command {
} }
await response.delete(); await response.delete();
return splitResult.forEach((m) => message.channel.createMessage(`\`\`\`bash\n${m}\n\`\`\``)); return splitResult.forEach((m) => message.channel.send(`\`\`\`bash\n${m}\n\`\`\``));
} catch (error) { } catch (error) {
return this.client.util.handleError(error, message, this); return this.client.util.handleError(error, message, this);
} }

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class GetReferral extends Command { export default class GetReferral extends Command {
@ -16,8 +16,8 @@ export default class GetReferral extends Command {
const account = await this.client.db.Account.findOne({ userID: message.author.id }); const account = await this.client.db.Account.findOne({ userID: message.author.id });
if (!account) return this.error(message.channel, 'You do not have a Cloud Services account.'); if (!account) return this.error(message.channel, 'You do not have a Cloud Services account.');
return this.client.getDMChannel(message.author.id).then((chan) => { return this.client.users.fetch(message.author.id).then((u) => {
chan.createMessage(`__**CS Account Referral Code**__\n*Referral codes are considered to be somewhat private information. Applicants with referral codes have a greater chance of approval, don't refer someone you don't trust :).*\nYour referral code: \`${account.referralCode}\`\nReferrals Granted: \`${account.totalReferrals ? account.totalReferrals : '0'}\``); u.send(`__**CS Account Referral Code**__\n*Referral codes are considered to be somewhat private information. Applicants with referral codes have a greater chance of approval, don't refer someone you don't trust :).*\nYour referral code: \`${account.referralCode}\`\nReferrals Granted: \`${account.totalReferrals ? account.totalReferrals : '0'}\``);
}).catch(() => this.error(message.channel, 'Could not send you a DM.')); }).catch(() => this.error(message.channel, 'Could not send you a DM.'));
} catch (err) { } catch (err) {
return this.client.util.handleError(err, message, this); return this.client.util.handleError(err, message, this);

View File

@ -1,6 +1,5 @@
import { Message } from 'eris'; import { Message, MessageEmbed } from 'discord.js';
import { createPaginationEmbed } from 'eris-pagination'; import { Client, Command } from '../class';
import { Client, Command, RichEmbed } from '../class';
export default class Help extends Command { export default class Help extends Command {
constructor(client: Client) { constructor(client: Client) {
@ -21,44 +20,45 @@ export default class Help extends Command {
const commands = this.client.commands.map((c) => { const commands = this.client.commands.map((c) => {
const aliases = c.aliases.map((alias) => `${this.client.config.prefix}${alias}`).join(', '); const aliases = c.aliases.map((alias) => `${this.client.config.prefix}${alias}`).join(', ');
const perms: string[] = []; const perms: string[] = [];
let allowedRoles = c.permissions && c.permissions.roles && c.permissions.roles.map((r) => `<@&${r}>`).join(', '); let allowedRoles = c.permissions && c.permissions.roles && c.permissions.roles.map((r) => r.toString()).join(', ');
if (allowedRoles) { allowedRoles = `**Roles:** ${allowedRoles}`; perms.push(allowedRoles); } if (allowedRoles) { allowedRoles = `**Roles:** ${allowedRoles}`; perms.push(allowedRoles); }
let allowedUsers = c.permissions && c.permissions.users && c.permissions.users.map((u) => `<@${u}>`).join(', '); let allowedUsers = c.permissions && c.permissions.users && c.permissions.users.map((u) => u.toString()).join(', ');
if (allowedUsers) { allowedUsers = `**Users:** ${allowedUsers}`; perms.push(allowedUsers); } if (allowedUsers) { allowedUsers = `**Users:** ${allowedUsers}`; perms.push(allowedUsers); }
const displayedPerms = perms.length ? `**Permissions:**\n${perms.join('\n')}` : ''; 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: false }; 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); const splitCommands = this.client.util.splitFields(commands);
const cmdPages: RichEmbed[] = []; const cmdPages: MessageEmbed[] = [];
splitCommands.forEach((splitCmd) => { splitCommands.forEach((splitCmd) => {
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTimestamp(); embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL); embed.setTimestamp();
embed.setAuthor(`${this.client.user.username}#${this.client.user.discriminator}`, this.client.user.avatarURL); embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL());
embed.setAuthor(`${this.client.user.username}#${this.client.user.discriminator}`, this.client.user.avatarURL());
embed.setDescription(`Command list for ${this.client.user.username}`); embed.setDescription(`Command list for ${this.client.user.username}`);
splitCmd.forEach((c) => embed.addField(c.name, c.value, c.inline)); splitCmd.forEach((c) => embed.addField(c.name, c.value, c.inline));
return cmdPages.push(embed); return cmdPages.push(embed);
}); });
if (cmdPages.length === 1) return message.channel.createMessage({ embed: cmdPages[0] }); if (cmdPages.length === 1) return message.channel.send({ embeds: [cmdPages[0]] });
return createPaginationEmbed(message, cmdPages); return this.client.util.createPaginationEmbed(message, cmdPages);
} }
const resolved = await this.client.util.resolveCommand(args, message); const resolved = await this.client.util.resolveCommand(args, message);
if (!resolved) return message.channel.createMessage(`${this.client.stores.emojis.error} **Command not found!**`); if (!resolved) return message.channel.send(`${this.client.stores.emojis.error} **Command not found!**`);
const { cmd } = resolved; const { cmd } = resolved;
const perms: string[] = []; const perms: string[] = [];
let allowedRoles = cmd.permissions && cmd.permissions.roles && cmd.permissions.roles.map((r) => `<@&${r}>`).join(', '); let allowedRoles = cmd.permissions && cmd.permissions.roles && cmd.permissions.roles.map((r) => r.toString()).join(', ');
if (allowedRoles) { allowedRoles = `**Roles:** ${allowedRoles}`; perms.push(allowedRoles); } if (allowedRoles) { allowedRoles = `**Roles:** ${allowedRoles}`; perms.push(allowedRoles); }
let allowedUsers = cmd.permissions && cmd.permissions.users && cmd.permissions.users.map((u) => `<@${u}>`).join(', '); let allowedUsers = cmd.permissions && cmd.permissions.users && cmd.permissions.users.map((u) => u.toString()).join(', ');
if (allowedUsers) { allowedUsers = `**Users:** ${allowedUsers}`; perms.push(allowedUsers); } if (allowedUsers) { allowedUsers = `**Users:** ${allowedUsers}`; perms.push(allowedUsers); }
const displayedPerms = perms.length ? `\n**Permissions:**\n${perms.join('\n')}` : ''; const displayedPerms = perms.length ? `\n**Permissions:**\n${perms.join('\n')}` : '';
const aliases = cmd.aliases.length ? `\n**Aliases:** ${cmd.aliases.map((alias) => `${this.client.config.prefix}${cmd.parentName ? `${cmd.parentName} ` : ''}${alias}`).join(', ')}` : ''; const aliases = cmd.aliases.length ? `\n**Aliases:** ${cmd.aliases.map((alias) => `${this.client.config.prefix}${cmd.parentName ? `${cmd.parentName} ` : ''}${alias}`).join(', ')}` : '';
const subcommands = cmd.subcommands.size ? `\n**Subcommands:** ${cmd.subcommands.map((s) => `${cmd.name} ${s.name}`).join(', ')}` : ''; const subcommands = cmd.subcommands.size ? `\n**Subcommands:** ${cmd.subcommands.map((s) => `${cmd.name} ${s.name}`).join(', ')}` : '';
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTimestamp(); embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL); embed.setTimestamp(); embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL());
embed.setTitle(`${this.client.config.prefix}${cmd.parentName ? `${cmd.parentName}${cmd.name}` : cmd.name}`); embed.setAuthor(`${this.client.user.username}#${this.client.user.discriminator}`, this.client.user.avatarURL); embed.setTitle(`${this.client.config.prefix}${cmd.parentName ? `${cmd.parentName}${cmd.name}` : cmd.name}`); embed.setAuthor(`${this.client.user.username}#${this.client.user.discriminator}`, this.client.user.avatarURL());
const description = `**Description**: ${cmd.description}\n**Usage:** ${cmd.usage}${aliases}${displayedPerms}${subcommands}`; const description = `**Description**: ${cmd.description}\n**Usage:** ${cmd.usage}${aliases}${displayedPerms}${subcommands}`;
embed.setDescription(description); embed.setDescription(description);
message.channel.createMessage({ embed }); message.channel.send({ embeds: [embed] });
} catch (error) { } catch (error) {
this.client.util.handleError(error, message, this); this.client.util.handleError(error, message, this);
} }

View File

@ -1,7 +1,7 @@
import { Message } from 'eris'; import { Message, MessageEmbed } from 'discord.js';
import { totalmem } from 'os'; import { totalmem } from 'os';
import { Client, Command, RichEmbed } from '../class'; import { Client, Command } from '../class';
import { version as erisVersion } from '../../node_modules/eris/package.json'; import { version as discordjsVersion } from '../../node_modules/discord.js/package.json';
import { version as expressVersion } from '../../node_modules/express/package.json'; import { version as expressVersion } from '../../node_modules/express/package.json';
import { version as mongooseVersion } from '../../node_modules/mongoose/package.json'; import { version as mongooseVersion } from '../../node_modules/mongoose/package.json';
import { version as ioredisVersion } from '../../node_modules/ioredis/package.json'; import { version as ioredisVersion } from '../../node_modules/ioredis/package.json';
@ -18,20 +18,20 @@ export default class Info extends Command {
public async run(message: Message) { public async run(message: Message) {
try { try {
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('Information'); embed.setTitle('Information');
embed.setThumbnail(this.client.user.avatarURL); embed.setThumbnail(this.client.user.avatarURL());
embed.addField('Language(s)', '<:ts:604565354554982401> TypeScript, <:Go:703449475405971466> Go', true); embed.addField('Language(s)', '<:ts:604565354554982401> TypeScript, <:Go:703449475405971466> Go', true);
embed.addField('Runtime', `Node (${process.version})`, true); embed.addField('Runtime', `Node (${process.version})`, true);
embed.addField('Compilers/Transpilers', `TypeScript [tsc] (${tscVersion}) | Go [gc] (${await this.client.util.exec('go version')})`, true); embed.addField('Compilers/Transpilers', `TypeScript [tsc] (${tscVersion}) | Go [gc] (${await this.client.util.exec('go version')})`, true);
embed.addField('Process Manager', `SystemD (${(await this.client.util.exec('systemd --version')).split('\n')[0]})`, true); embed.addField('Process Manager', `SystemD (${(await this.client.util.exec('systemd --version')).split('\n')[0]})`, true);
embed.addField('Discord Library', `Eris (${erisVersion})`, true); embed.addField('Discord Library', `Discord.js (${discordjsVersion})`, true);
embed.addField('HTTP Server Library', `Express (${expressVersion})`, true); embed.addField('HTTP Server Library', `Express (${expressVersion})`, true);
embed.addField('Database Library', `MongoDB w/ Mongoose ODM (${mongooseVersion})`, true); embed.addField('Database Library', `MongoDB w/ Mongoose ODM (${mongooseVersion})`, true);
embed.addField('Cache Library', `Redis w/ IORedis (${ioredisVersion})`, true); embed.addField('Cache Library', `Redis w/ IORedis (${ioredisVersion})`, true);
embed.addField('Memory Usage', `${Math.round(process.memoryUsage().rss / 1024 / 1024)} MB / ${Math.round(totalmem() / 1024 / 1024 / 1024)} GB`, true); embed.addField('Memory Usage', `${Math.round(process.memoryUsage().rss / 1024 / 1024)} MB / ${Math.round(totalmem() / 1024 / 1024 / 1024)} GB`, true);
embed.addField('Repository', 'https://loc.sh/csdgit | Licensed under GNU Affero General Public License V3', true); embed.addField('Repository', 'https://loc.sh/csdgit | Licensed under GNU Affero General Public License V3', true);
return message.channel.createMessage({ embed }); return message.channel.send({ embeds: [embed] });
} catch (err) { } catch (err) {
return this.client.util.handleError(err, message, this); return this.client.util.handleError(err, message, this);
} }

View File

@ -1,5 +1,5 @@
import { Message } from 'eris'; import { Message, MessageEmbed } from 'discord.js';
import { Client, Command, RichEmbed } from '../class'; import { Client, Command } from '../class';
import { dataConversion } from '../functions'; import { dataConversion } from '../functions';
import setRamNotification from './limits_setramnotification'; import setRamNotification from './limits_setramnotification';
@ -16,7 +16,7 @@ export default class Limits extends Command {
public async run(message: Message) { public async run(message: Message) {
try { try {
const tiers = await this.client.db.Tier.find(); const tiers = await this.client.db.Tier.find();
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('Resource Limit Information'); embed.setTitle('Resource Limit Information');
const account = await this.client.db.Account.findOne({ userID: message.author.id }); const account = await this.client.db.Account.findOne({ userID: message.author.id });
if (account) { if (account) {
@ -29,12 +29,12 @@ export default class Limits extends Command {
} }
embed.setDescription(`Your resource limit is ${dataConversion(tier.resourceLimits?.ram * 1024 * 1024) ?? '0 B'}.\n${msg}`); embed.setDescription(`Your resource limit is ${dataConversion(tier.resourceLimits?.ram * 1024 * 1024) ?? '0 B'}.\n${msg}`);
} }
embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setFooter(this.client.user.username, this.client.user.avatarURL());
embed.setTimestamp(); embed.setTimestamp();
for (const tier of tiers.sort((a, b) => a.id - b.id)) { for (const tier of tiers.sort((a, b) => a.id - b.id)) {
embed.addField(`Tier ${tier.id}`, `**RAM:** ${dataConversion(tier.resourceLimits?.ram * 1024 * 1024) ?? '0 B'}\n**Storage:** ${dataConversion(tier.resourceLimits?.storage * 1024 * 1024) ?? '0 B'}`); embed.addField(`Tier ${tier.id}`, `**RAM:** ${dataConversion(tier.resourceLimits?.ram * 1024 * 1024) ?? '0 B'}\n**Storage:** ${dataConversion(tier.resourceLimits?.storage * 1024 * 1024) ?? '0 B'}`);
} }
return message.channel.createMessage({ embed }); return message.channel.send({ embeds: [embed] });
} catch (error) { } catch (error) {
return this.client.util.handleError(error, message, this); return this.client.util.handleError(error, message, this);
} }

View File

@ -1,11 +1,11 @@
import { Message } from 'eris'; import { Message, TextChannel } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class Limits_SetRAMNotification extends Command { export default class Limits_SetRAMNotification extends Command {
constructor(client: Client) { constructor(client: Client) {
super(client); super(client);
this.name = 'set-ram-notification'; this.name = 'set-ram-notification';
this.description = 'Sets your personal perference for receiving RAM resource limit notifications. Set the limit to "-1" to disable notifications.'; this.description = 'Sets your personal preference for receiving RAM resource limit notifications. Set the limit to "-1" to disable notifications.';
this.usage = `${this.client.config.prefix}limits set-ram-notification <limit in mb>`; this.usage = `${this.client.config.prefix}limits set-ram-notification <limit in mb>`;
this.enabled = true; this.enabled = true;
} }
@ -13,16 +13,16 @@ export default class Limits_SetRAMNotification extends Command {
public async run(message: Message, args: string[]) { public async run(message: Message, args: string[]) {
try { try {
const account = await this.client.db.Account.findOne({ userID: message.author.id }); const account = await this.client.db.Account.findOne({ userID: message.author.id });
if (!account) return this.error(message.channel, 'You do not appear to have an account.'); if (!account) return this.error(message.channel as TextChannel, 'You do not appear to have an account.');
const tier = await this.client.db.Tier.findOne({ id: account.tier }); const tier = await this.client.db.Tier.findOne({ id: account.tier });
if (Number(args[0]) >= tier.resourceLimits.ram) return this.error(message.channel, 'You cannot set your notification limit to be set to or above your hard limit.'); if (Number(args[0]) >= tier.resourceLimits.ram) return this.error(message.channel as TextChannel, 'You cannot set your notification limit to be set to or above your hard limit.');
if (Number(args[0]) < 0) return this.error(message.channel, 'You cannot set your notification limit to a negative number.'); if (Number(args[0]) < 0) return this.error(message.channel as TextChannel, 'You cannot set your notification limit to a negative number.');
if (Number(args[0]) === 0) { if (Number(args[0]) === 0) {
await account.updateOne({ $set: { ramLimitNotification: 0 } }); await account.updateOne({ $set: { ramLimitNotification: 0 } });
return this.success(message.channel, 'You have disabled notifications.'); return this.success(message.channel as TextChannel, 'You have disabled notifications.');
} }
await account.updateOne({ $set: { ramLimitNotification: Number(args[0]) } }); await account.updateOne({ $set: { ramLimitNotification: Number(args[0]) } });
return this.success(message.channel, `You will now receive notifications when you go above ${Number(args[0])} MB.`); return this.success(message.channel as TextChannel, `You will now receive notifications when you go above ${Number(args[0])} MB.`);
} catch (error) { } catch (error) {
return this.client.util.handleError(error, message, this); return this.client.util.handleError(error, message, this);
} }

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class Load extends Command { export default class Load extends Command {

View File

@ -1,5 +1,5 @@
import moment, { unitOfTime } from 'moment'; import moment, { unitOfTime } from 'moment';
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class Lock extends Command { export default class Lock extends Command {
@ -29,7 +29,7 @@ export default class Lock extends Command {
const momentMilliseconds = moment.duration(Number(length), unit as unitOfTime.Base).asMilliseconds(); const momentMilliseconds = moment.duration(Number(length), unit as unitOfTime.Base).asMilliseconds();
const reason = momentMilliseconds ? args.slice(2).join(' ') : args.slice(1).join(' '); const reason = momentMilliseconds ? args.slice(2).join(' ') : args.slice(1).join(' ');
await this.client.util.createModerationLog(account.userID, message.member, 2, reason, momentMilliseconds); await this.client.util.createModerationLog(account.userID, message.author, 2, reason, momentMilliseconds);
edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been locked by Technician ${message.author.username}#${message.author.discriminator}.***`); edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been locked by Technician ${message.author.username}#${message.author.discriminator}.***`);
message.delete(); message.delete();
@ -44,7 +44,7 @@ export default class Lock extends Command {
<p><b>Reason:</b> ${momentMilliseconds ? args.slice(2).join(' ') : args.slice(1).join(' ')}</p> <p><b>Reason:</b> ${momentMilliseconds ? args.slice(2).join(' ') : args.slice(1).join(' ')}</p>
<p><b>Technician:</b> ${message.author.username}</p> <p><b>Technician:</b> ${message.author.username}</p>
<p><b>Expiration:</b> ${momentMilliseconds ? moment(expiry).format('dddd, MMMM Do YYYY, h:mm:ss A') : 'N/A'}</p> <p><b>Expiration:</b> ${momentMilliseconds ? moment(expiry).format('dddd, MMMM Do YYYY, h:mm:ss A') : 'N/A'}</p>
<b><i>Library of Code sp-us | Support Team</i></b> <b><i>Library of Code sp-us | Support Team</i></b>
`, `,
}); });

View File

@ -1,6 +1,5 @@
import { Message } from 'eris'; import { Message, MessageEmbed } from 'discord.js';
import { createPaginationEmbed } from 'eris-pagination'; import { Client, Command } from '../class';
import { Client, Command, RichEmbed } from '../class';
export default class Modlogs extends Command { export default class Modlogs extends Command {
constructor(client: Client) { constructor(client: Client) {
@ -35,16 +34,16 @@ export default class Modlogs extends Command {
const inline = true; const inline = true;
return { name, value, inline }; return { name, value, inline };
})); }));
const users = [...new Set(query.map((log) => log.userID))].map((u) => `<@${u}>`); const users = [...new Set(query.map((log) => log.userID))].map((u) => u.toString());
const logs = this.client.util.splitFields(formatted); const logs = this.client.util.splitFields(formatted);
const embeds = logs.map((l) => { const embeds = logs.map((l) => {
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setDescription(`List of Cloud moderation logs for ${users.join(', ')}`); embed.setDescription(`List of Cloud moderation logs for ${users.join(', ')}`);
embed.setAuthor('Library of Code | Cloud Services', this.client.user.avatarURL, 'https://libraryofcode.org/'); embed.setAuthor('Library of Code | Cloud Services', this.client.user.avatarURL(), 'https://libraryofcode.org/');
embed.setTitle('Cloud Modlogs/Infractions'); embed.setTitle('Cloud Modlogs/Infractions');
embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL); embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL());
l.forEach((f) => embed.addField(f.name, f.value, f.inline)); l.forEach((f) => embed.addField(f.name, f.value, f.inline));
embed.setTimestamp(); embed.setTimestamp();
embed.setColor(3447003); embed.setColor(3447003);
@ -52,9 +51,9 @@ export default class Modlogs extends Command {
}); });
if (embeds.length === 1) { if (embeds.length === 1) {
msg.edit({ content: '', embed: embeds[0] }); msg.edit({ content: '', embeds: [embeds[0]] });
} else { } else {
createPaginationEmbed(message, embeds, {}); this.client.util.createPaginationEmbed(message, embeds);
} }
return msg; return msg;
} catch (error) { } catch (error) {

View File

@ -1,5 +1,5 @@
import { Message } from 'eris'; import { Message, MessageEmbed, TextChannel } from 'discord.js';
import { Client, Command, RichEmbed } from '../class'; import { Client, Command } from '../class';
export default class Notify extends Command { export default class Notify extends Command {
constructor(client: Client) { constructor(client: Client) {
@ -17,17 +17,18 @@ export default class Notify extends Command {
const edit = await this.loading(message.channel, 'Sending notification...'); const edit = await this.loading(message.channel, 'Sending notification...');
const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] }); const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] });
if (!account) return edit.edit(`***${this.client.stores.emojis.error} Cannot find user.***`); if (!account) return edit.edit(`***${this.client.stores.emojis.error} Cannot find user.***`);
const embed = new RichEmbed() const embed = new MessageEmbed()
.setTitle('Cloud Account | Notification') .setTitle('Cloud Account | Notification')
.setDescription(args.slice(1).join(' ')) .setDescription(args.slice(1).join(' '))
.addField('Technician', `<@${message.author.id}>`, true) .addField('Technician', message.author.toString(), true)
.setFooter(this.client.user.username, this.client.user.avatarURL) .setFooter(this.client.user.username, this.client.user.avatarURL())
.setTimestamp(); .setTimestamp();
this.client.getDMChannel(account.userID).then((channel) => { this.client.users.fetch(account.userID).then((u) => {
channel.createMessage({ embed }); u.send({ embeds: [embed] });
}); });
embed.addField('User', `${account.username} | <@${account.userID}>`, true); embed.addField('User', `${account.username} | <@${account.userID}>`, true);
this.client.createMessage('580950455581147146', { embed }); const ch = this.client.channels.cache.get('580950455581147146') as TextChannel;
ch.send({ embeds: [embed] });
this.client.util.transport.sendMail({ this.client.util.transport.sendMail({
to: account.emailAddress, to: account.emailAddress,
from: 'Library of Code sp-us | Cloud Services <help@libraryofcode.org>', from: 'Library of Code sp-us | Cloud Services <help@libraryofcode.org>',

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class Ping extends Command { export default class Ping extends Command {
@ -12,8 +12,8 @@ export default class Ping extends Command {
public async run(message: Message) { public async run(message: Message) {
try { try {
const clientStart: number = Date.now(); const clientStart: number = Date.now();
const msg: Message = await message.channel.createMessage('🏓 Pong!'); const msg: Message = await message.channel.send('🏓 Pong!');
msg.edit(`🏓 Pong!\nClient: \`${Date.now() - clientStart}ms\`\nResponse: \`${msg.createdAt - message.createdAt}ms\``); msg.edit(`🏓 Pong!\nClient: \`${Date.now() - clientStart}ms\`\nResponse: \`${msg.createdTimestamp - message.createdTimestamp}ms\``);
} catch (error) { } catch (error) {
this.client.util.handleError(error, message, this); this.client.util.handleError(error, message, this);
} }

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import axios from 'axios'; import axios from 'axios';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
@ -41,7 +41,6 @@ export default class Pull extends Command {
+ `***${this.client.stores.emojis.loading} Reinstalling dependencies...***`); + `***${this.client.stores.emojis.loading} Reinstalling dependencies...***`);
const passedPull = await updateMessage.edit(continueMessage); const passedPull = await updateMessage.edit(continueMessage);
let install: string; let install: string;
try { try {
install = await this.client.util.exec('yarn install', { cwd: '/opt/CloudServices' }); install = await this.client.util.exec('yarn install', { cwd: '/opt/CloudServices' });
@ -76,7 +75,7 @@ export default class Pull extends Command {
updatedMessage += `${this.client.stores.emojis.error} Could not upload error: ${e}`; updatedMessage += `${this.client.stores.emojis.error} Could not upload error: ${e}`;
} }
} else { } else {
split.forEach((m) => message.channel.createMessage(`\`\`\`bash\n${m}\n\`\`\``)); split.forEach((m) => message.channel.send(`\`\`\`bash\n${m}\n\`\`\``));
} }
} }
this.client.buildError = true; this.client.buildError = true;

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class ResetPassword extends Command { export default class ResetPassword extends Command {
@ -25,9 +25,9 @@ export default class ResetPassword extends Command {
await this.client.util.exec(`echo '${account.username}:${tempPass}@' | chpasswd && chage -d0 ${account.username}`); await this.client.util.exec(`echo '${account.username}:${tempPass}@' | chpasswd && chage -d0 ${account.username}`);
let completeMessage = `${this.client.stores.emojis.success} ***Password for ${account.username} reset to \`${tempPass}@\`***`; let completeMessage = `${this.client.stores.emojis.success} ***Password for ${account.username} reset to \`${tempPass}@\`***`;
const dmChannel = await this.client.getDMChannel(account.userID); const dmChannel = await this.client.users.fetch(account.userID);
try { try {
await dmChannel.createMessage(`We received a password reset request from you, your new password is \`${tempPass}@\`.\n` await dmChannel.send(`We received a password reset request from you, your new password is \`${tempPass}@\`.\n`
+ `You will be asked to change your password when you log back in, \`(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` + `You will be asked to change your password when you log back in, \`(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.'); + 'Bear in mind that when you enter your password, it will be blank, so be careful not to type in your password incorrectly.');
} catch (error) { } catch (error) {

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class Restart extends Command { export default class Restart extends Command {

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
import SetLimit_RAM from './setlimit_ram'; import SetLimit_RAM from './setlimit_ram';

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class SetLimit_RAM extends Command { export default class SetLimit_RAM extends Command {

View File

@ -1,7 +1,7 @@
import moment from 'moment'; import moment from 'moment';
import { Message } from 'eris'; import { Message, MessageEmbed } from 'discord.js';
import os, { totalmem } from 'os'; import os from 'os';
import { Client, Command, RichEmbed } from '../class'; import { Client, Command } from '../class';
import { dataConversion } from '../functions'; import { dataConversion } from '../functions';
export default class SysInfo extends Command { export default class SysInfo extends Command {
@ -14,21 +14,21 @@ export default class SysInfo extends Command {
public async run(message: Message) { public async run(message: Message) {
const availableMemory: string = await this.client.util.exec('free -b'); const availableMemory: string = await this.client.util.exec('free -b');
const usedMemory = dataConversion(totalmem() - Number(availableMemory.split('\n')[1].split(' ').slice(-1)[0])); const usedMemory = dataConversion(os.totalmem() - Number(availableMemory.split('\n')[1].split(' ').slice(-1)[0]));
const date = new Date(); const date = new Date();
date.setMilliseconds(-(moment.duration(os.uptime(), 's').asMilliseconds())); date.setMilliseconds(-(moment.duration(os.uptime(), 's').asMilliseconds()));
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('System Information & Statistics'); embed.setTitle('System Information & Statistics');
embed.addField('Hostname', os.hostname(), true); 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('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('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('Load Average (last 15 minutes)', os.loadavg()[2].toFixed(3), true);
embed.addField('Memory/RAM', `${usedMemory} / ${dataConversion(totalmem())}`, true); embed.addField('Memory/RAM', `${usedMemory} / ${dataConversion(os.totalmem())}`, true);
embed.addField('Network Interfaces (IPv4)', os.networkInterfaces().enp0s3.filter((r) => r.family === 'IPv4')[0].address, true); embed.addField('Network Interfaces (IPv4)', os.networkInterfaces().enp0s3.filter((r) => r.family === 'IPv4')[0].address, true);
// embed.addField('Network Interfaces (IPv6)', os.networkInterfaces().enp0s3.filter((r) => r.family === 'IPv6')[0].address.replace(/:/gi, '\:'), true); // eslint-disable-line // embed.addField('Network Interfaces (IPv6)', os.networkInterfaces().enp0s3.filter((r) => r.family === 'IPv6')[0].address.replace(/:/gi, '\:'), true); // eslint-disable-line
embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setFooter(this.client.user.username, this.client.user.avatarURL());
embed.setTimestamp(); embed.setTimestamp();
message.channel.createMessage({ embed }); message.channel.send({ embeds: [embed] });
} }
} }

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
import SystemD_Linger from './systemd_linger'; import SystemD_Linger from './systemd_linger';
import SystemD_Status from './systemd_status'; import SystemD_Status from './systemd_status';

View File

@ -1,5 +1,5 @@
/* eslint-disable consistent-return */ /* eslint-disable consistent-return */
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class SystemdD_Linger extends Command { export default class SystemdD_Linger extends Command {

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class SystemD_Restart extends Command { export default class SystemD_Restart extends Command {

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class SystemD_Start extends Command { export default class SystemD_Start extends Command {

View File

@ -1,5 +1,5 @@
import { Message } from 'eris'; import { Message, MessageEmbed } from 'discord.js';
import { Client, Command, RichEmbed } from '../class'; import { Client, Command } from '../class';
export default class SystemD_Status extends Command { export default class SystemD_Status extends Command {
constructor(client: Client) { constructor(client: Client) {
@ -22,12 +22,12 @@ export default class SystemD_Status extends Command {
if (err.toString().includes('could not be found')) return this.error(message.channel, 'The service name you provided doesn\'t exist.'); if (err.toString().includes('could not be found')) return this.error(message.channel, 'The service name you provided doesn\'t exist.');
return this.error(message.channel, err.toString()); return this.error(message.channel, err.toString());
} }
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle(`SystemD Status | ${args[0]}`); embed.setTitle(`SystemD Status | ${args[0]}`);
embed.setDescription(`\`\`\`sh\n${cmd}\n\`\`\``); embed.setDescription(`\`\`\`sh\n${cmd}\n\`\`\``);
embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setFooter(this.client.user.username, this.client.user.avatarURL());
embed.setTimestamp(); embed.setTimestamp();
return message.channel.createMessage({ embed }); return message.channel.send({ embeds: [embed] });
} catch (err) { } catch (err) {
return this.client.util.handleError(err, message, this); return this.client.util.handleError(err, message, this);
} }

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class SystemD_Stop extends Command { export default class SystemD_Stop extends Command {

View File

@ -1,5 +1,5 @@
import { Message } from 'eris'; import { Message, MessageEmbed, TextChannel } from 'discord.js';
import { Client, Command, RichEmbed } from '../class'; import { Client, Command } from '../class';
export default class Tier extends Command { export default class Tier extends Command {
constructor(client: Client) { constructor(client: Client) {
@ -28,16 +28,18 @@ export default class Tier extends Command {
await account.updateOne({ $set: { tier: Number(args[1]) } }); await account.updateOne({ $set: { tier: Number(args[1]) } });
} }
edit.edit(`***${this.client.stores.emojis.success} Tier for ${account.username} has been changed to ${args[1]}.***`); edit.edit(`***${this.client.stores.emojis.success} Tier for ${account.username} has been changed to ${args[1]}.***`);
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('Cloud Account | Tier Change'); embed.setTitle('Cloud Account | Tier Change');
embed.setColor('#0099ff'); embed.setColor('#0099ff');
embed.addField('User', `${account.username} | <@${account.userID}>`, true); embed.addField('User', `${account.username} | <@${account.userID}>`, true);
embed.addField('Technician', `<@${message.author.id}>`, true); embed.addField('Technician', message.author.toString(), true);
embed.addField('Old Tier -> New Tier', `${account.tier} -> ${args[1]}`, true); embed.addField('Old Tier -> New Tier', `${account.tier} -> ${args[1]}`, true);
embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setFooter(this.client.user.username, this.client.user.avatarURL());
embed.setTimestamp(); embed.setTimestamp();
await this.client.util.sendMessageToUserTerminal(account.username, `A technician has changed your tier to ${args[1]}`).catch(() => { }); await this.client.util.sendMessageToUserTerminal(account.username, `A technician has changed your tier to ${args[1]}`).catch(() => { });
this.client.createMessage('580950455581147146', { embed }); return this.client.getDMChannel(account.userID).then((channel) => channel.createMessage({ embed })).catch(); const ch = this.client.channels.cache.get('580950455581147146') as TextChannel;
ch.send({ embeds: [embed] });
return this.client.users.fetch(account.userID).then((u) => u.send({ embeds: [embed] })).catch();
} catch (error) { } catch (error) {
return this.client.util.handleError(error, message, this); return this.client.util.handleError(error, message, this);
} }

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class Unban extends Command { export default class Unban extends Command {
@ -16,7 +16,7 @@ export default class Unban extends Command {
public async run(message: Message, args: string[]) { public async run(message: Message, args: string[]) {
try { try {
if (!args[1]) return this.client.commands.get('help').run(message, [this.name]); if (!args[1]) return this.client.commands.get('help').run(message, [this.name]);
const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Unbanning IP...***`); const msg = await message.channel.send(`${this.client.stores.emojis.loading} ***Unbanning IP...***`);
try { try {
await this.client.util.exec(`sudo fail2ban-client set ${args[0]} unbanip ${args[1]}`); await this.client.util.exec(`sudo fail2ban-client set ${args[0]} unbanip ${args[1]}`);
} catch (error) { } catch (error) {

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class Unlock extends Command { export default class Unlock extends Command {
@ -21,7 +21,7 @@ export default class Unlock extends Command {
await this.client.util.exec(`unlock ${account.username}`); await this.client.util.exec(`unlock ${account.username}`);
await account.updateOne({ locked: false }); await account.updateOne({ locked: false });
await this.client.util.createModerationLog(account.userID, message.member, 3, args.slice(1).join(' ')); await this.client.util.createModerationLog(account.userID, message.author, 3, args.slice(1).join(' '));
message.delete(); message.delete();
edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been unlocked by Technician ${message.author.username}#${message.author.discriminator}.***`); edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been unlocked by Technician ${message.author.username}#${message.author.discriminator}.***`);
} catch (error) { } catch (error) {

View File

@ -1,7 +1,6 @@
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
import { Message } from 'eris'; import { Message, MessageEmbed } from 'discord.js';
import { createPaginationEmbed } from 'eris-pagination'; import { Client, Command } from '../class';
import { Client, Command, RichEmbed } from '../class';
export default class Users extends Command { export default class Users extends Command {
constructor(client: Client) { constructor(client: Client) {
@ -47,10 +46,10 @@ export default class Users extends Command {
const data = this.client.util.splitFields(embedFields); const data = this.client.util.splitFields(embedFields);
const embeds = data.map((l) => { const embeds = data.map((l) => {
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setAuthor('Library of Code | Cloud Services', this.client.user.avatarURL, 'https://libraryofcode.org/'); embed.setAuthor('Library of Code | Cloud Services', this.client.user.avatarURL(), 'https://libraryofcode.org/');
embed.setTitle('Cloud Accounts'); embed.setTitle('Cloud Accounts');
embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL); embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL());
l.forEach((f) => embed.addField(f.name, f.value, true)); l.forEach((f) => embed.addField(f.name, f.value, true));
embed.setTimestamp(); embed.setTimestamp();
embed.setColor(3447003); embed.setColor(3447003);
@ -58,10 +57,10 @@ export default class Users extends Command {
}); });
if (embeds.length === 1) { if (embeds.length === 1) {
msg.edit({ content: '', embed: embeds[0] }); msg.edit({ content: '', embeds: [embeds[0]] });
} else { } else {
msg.delete(); msg.delete();
createPaginationEmbed(message, embeds, {}); this.client.util.createPaginationEmbed(message, embeds);
} }
return msg; return msg;
} catch (error) { } catch (error) {

View File

@ -1,4 +1,4 @@
import { Message } from 'eris'; import { Message } from 'discord.js';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class Warn extends Command { export default class Warn extends Command {
@ -18,7 +18,7 @@ export default class Warn extends Command {
const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] }); const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] });
if (!account) return edit.edit(`***${this.client.stores.emojis.error} Cannot find user.***`); if (!account) return edit.edit(`***${this.client.stores.emojis.error} Cannot find user.***`);
if (account.root) return edit.edit(`***${this.client.stores.emojis.error} Permission denied.***`); if (account.root) return edit.edit(`***${this.client.stores.emojis.error} Permission denied.***`);
await this.client.util.createModerationLog(account.userID, message.member, 1, args.slice(1).join(' ')); await this.client.util.createModerationLog(account.userID, message.author, 1, args.slice(1).join(' '));
message.delete(); message.delete();
edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been warned by Technician ${message.author.username}#${message.author.discriminator}.***`); edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been warned by Technician ${message.author.username}#${message.author.discriminator}.***`);
await this.client.util.sendMessageToUserTerminal(account.username, `WARNING FROM TECHNICIAN: ${args.slice(1).join(' ')}`).catch(() => { }); await this.client.util.sendMessageToUserTerminal(account.username, `WARNING FROM TECHNICIAN: ${args.slice(1).join(' ')}`).catch(() => { });

View File

@ -1,6 +1,6 @@
import moment from 'moment'; import moment from 'moment';
import { Message, GuildTextableChannel, Member, Role } from 'eris'; import { Message, TextChannel, Role, MessageEmbed, GuildMember } from 'discord.js';
import { Client, Command, Report, RichEmbed } from '../class'; import { Client, Command } from '../class';
import { dataConversion } from '../functions'; import { dataConversion } from '../functions';
import { AccountInterface } from '../models'; import { AccountInterface } from '../models';
@ -16,22 +16,26 @@ export default class Whois extends Command {
public fullRoles = ['662163685439045632', '701454780828221450']; public fullRoles = ['662163685439045632', '701454780828221450'];
public IP_REGEX = /((^\s*((([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]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))/g public IP_REGEX = /((^\s*((([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]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))/g;
public async run(message: Message<GuildTextableChannel>, args: string[]) { public IP_V4_REGEX = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/
public IP_V6_REGEX = /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/
public async run(message: Message, args: string[]) {
try { try {
let full = false; let full = false;
let account: AccountInterface; let account: AccountInterface;
if (args[1] === '--full' && this.fullRoles.some((r) => message.member.roles.includes(r) || message.author.id === '554168666938277889')) full = true; if (args[1] === '--full' && this.fullRoles.some((r) => message.member.roles.cache.has(r) || message.author.id === '554168666938277889')) full = true;
const user = args[0] || message.author.id; const user = args[0] || message.author.id;
if (full) account = await this.client.db.Account.findOne({ $or: [{ username: user }, { userID: user }, { emailAddress: user }, { supportKey: user.toUpperCase() }, { referralCode: args[0] }] }); if (full) account = await this.client.db.Account.findOne({ $or: [{ username: user }, { userID: user }, { emailAddress: user }, { supportKey: user.toUpperCase() }, { referralCode: args[0] }] });
else account = await this.client.db.Account.findOne({ $or: [{ username: user }, { userID: user }] }); else account = await this.client.db.Account.findOne({ $or: [{ username: user }, { userID: user }] });
if (!account) return this.error(message.channel, 'Account not found.'); if (!account) return this.error(message.channel as TextChannel, 'Account not found.');
const thumbnail = this.client.users.get(account.userID)?.avatarURL || message.channel.guild.iconURL; const thumbnail = (await this.client.users.fetch(account.userID))?.avatarURL() || message.guild.iconURL();
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('Account Information'); embed.setTitle('Account Information');
embed.setThumbnail(thumbnail); embed.setThumbnail(thumbnail);
if (full) await this.full(account, embed, message.member); if (full) await this.full(account, embed, message.member);
@ -43,18 +47,18 @@ export default class Whois extends Command {
switch (true) { switch (true) {
case account.permissions.director: case account.permissions.director:
details += 'This account belongs to a Director.\n'; details += 'This account belongs to a Director.\n';
role = message.member.guild.roles.get('662163685439045632'); role = await message.member.guild.roles.fetch('662163685439045632');
break; break;
case account.permissions.technician: case account.permissions.technician:
details += 'This account belongs to a Technician.\n'; details += 'This account belongs to a Technician.\n';
role = message.member.guild.roles.get('701454780828221450'); role = await message.member.guild.roles.fetch('701454780828221450');
break; break;
case account.permissions.staff: case account.permissions.staff:
details += 'This account belongs to a Staff member.\n'; details += 'This account belongs to a Staff member.\n';
role = message.member.guild.roles.get('453689940140883988'); role = await message.member.guild.roles.fetch('453689940140883988');
break; break;
default: default:
role = message.member.guild.roles.get(message.member.guild.id); role = await message.member.guild.roles.fetch(message.member.guild.id);
break; break;
} }
if (account.root) details += '**This account has root/administrative privileges.**\n'; if (account.root) details += '**This account has root/administrative privileges.**\n';
@ -62,13 +66,13 @@ export default class Whois extends Command {
if (details) embed.addField('Additional Details', details, true); if (details) embed.addField('Additional Details', details, true);
embed.setTimestamp(); embed.setTimestamp();
return message.channel.createMessage({ embed }); return message.channel.send({ embeds: [embed] });
} catch (error) { } catch (error) {
return this.client.util.handleError(error, message, this); return this.client.util.handleError(error, message, this);
} }
} }
public async full(account: AccountInterface, embed: RichEmbed, member: Member) { public async full(account: AccountInterface, embed: MessageEmbed, member: GuildMember) {
const [cpuUsage, data, fingerInformation, chage, memory] = await Promise.all([ const [cpuUsage, data, fingerInformation, chage, memory] = await Promise.all([
this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`), this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`),
this.client.redis.get(`storage-${account.username}`), this.client.redis.get(`storage-${account.username}`),
@ -76,7 +80,7 @@ export default class Whois extends Command {
this.client.util.exec(`chage -l ${account.username}`), this.client.util.exec(`chage -l ${account.username}`),
this.client.util.exec(`memory ${account.username}`), this.client.util.exec(`memory ${account.username}`),
]); ]);
const finger = !member.roles.includes('662163685439045632') ? fingerInformation.replace(this.IP_REGEX, '[MASKED IP ADDRRESS]') : fingerInformation; const finger = !member.roles.cache.has('662163685439045632') ? fingerInformation.replace(this.IP_REGEX, '[MASKED IP ADDRESS]') : fingerInformation;
embed.setDescription(`${finger}\n${chage}`); embed.setDescription(`${finger}\n${chage}`);
embed.addField('Username', `${account.username} | <@${account.userID}>`, true); embed.addField('Username', `${account.username} | <@${account.userID}>`, true);
@ -85,14 +89,16 @@ export default class Whois extends Command {
embed.addField('Tier', String(account.tier), true); embed.addField('Tier', String(account.tier), true);
embed.addField('Support Key', account.supportKey, true); embed.addField('Support Key', account.supportKey, true);
embed.addField('Referral Code & Total', `${account.referralCode} | ${account.totalReferrals}`, true); embed.addField('Referral Code & Total', `${account.referralCode} | ${account.totalReferrals}`, true);
embed.addField('Created By', this.client.users.get(account.createdBy) ? `<@${this.client.users.get(account.createdBy).id}>` : 'SYSTEM', true); embed.addField('Created By', await this.client.users.fetch(account.createdBy)
? (await this.client.users.fetch(account.createdBy)).toString()
: 'SYSTEM', true);
embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true);
embed.addField('CPU Usage', `${cpuUsage.split('\n')[0] || '0'}%`, true); embed.addField('CPU Usage', `${cpuUsage.split('\n')[0] || '0'}%`, true);
embed.addField('Memory', dataConversion(Number(memory) * 1000), true); embed.addField('Memory', dataConversion(Number(memory) * 1000), true);
embed.addField('Storage', data ? dataConversion(Number(data)) : 'N/A', true); embed.addField('Storage', data ? dataConversion(Number(data)) : 'N/A', true);
} }
public async default(account: AccountInterface, embed: RichEmbed) { public async default(account: AccountInterface, embed: MessageEmbed) {
const [cpuUsage, data, memory] = await Promise.all([ const [cpuUsage, data, memory] = await Promise.all([
this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`), this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`),
this.client.redis.get(`storage-${account.username}`), this.client.redis.get(`storage-${account.username}`),
@ -102,7 +108,9 @@ export default class Whois extends Command {
embed.addField('Username', `${account.username} | <@${account.userID}>`, true); embed.addField('Username', `${account.username} | <@${account.userID}>`, true);
embed.addField('ID', account.userID, true); embed.addField('ID', account.userID, true);
embed.addField('Tier', String(account.tier), true); embed.addField('Tier', String(account.tier), true);
embed.addField('Created By', this.client.users.get(account.createdBy) ? `<@${this.client.users.get(account.createdBy).id}>` : 'SYSTEM', true); embed.addField('Created By', await this.client.users.fetch(account.createdBy)
? (await this.client.users.fetch(account.createdBy)).toString()
: 'SYSTEM', true);
embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true);
embed.addField('CPU Usage', `${cpuUsage.split('\n')[0] || '0'}%`, true); embed.addField('CPU Usage', `${cpuUsage.split('\n')[0] || '0'}%`, true);
embed.addField('Memory', dataConversion(Number(memory) * 1000), true); embed.addField('Memory', dataConversion(Number(memory) * 1000), true);

View File

@ -1,5 +1,5 @@
import { Message, TextChannel } from 'eris'; import { Message, TextChannel, MessageEmbed } from 'discord.js';
import { Client, Event, RichEmbed } from '../class'; import { Client, Event } from '../class';
export default class extends Event { export default class extends Event {
public client: Client public client: Client
@ -10,9 +10,6 @@ export default class extends Event {
this.event = 'messageCreate'; this.event = 'messageCreate';
} }
public info(message: Message) {
}
public async run(message: Message) { public async run(message: Message) {
try { try {
if (message.author.bot && message.author.id !== '554168666938277889') return; if (message.author.bot && message.author.id !== '554168666938277889') return;
@ -28,8 +25,9 @@ export default class extends Event {
let hasRolePerms: boolean = false; let hasRolePerms: boolean = false;
if (resolved.cmd.permissions.roles) { if (resolved.cmd.permissions.roles) {
for (const role of resolved.cmd.permissions.roles) { for (const role of resolved.cmd.permissions.roles) {
if (message.member && message.member.roles.includes(role)) { if (message.member && message.member.roles.cache.has(role)) {
hasRolePerms = true; break; hasRolePerms = true;
break;
} }
} }
} }
@ -37,9 +35,15 @@ export default class extends Event {
hasUserPerms = true; hasUserPerms = true;
hasRolePerms = true; hasRolePerms = true;
} }
if (message.author.id === '554168666938277889') { hasUserPerms = true; hasRolePerms = true; } if (message.author.id === '554168666938277889') {
hasUserPerms = true;
hasRolePerms = true;
}
if (!hasRolePerms && !hasUserPerms) return; if (!hasRolePerms && !hasUserPerms) return;
if (!resolved.cmd.enabled) { message.channel.createMessage(`***${this.client.stores.emojis.error} This command has been disabled***`); return; } if (!resolved.cmd.enabled) {
message.channel.send(`***${this.client.stores.emojis.error} This command has been disabled***`);
return;
}
await resolved.cmd.run(message, resolved.args); await resolved.cmd.run(message, resolved.args);
} catch (error) { } catch (error) {
this.client.util.handleError(error, message); this.client.util.handleError(error, message);

View File

@ -74,7 +74,7 @@ func handler(config ConfigStruct) {
collection := mongoClient.Database("cloudservices").Collection("accounts") collection := mongoClient.Database("cloudservices").Collection("accounts")
cur, err := collection.Find(context.TODO(), bson.D{}) cur, err := collection.Find(context.TODO(), bson.D{})
HandleError(err, 0) HandleError(err, 0)
for cur.Next(context.TODO()) { for cur.Next(context.TODO()) {
checkAccountSizeAndUpdate(cur.Current.Lookup("username").String(), cur.Current.Lookup("id").String()) checkAccountSizeAndUpdate(cur.Current.Lookup("username").String(), cur.Current.Lookup("id").String())
fmt.Printf("Checking account information for %s\n", cur.Current.Lookup("username").String()) fmt.Printf("Checking account information for %s\n", cur.Current.Lookup("username").String())

View File

@ -1,60 +1,62 @@
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
import { Client, RichEmbed } from '../class'; import { MessageEmbed, TextChannel } from 'discord.js';
import { Client } from '../class';
export default function checkStaffStatus(client: Client) { export default function checkStaffStatus(client: Client) {
setInterval(async () => { setInterval(async () => {
const accounts = await client.db.Account.find(); const accounts = await client.db.Account.find();
for (const acc of accounts) { for (const acc of accounts) {
const tier3 = await client.db.Tier.findOne({ id: 3 }); const tier3 = await client.db.Tier.findOne({ id: 3 });
let user = client.guilds.cache.get('446067825673633794').members.cache.get(acc.userID);
let user = client.guilds.get('446067825673633794').members.get(acc.userID);
try { try {
if (!user) user = await client.guilds.get('446067825673633794').getRESTMember(acc.userID); if (!user) user = await client.guilds.cache.get('446067825673633794').members.fetch(acc.userID);
} catch (error) { } catch (error) {
continue; // eslint-disable-line no-continue continue; // eslint-disable-line no-continue
} }
if (!acc.permissions.director && user.roles.includes('662163685439045632')) {
if (!acc.permissions.director && user.roles.cache.has('662163685439045632')) {
await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.director': true } }); await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.director': true } });
if (acc.ramLimitNotification !== -1) { if (acc.ramLimitNotification !== -1) {
await client.db.Account.updateOne({ username: acc.username }, { $set: { ramLimitNotification: tier3.resourceLimits.ram - 20 } }); await client.db.Account.updateOne({ username: acc.username }, { $set: { ramLimitNotification: tier3.resourceLimits.ram - 20 } });
} }
} }
if (!acc.permissions.technician && user.roles.includes('701454780828221450')) { if (!acc.permissions.technician && user.roles.cache.has('701454780828221450')) {
await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.technician': true } }); await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.technician': true } });
if (acc.ramLimitNotification !== -1) { if (acc.ramLimitNotification !== -1) {
await client.db.Account.updateOne({ username: acc.username }, { $set: { ramLimitNotification: tier3.resourceLimits.ram - 20 } }); await client.db.Account.updateOne({ username: acc.username }, { $set: { ramLimitNotification: tier3.resourceLimits.ram - 20 } });
} }
} }
if (!acc.permissions.staff && user.roles.includes('446104438969466890')) { if (!acc.permissions.staff && user.roles.cache.has('446104438969466890')) {
await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.staff': true } }); await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.staff': true } });
if (acc.ramLimitNotification !== -1) { if (acc.ramLimitNotification !== -1) {
await client.db.Account.updateOne({ username: acc.username }, { $set: { ramLimitNotification: tier3.resourceLimits.ram - 20 } }); await client.db.Account.updateOne({ username: acc.username }, { $set: { ramLimitNotification: tier3.resourceLimits.ram - 20 } });
} }
} }
if (acc.permissions.director && !user.roles.includes('662163685439045632')) { if (acc.permissions.director && !user.roles.cache.has('662163685439045632')) {
await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.director': false } }); await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.director': false } });
} }
if (acc.permissions.technician && !user.roles.includes('701454780828221450')) { if (acc.permissions.technician && !user.roles.cache.has('701454780828221450')) {
await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.technician': false } }); await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.technician': false } });
} }
if (acc.permissions.staff && !user.roles.includes('446104438969466890')) { if (acc.permissions.staff && !user.roles.cache.has('446104438969466890')) {
await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.staff': false } }); await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.staff': false } });
} }
if (acc.permissions.staff && acc.tier < 3) { if (acc.permissions.staff && acc.tier < 3) {
await client.db.Account.updateOne({ username: acc.username }, { $set: { tier: 3 } }); await client.db.Account.updateOne({ username: acc.username }, { $set: { tier: 3 } });
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('Cloud Account | Tier Change'); embed.setTitle('Cloud Account | Tier Change');
embed.setColor('#0099ff'); embed.setColor('#0099ff');
embed.addField('User', `${acc.username} | <@${acc.userID}>`, true); embed.addField('User', `${acc.username} | <@${acc.userID}>`, true);
embed.addField('Moderator', `<@${client.user.id}>`, true); embed.addField('Moderator', client.user.toString(), true);
embed.addField('Old Tier -> New Tier', `${acc.tier} -> 3`, true); embed.addField('Old Tier -> New Tier', `${acc.tier} -> 3`, true);
embed.setFooter(client.user.username, client.user.avatarURL); embed.setFooter(client.user.username, client.user.avatarURL());
embed.setTimestamp(); embed.setTimestamp();
client.createMessage('580950455581147146', { embed }); const ch = await client.channels.fetch('580950455581147146') as TextChannel;
client.getDMChannel(acc.userID).then((chan) => { ch.send({ embeds: [embed] });
chan.createMessage('***Your account has automatically been upgraded to Tier 3 since you are a Staff member.***'); client.users.fetch(acc.userID).then((chan) => {
chan.send('***Your account has automatically been upgraded to Tier 3 since you are a Staff member.***');
}); });
} }
} }

View File

@ -1,7 +1,8 @@
/* eslint-disable no-useless-escape */ /* eslint-disable no-useless-escape */
/* eslint-disable no-continue */ /* eslint-disable no-continue */
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
import { Client, RichEmbed } from '../class'; import { MessageEmbed, TextChannel } from 'discord.js';
import { Client } from '../class';
import { Tiers } from '../models'; import { Tiers } from '../models';
const channelID = '691824484230889546'; const channelID = '691824484230889546';
@ -32,15 +33,16 @@ export default function memory(client: Client) {
client.signale.info(`RAM Hard Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.hard} MB`); client.signale.info(`RAM Hard Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.hard} MB`);
await client.util.sendMessageToUserTerminal(acc.username, 'REACHED RAM LIMIT; SENDING KILL SIGNAL'); await client.util.sendMessageToUserTerminal(acc.username, 'REACHED RAM LIMIT; SENDING KILL SIGNAL');
client.util.exec(`killall -9 -u ${acc.username}`); client.util.exec(`killall -9 -u ${acc.username}`);
const embed = new RichEmbed(); const embed = new MessageEmbed();
embed.setTitle('Resource Enforcement Notification'); embed.setTitle('Resource Enforcement Notification');
embed.setDescription('Someone has reached the (hard) resource limit for their tier on RAM. The system has automatically killed all of their processes.'); embed.setDescription('Someone has reached the (hard) resource limit for their tier on RAM. The system has automatically killed all of their processes.');
embed.addField('User', `${acc.username} | <@${acc.userID}> | ${acc.userID}`, true); embed.addField('User', `${acc.username} | <@${acc.userID}> | ${acc.userID}`, true);
embed.addField('Tier', String(acc.tier), true); embed.addField('Tier', String(acc.tier), true);
embed.addField('Memory Usage', `${String(memoryConversion)} MB`, true); embed.addField('Memory Usage', `${String(memoryConversion)} MB`, true);
embed.addField('Memory Limit', `${String(userLimits.hard)} MB`, true); embed.addField('Memory Limit', `${String(userLimits.hard)} MB`, true);
client.createMessage(channelID, { embed }); const ch = client.channels.cache.get(channelID) as TextChannel;
client.util.createModerationLog(acc.userID, client.guilds.get('446067825673633794').members.get(client.user.id), 1, `You have exceeded your resource limit of '${String(userLimits.hard)} MB'. Any process running on your user account has been sent a STOP/KILL signal. If you have any questions, please contact a Technician.`); ch.send({ embeds: [embed] });
client.util.createModerationLog(acc.userID, (await (await client.guilds.fetch('446067825673633794')).members.fetch(client.user.id)).user, 1, `You have exceeded your resource limit of '${String(userLimits.hard)} MB'. Any process running on your user account has been sent a STOP/KILL signal. If you have any questions, please contact a Technician.`);
client.util.transport.sendMail({ client.util.transport.sendMail({
to: acc.emailAddress, to: acc.emailAddress,
from: 'Library of Code sp-us | Cloud Services <help@libraryofcode.org>', from: 'Library of Code sp-us | Cloud Services <help@libraryofcode.org>',
@ -50,38 +52,40 @@ export default function memory(client: Client) {
<p>Your account has received an official warning from a Technician. Please get the underlying issue resolved to avoid <i>possible</i> moderative action.</p> <p>Your account has received an official warning from a Technician. Please get the underlying issue resolved to avoid <i>possible</i> moderative action.</p>
<p><strong>Reason:</strong> You have exceeded your resource limit of '${String(userLimits.hard)} MB'. Any process running on your user account has been sent a STOP/KILL signal. If you have any questions, please contact a Technician.</p> <p><strong>Reason:</strong> You have exceeded your resource limit of '${String(userLimits.hard)} MB'. Any process running on your user account has been sent a STOP/KILL signal. If you have any questions, please contact a Technician.</p>
<p><strong>Moderator:</strong> SYSTEM</p> <p><strong>Moderator:</strong> SYSTEM</p>
<b><i>Library of Code sp-us | Support Team</i></b> <b><i>Library of Code sp-us | Support Team</i></b>
`, `,
}); });
client.createMessage(channelID, { embed }); ch.send({ embeds: [embed] });
set.delete(acc.username); set.delete(acc.username);
} else if ((memoryConversion >= userLimits.soft) && !set.has(acc.username)) { } else if ((memoryConversion >= userLimits.soft) && !set.has(acc.username)) {
client.signale.info(`RAM Soft Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.soft} MB`); client.signale.info(`RAM Soft Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.soft} MB`);
const embed = new RichEmbed(); const embed = new MessageEmbed();
if (client.users.get(acc.userID)) embed.setThumbnail(client.users.get(acc.userID).avatarURL); const user = await client.users.fetch(acc.userID);
if (user) embed.setThumbnail(user.avatarURL());
embed.setTitle('Resource Limit Notification'); embed.setTitle('Resource Limit Notification');
embed.setDescription('Someone has reached the (soft) resource limit for their tier on RAM.'); embed.setDescription('Someone has reached the (soft) resource limit for their tier on RAM.');
embed.addField('User', `${acc.username} | <@${acc.userID}> | ${acc.userID}`, true); embed.addField('User', `${acc.username} | <@${acc.userID}> | ${acc.userID}`, true);
embed.addField('Tier', String(acc.tier), true); embed.addField('Tier', String(acc.tier), true);
embed.addField('Memory Usage', `${String(memoryConversion)} MB`, true); embed.addField('Memory Usage', `${String(memoryConversion)} MB`, true);
embed.addField('Memory Limit', `${String(userLimits.hard)} MB`, true); embed.addField('Memory Limit', `${String(userLimits.hard)} MB`, true);
embed.setFooter(client.user.username, client.user.avatarURL); embed.setFooter(client.user.username, client.user.avatarURL());
embed.setTimestamp(); embed.setTimestamp();
if (acc.ramLimitNotification !== 0) { if (acc.ramLimitNotification !== 0) {
await client.createMessage(channelID, { embed }); const ch = client.channels.cache.get(channelID) as TextChannel;
await ch.send({ embeds: [embed] });
} }
if ((memoryConversion >= acc.ramLimitNotification) && (acc.ramLimitNotification !== 0)) { if ((memoryConversion >= acc.ramLimitNotification) && (acc.ramLimitNotification !== 0)) {
const notifyEmbed = new RichEmbed() const notifyEmbed = new MessageEmbed()
.setTitle('Cloud Account | Notification') .setTitle('Cloud Account | Notification')
.setDescription(`You are about to reach your RAM resource limits, you are currently using '${String(Math.round(memoryConversion))} MB' and your limit is '${String(userLimits.hard)} MB'. Please correct your usage to avoid further action.`) .setDescription(`You are about to reach your RAM resource limits, you are currently using '${String(Math.round(memoryConversion))} MB' and your limit is '${String(userLimits.hard)} MB'. Please correct your usage to avoid further action.`)
.addField('User', `${acc.username} | <@${acc.userID}>`, true) .addField('User', `${acc.username} | <@${acc.userID}>`, true)
.addField('Technician', 'SYSTEM', true) .addField('Technician', 'SYSTEM', true)
.addField('Additional Information', 'This notification was sent by the system. You can set your notification preferences by running \`=limits set-ram-notification <preferred ram threshold in MB>\`, you can disable these notifications by running \`=limits set-ram-notification -1\`.') .addField('Additional Information', 'This notification was sent by the system. You can set your notification preferences by running \`=limits set-ram-notification <preferred ram threshold in MB>\`, you can disable these notifications by running \`=limits set-ram-notification -1\`.')
.setFooter(client.user.username, client.user.avatarURL) .setFooter(client.user.username, client.user.avatarURL())
.setTimestamp(); .setTimestamp();
client.getDMChannel(acc.userID).then((channel) => { client.users.fetch(acc.userID).then((u) => {
channel.createMessage({ embed: notifyEmbed }); u.send({ embeds: [notifyEmbed] });
}); });
await client.util.sendMessageToUserTerminal(acc.username, `You are about to reach your RAM resource limits, you are currently using '${String(Math.round(memoryConversion))} MB' and your limit is '${String(userLimits.hard)} MB'. Please correct your usage to avoid further action.`).catch(() => { }); await client.util.sendMessageToUserTerminal(acc.username, `You are about to reach your RAM resource limits, you are currently using '${String(Math.round(memoryConversion))} MB' and your limit is '${String(userLimits.hard)} MB'. Please correct your usage to avoid further action.`).catch(() => { });
client.util.transport.sendMail({ client.util.transport.sendMail({
@ -92,11 +96,12 @@ export default function memory(client: Client) {
<h1>Library of Code sp-us | Cloud Services</h1> <h1>Library of Code sp-us | Cloud Services</h1>
<p>You are about to reach your RAM resource limits, you are currently using '${String(memoryConversion)} MB' and your limit is '${String(userLimits.hard)} MB'. Please correct your usage to avoid further action.</p> <p>You are about to reach your RAM resource limits, you are currently using '${String(memoryConversion)} MB' and your limit is '${String(userLimits.hard)} MB'. Please correct your usage to avoid further action.</p>
<p><strong>Technician:</strong> SYSTEM</p> <p><strong>Technician:</strong> SYSTEM</p>
<b><i>Library of Code sp-us | Support Team</i></b> <b><i>Library of Code sp-us | Support Team</i></b>
`, `,
}); });
client.createMessage('580950455581147146', { embed: notifyEmbed }); const channel = client.channels.cache.get('580950455581147146') as TextChannel;
channel.send({ embeds: [notifyEmbed] });
} }
set.add(acc.username); set.add(acc.username);
} }

View File

@ -1,4 +1,5 @@
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
/* eslint-disable no-unreachable */
// import fs from 'fs-extra'; // import fs from 'fs-extra';
import { spawn } from 'child_process'; import { spawn } from 'child_process';
import { Client } from '../class'; import { Client } from '../class';

View File

@ -1,65 +1,61 @@
{ {
"compilerOptions": { "compilerOptions": {
/* Basic Options */ // "incremental": true, /* Enable incremental compilation */
// "incremental": true, /* Enable incremental compilation */ "target": "ES2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"target": "ES2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ "lib": [
"lib": ["ES2019.Object", "ES2020.Promise"], /* Specify library files to be included in the compilation. */ "ES2019.Object",
// "allowJs": true, /* Allow javascript files to be compiled. */ "ES2020.Promise"
// "checkJs": true, /* Report errors in .js files. */ ], /* Specify library files to be included in the compilation. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ // "allowJs": true, /* Allow javascript files to be compiled. */
"declaration": false, /* Generates corresponding '.d.ts' file. */ // "checkJs": true, /* Report errors in .js files. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "sourceMap": true, /* Generates corresponding '.map' file. */ "declaration": false, /* Generates corresponding '.d.ts' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"outDir": "./dist", /* Redirect output structure to the directory. */ // "sourceMap": true, /* Generates corresponding '.map' file. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ // "outFile": "./", /* Concatenate and emit output to single file. */
// "composite": true, /* Enable project compilation */ "outDir": "./dist", /* Redirect output structure to the directory. */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
"removeComments": true, /* Do not emit comments to output. */ // "composite": true, /* Enable project compilation */
// "noEmit": true, /* Do not emit outputs. */ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */ "removeComments": true, /* Do not emit comments to output. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ // "noEmit": true, /* Do not emit outputs. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ // "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
/* Strict Type-Checking Options */ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
"strict": false, /* Enable all strict type-checking options. */ /* Strict Type-Checking Options */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ "strict": true, /* Enable all strict type-checking options. */
// "strictNullChecks": true, /* Enable strict null checks. */ "skipLibCheck": true,
// "strictFunctionTypes": true, /* Enable strict checking of function types. */ "noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ "strictNullChecks": false, /* Enable strict null checks. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ "strictPropertyInitialization": false, /* Enable strict checking of property initialization in classes. */
"noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
/* Additional Checks */ "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
// "noUnusedLocals": true, /* Report errors on unused locals. */ /* Additional Checks */
// "noUnusedParameters": true, /* Report errors on unused parameters. */ // "noUnusedLocals": true, /* Report errors on unused locals. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */ /* Module Resolution Options */
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
"resolveJsonModule": true, "resolveJsonModule": true,
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
"typeRoots": ["./types"], /* List of folders to include type definitions from. */ // "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */ // "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"skipLibCheck": true, /* Skips type-checking the installed libraries in node_modules. */ "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
/* Source Map Options */ // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ /* Experimental Options */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
} }
} }

8
types/eris.d.ts vendored
View File

@ -1,8 +0,0 @@
import { EmbedOptions } from 'eris';
import RichEmbed from '../src/class/RichEmbed';
declare global {
namespace Eris {
type MessageContent = string | { content?: string; tts?: boolean; disableEveryone?: boolean; embed?: EmbedOptions | RichEmbed; flags?: number };
}
}

2717
yarn.lock

File diff suppressed because it is too large Load Diff