From f86659251317c6963076f4e3c41c380a83322ba3 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Fri, 27 Dec 2019 21:19:32 -0500 Subject: [PATCH 001/516] add lock on storage --- src/go/storage/storage.go | 50 ++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/go/storage/storage.go b/src/go/storage/storage.go index 264c40d..9771d68 100644 --- a/src/go/storage/storage.go +++ b/src/go/storage/storage.go @@ -9,8 +9,8 @@ import ( "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "io/ioutil" - "time" - "strings" + "strings" + "time" ) // Collection the MongoDB Account collection @@ -39,6 +39,7 @@ func HandleError(e error, serv int) { } func main() { + var status bool type Config struct { MongoDB string `json:"mongoURL"` } @@ -52,11 +53,11 @@ func main() { ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) err = client.Connect(ctx) HandleError(err, 1) - err = client.Ping(context.TODO(), nil) - fmt.Printf("Connected to MongoDB [GO]\n") + err = client.Ping(context.TODO(), nil) + fmt.Printf("Connected to MongoDB [GO]\n") HandleError(err, 1) - Collection = client.Database("cloudservices").Collection("accounts") + Collection = client.Database("cloudservices").Collection("accounts") RedisClient = redis.NewClient(&redis.Options{ Addr: "localhost:6379", @@ -64,36 +65,41 @@ func main() { DB: 0, }) - _, err = RedisClient.Ping().Result() - fmt.Printf("Connected to Redis [GO]\n") + _, err = RedisClient.Ping().Result() + fmt.Printf("Connected to Redis [GO]\n") HandleError(err, 1) + status = false for { fmt.Printf("Calling handler func [GO]\n") - handler() - time.Sleep(1000000 * time.Millisecond) - } + if status == false { + handler(&status) + time.Sleep(1000000 * time.Millisecond) + } + } } -func handler() { +func handler(status* bool) { + *status = true cur, err := Collection.Find(context.TODO(), bson.D{}) HandleError(err, 0) for cur.Next(context.TODO()) { - go checkAccountSizeAndUpdate(cur.Current.Lookup("username").String(), cur.Current.Lookup("id").String()) - fmt.Printf("Checking account information for %s\n", cur.Current.Lookup("username").String()) + go checkAccountSizeAndUpdate(cur.Current.Lookup("username").String(), cur.Current.Lookup("id").String()) + fmt.Printf("Checking account information for %s\n", cur.Current.Lookup("username").String()) time.Sleep(600000 * time.Millisecond) } + *status = false } func checkAccountSizeAndUpdate(username string, id string) { - var size float64 = 0 - var userHomeDirectory string = strings.Replace(strings.Join([]string{"/home/", string(username)}, ""), "\"", "", -1) - fmt.Println(userHomeDirectory) - sizeHome := DirSize(&userHomeDirectory) - size += sizeHome - sizeMail := DirSize(&userHomeDirectory) - size += sizeMail - RedisClient.Set("storage"+"-"+string(id), size, 0) - fmt.Printf("Set Call | Username: %v, ID: %v | Bytes: %f\n", string(username), string(id), size) + var size float64 = 0 + var userHomeDirectory string = strings.Replace(strings.Join([]string{"/home/", string(username)}, ""), "\"", "", -1) + fmt.Println(userHomeDirectory) + sizeHome := DirSize(&userHomeDirectory) + size += sizeHome + sizeMail := DirSize(&userHomeDirectory) + size += sizeMail + RedisClient.Set("storage"+"-"+string(id), size, 0) + fmt.Printf("Set Call | Username: %v, ID: %v | Bytes: %f\n", string(username), string(id), size) } -- 2.20.1 From 6d186a7f3a6f3166dabcae05f3b94700d368e3e4 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 28 Dec 2019 02:45:32 +0000 Subject: [PATCH 002/516] Change build --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 355e0cc..872be08 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "dist/Client.js", "scripts": { "lint": "eslint ./ --ext ts --fix", - "build": "tsc -p ./tsconfig.json", + "build": "sh ./build.sh", "lint-find": "eslint ./ --ext ts" }, "author": "Library of Code sp-us Engineering Team", -- 2.20.1 From 609079fc12e7206587378a882d6e61ece296942f Mon Sep 17 00:00:00 2001 From: Matthew R Date: Fri, 27 Dec 2019 21:54:54 -0500 Subject: [PATCH 003/516] rewrite build.sh --- build.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/build.sh b/build.sh index a243591..8b38d4c 100644 --- a/build.sh +++ b/build.sh @@ -1,6 +1,5 @@ -echo "Library of Code sp-us | Cloud Services" -echo "TypeScript & Go" -echo "Building TS files" -yarn run build -echo "Building Go files" -go build -o dist/intervals/storage src/intervals/storage.go src/intervals/dirsize.go \ No newline at end of file +# This file builds the Go binaries. Hardcoded by LOC Engineering +go build -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go +file dist/bin/storage +go build -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go +file dist/bin/checkCertificate -- 2.20.1 From f229e4a8251852319029ab7363f4a18cb40fb346 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Fri, 27 Dec 2019 21:55:21 -0500 Subject: [PATCH 004/516] add parseCertificate typescript bindings --- src/functions/parseCertificate.ts | 61 +++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/functions/parseCertificate.ts diff --git a/src/functions/parseCertificate.ts b/src/functions/parseCertificate.ts new file mode 100644 index 0000000..2f45301 --- /dev/null +++ b/src/functions/parseCertificate.ts @@ -0,0 +1,61 @@ +import { Client } from '..'; + +export interface Certificate { + subject: { + commonName: string, + emailAddress: string + organizationName: string, + organizationalUnitName: string, + countryName: string, + }, + issuer: { + commonName: string + emailAddress: null, + organizationName: string, + organizationalUnitName: string, + countryName: string, + }, + extensions: { + keyUsage: '[ Not implemented by executable ]', + extendedKeyUsage: string[], + certificatePolicies: string[], + }, + serial: string, + fingerPrint: string, + signatureAlgorithm: string, + publicKeyAlgorithm: string, + notBefore: Date, + notAfter: Date, +} + +export default async function parseCertificate(client: Client, pathToCertificate: string): Promise { + const result = await client.util.exec(`${__dirname}/../bin/checkCertificate ${pathToCertificate}`); + const parsedObject = JSON.parse(result); + return { + subject: { + commonName: parsedObject.RawParse.Subject.CommonName, + emailAddress: parsedObject.AbstractParse.EmailAddress, + organizationName: parsedObject.RawParse.Subject.Organization[0], + organizationalUnitName: parsedObject.RawParse.Subject.OrganizationalUnit[0], + countryName: parsedObject.RawParse.Subject.Country[0], + }, + issuer: { + commonName: parsedObject.RawParse.Issuer.CommonName, + emailAddress: null, + organizationName: parsedObject.RawParse.Issuer.Organization[0], + organizationalUnitName: parsedObject.RawParse.Issuer.OrganizationalUnit[0], + countryName: parsedObject.RawParse.Issuer.Country[0], + }, + extensions: { + keyUsage: '[ Not implemented by executable ]', + extendedKeyUsage: parsedObject.AbstractParse.ExtendedKeyUsage, + certificatePolicies: parsedObject.AbstractParse.PolicyIdentifiers, + }, + serial: parsedObject.AbstractParse.SerialNumber, + fingerPrint: parsedObject.AbstractParse.FingerPrint, + signatureAlgorithm: parsedObject.AbstractParse.SignatureAlgorithm, + publicKeyAlgorithm: parsedObject.AbstractParse.PublicKeyAlgorithm, + notBefore: new Date(parsedObject.RawParse.NotBefore), + notAfter: new Date(parsedObject.RawParse.NotAfter), + }; +} -- 2.20.1 From 2b227d49f457ee216297af029939c93f192c8670 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 28 Dec 2019 03:12:14 +0000 Subject: [PATCH 005/516] Add subcommand --- src/commands/securesign.ts | 3 +- src/commands/securesign_alliance.ts | 78 +++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/commands/securesign_alliance.ts diff --git a/src/commands/securesign.ts b/src/commands/securesign.ts index 4f184a5..6b7dfbe 100644 --- a/src/commands/securesign.ts +++ b/src/commands/securesign.ts @@ -6,6 +6,7 @@ import Init from './securesign_init'; import Account from './securesign_account'; import ActivateKey from './securesign_activatekey'; import CreateCrt from './securesign_createcrt'; +import Alliace from './securesign_alliance'; export default class SecureSign extends Command { constructor(client: Client) { @@ -14,7 +15,7 @@ export default class SecureSign extends Command { this.description = 'Runs SecureSign CLI commands'; this.usage = `Run ${this.client.config.prefix}${this.name} [subcommand] for usage information`; this.aliases = ['ss']; - this.subcmds = [Build, Init, Account, ActivateKey, CreateCrt]; + this.subcmds = [Build, Init, Account, ActivateKey, CreateCrt, Alliace]; this.enabled = true; } diff --git a/src/commands/securesign_alliance.ts b/src/commands/securesign_alliance.ts new file mode 100644 index 0000000..cc54c10 --- /dev/null +++ b/src/commands/securesign_alliance.ts @@ -0,0 +1,78 @@ +import { Message } from 'eris'; +import axios from 'axios'; +import fs from 'fs-extra'; +import { Client } from '..'; +import { Command } from '../class'; + +export default class SecureSign_Alliance extends Command { + constructor(client: Client) { + super(client); + this.name = 'alliance'; + this.description = 'Claims an alliance/promo key'; + this.usage = `${this.client.config.prefix}securesign alliance [key]`; + this.enabled = true; + this.guildOnly = false; + } + + public async run(message: Message, args: string[]) { + try { + const account = await this.client.db.Account.findOne({ userID: message.author.id }); + if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); + if (!account.hash) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not initialized***`); + + const promocode = args[0]; + const splitPromo = promocode.split('-'); + if (splitPromo.length !== 5 || splitPromo.some((code) => code.length < 4 || code.length > 6)) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid promotion code***`); + + const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Activating key...***`); + const Authorization = this.client.util.getAcctHash(account.homepath); + + // Check if they can activate promos + try { + const { data } = await axios({ + method: 'GET', + url: 'https://api.securesign.org/account/details', + headers: { Authorization, 'Content-Type': 'application/json' }, + }); + + const { promo } = data.message; + if (!promo) return msg.edit(`${this.client.stores.emojis.error} ***Please ask a member of staff to generate an activation key with promotions allowed***`); + } catch (error) { + const { code } = error.response.data; + if (code === 1001) { + await this.client.db.Account.updateOne({ userID: account.userID }, { $set: { hash: false } }); + this.client.getDMChannel(account.userID).then((channel) => channel.createMessage('Your SecureSign password has been reset - please reinitialize your SecureSign account')).catch(); + return msg.edit(`${this.client.stores.emojis.error} ***Authentication failed***`); + } + throw error; + } + + let data: { URL: string }; + try { + const request = await axios({ + method: 'POST', + url: 'https://api.securesign.org/certificates/alliance/client', + headers: { Authorization }, + }); + data = request.data; + } catch (error) { + const { code } = error.response.data; + if (code === 1001) { + await this.client.db.Account.updateOne({ userID: account.userID }, { $set: { hash: false } }); + this.client.getDMChannel(account.userID).then((channel) => channel.createMessage('Your SecureSign password has been reset - please reinitialize your SecureSign account')).catch(); + return msg.edit(`${this.client.stores.emojis.error} ***Authentication failed***`); + } + if (code === 1002) return msg.edit(`${this.client.stores.emojis.error} ***Server responded with ${error.message}`); + throw error; + } + + const certificate = await axios({ method: 'GET', url: data.URL }); + if (!fs.existsSync(`${account.homepath}/Validation/`)) await fs.mkdir(`${account.homepath}/Validation/`); + await fs.writeFile(`${account.homepath}/Validation/${account.username}.crt`, certificate.data, { encoding: 'utf8' }); + + return msg.edit(`${this.client.stores.emojis.success} ***Successfully activated key and created and saved certificate***`); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} -- 2.20.1 From f2d250921f670c85d2a9baf26b7cab30dcb436d9 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 28 Dec 2019 03:33:14 +0000 Subject: [PATCH 006/516] Get rid of the damn comments --- src/commands/createaccount.ts | 17 ----------------- src/functions/checkLock.ts | 26 -------------------------- 2 files changed, 43 deletions(-) diff --git a/src/commands/createaccount.ts b/src/commands/createaccount.ts index 4546c61..9e6eb35 100644 --- a/src/commands/createaccount.ts +++ b/src/commands/createaccount.ts @@ -45,23 +45,6 @@ export default class CreateAccount extends Command { await this.client.util.createAccount(passHash, etcPasswd, args[2], args[0], args[1], message.author.id); await this.client.util.createModerationLog(args[0], message.member, 0); - /* - const log = await new this.client.db.Moderation({ - username: args[2], userID: args[0], logID: uuid(), moderatorID: message.author.id, reason: 'User requested account creation', type: 0, date: new Date(), - }); - await log.save(); - - const embed = new RichEmbed(); - embed.setTitle('Cloud Account | Create'); - embed.setColor('00ff00'); - embed.addField('User', `${args[2]} | <@${args[0]}>`); - embed.addField('Engineer', `<@${message.author.id}>`, true); - embed.addField('Reason', 'User requested account creation'); - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - embed.setTimestamp(); - // @ts-ignore - this.client.createMessage('580950455581147146', { embed }); - */ this.client.util.transport.sendMail({ to: args[1], diff --git a/src/functions/checkLock.ts b/src/functions/checkLock.ts index 48c83b9..8ef6313 100644 --- a/src/functions/checkLock.ts +++ b/src/functions/checkLock.ts @@ -14,32 +14,6 @@ export default function checkLock(client: Client): void { await moderation.updateOne({ 'expiration.processed': true }); await account.updateOne({ locked: false }); await client.util.createModerationLog(account.userID, client.user, 3, 'Auto'); - /* - const mod = new client.db.Moderation({ - username: account.username, - userID: account.userID, - logID: uuid(), - moderatorID: client.user.id, - reason: 'Auto', - type: 3, - date: new Date(), - }); - await mod.save(); - const embed = new RichEmbed(); - embed.setTitle('Account Infraction | Unlock'); - embed.setColor(3066993); - embed.addField('User', `${account.username} | <@${account.userID}>`, true); - embed.addField('Supervisor', 'SYSTEM', true); - embed.addField('Reason', 'Auto', true); - embed.setFooter(client.user.username, client.user.avatarURL); - embed.setTimestamp(); - client.getDMChannel(account.userID).then((user) => { - // @ts-ignore - user.createMessage({ embed }); - }); - // @ts-ignore - client.createMessage('580950455581147146', { embed }); - */ client.signale.complete(`Unlocked account ${account.username} | Queue date at ${moderation.expiration.date.toLocaleString('en-us')}`); } }); -- 2.20.1 From 0a2088977be928d6721ca35fce906a7664449e70 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 30 Dec 2019 16:40:23 +0000 Subject: [PATCH 007/516] Added subcommand --- src/commands/cwg.ts | 3 +- src/commands/cwg_updatecert.ts | 63 ++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/commands/cwg_updatecert.ts diff --git a/src/commands/cwg.ts b/src/commands/cwg.ts index 502f51f..b7a4ade 100644 --- a/src/commands/cwg.ts +++ b/src/commands/cwg.ts @@ -4,6 +4,7 @@ import { Client } from '..'; import Create from './cwg_create'; import Data from './cwg_data'; import Delete from './cwg_delete'; +import UpdateCert from './cwg_updatecert'; export default class CWG extends Command { constructor(client: Client) { @@ -12,7 +13,7 @@ export default class CWG extends Command { this.description = 'Manages aspects for the CWG.'; this.usage = `Run ${this.client.config.prefix}${this.name} [subcommand] for usage information`; this.permissions = { roles: ['446104438969466890'] }; - this.subcmds = [Create, Data, Delete]; + this.subcmds = [Create, Data, Delete, UpdateCert]; this.enabled = true; } diff --git a/src/commands/cwg_updatecert.ts b/src/commands/cwg_updatecert.ts new file mode 100644 index 0000000..7f2b6aa --- /dev/null +++ b/src/commands/cwg_updatecert.ts @@ -0,0 +1,63 @@ +import { writeFile } from 'fs-extra'; +import axios from 'axios'; +import { Message } from 'eris'; +import { Command } from '../class'; +import { Client } from '..'; + +export default class CWG_UpdateCert extends Command { + constructor(client: Client) { + super(client); + this.name = 'updatecert'; + this.description = 'Update a CWG certificate'; + this.usage = `${this.client.config.prefix}cwg updatecert [Domain | Port] [Cert Chain] [Private Key] || Use snippets raw URL`; + this.permissions = { roles: ['525441307037007902'] }; + this.aliases = ['update', 'updatecrt', 'renew', 'renewcert', 'renewcrt']; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + if (!args[2]) return this.client.commands.get('help').run(message, ['cwg', this.name]); + const dom = await this.client.db.Domain.findOne({ $or: [{ domain: args[0] }, { port: Number(args[0]) || '' }] }); + if (!dom) return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); + const { domain, port, x509 } = dom; + const { cert, key } = x509; + + const urls = args.slice(1, 3); // eslint-disable-line + if (urls.some((l) => !l.includes('snippets.cloud.libraryofcode.org/raw/'))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid snippets URL***`); + const tasks = urls.map((l) => axios({ method: 'GET', url: l })); + const response = await Promise.all(tasks); + const certAndPrivateKey: string[] = response.map((r) => r.data); + + if (!this.isValidCertificateChain(certAndPrivateKey[0])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid Certificate Chain***`); + if (!this.isValidPrivateKey(certAndPrivateKey[1])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid Private Key***`); + + const writeTasks = [writeFile(cert, certAndPrivateKey[0], { encoding: 'utf8' }), writeFile(key, certAndPrivateKey[1], { encoding: 'utf8' })]; + await Promise.all(writeTasks); + + return message.channel.createMessage(`${this.client.stores.emojis.success} ***Updated certificate certificate for ${domain} on port ${port}`); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } + + public checkOccurance(text: string, query: string) { + return (text.match(new RegExp(query, 'g')) || []).length; + } + + public isValidCertificateChain(cert: string) { + if (!cert.startsWith('-----BEGIN CERTIFICATE-----')) return false; + if (!cert.endsWith('-----END CERTIFICATE-----')) return false; + if (this.checkOccurance(cert, '-----BEGIN CERTIFICATE-----') !== 2) return false; + if (this.checkOccurance(cert, '-----END CERTIFICATE-----') !== 2) return false; + return true; + } + + public isValidPrivateKey(key: string) { + if (!key.startsWith('-----BEGIN PRIVATE KEY-----')) return false; + if (!key.endsWith('-----END PRIVATE KEY-----')) return false; + if (this.checkOccurance(key, '-----BEGIN PRIVATE KEY-----') !== 1) return false; + if (this.checkOccurance(key, '-----END PRIVATE KEY-----') !== 1) return false; + return true; + } +} -- 2.20.1 From 6cbedfa04bc78450a9d22fa645c05c4e535e3eff Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 30 Dec 2019 16:47:14 +0000 Subject: [PATCH 008/516] include subcommands in cache removal --- src/commands/load.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/commands/load.ts b/src/commands/load.ts index ec4130d..f76b4b9 100644 --- a/src/commands/load.ts +++ b/src/commands/load.ts @@ -31,6 +31,7 @@ export default class Load extends Command { try { delete require.cache[`${corepath}/commands/index.js`]; delete require.cache[`${corepath}/commands/${args[1]}.js`]; + Object.keys(require.cache).filter((path) => path.includes(`${args[1]}_`)).forEach((path) => delete require.cache[path]); const cmdIndex = require('../commands'); let Cmd = cmdIndex[args[1]]; if (!Cmd) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Could not find file***`); @@ -39,6 +40,7 @@ export default class Load extends Command { this.client.loadCommand(Cmd); delete require.cache[`${corepath}/commands/index.js`]; delete require.cache[`${corepath}/commands/${args[1]}.js`]; + Object.keys(require.cache).filter((path) => path.includes(`${args[1]}_`)).forEach((path) => delete require.cache[path]); } catch (error) { if (error.message.includes('Cannot find module')) return message.channel.createMessage(`${this.client.stores.emojis} ***Cannot find file***`); throw error; -- 2.20.1 From c1538538eb77279d8f120e8144bf52385af2b64c Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 30 Dec 2019 16:51:56 +0000 Subject: [PATCH 009/516] Fix build --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 872be08..e710b4a 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "dist/Client.js", "scripts": { "lint": "eslint ./ --ext ts --fix", - "build": "sh ./build.sh", + "build": "tsc -p ./tsconfig.json && sh ./build.sh", "lint-find": "eslint ./ --ext ts" }, "author": "Library of Code sp-us Engineering Team", -- 2.20.1 From 591ced7c06ad0b9ad4452826b7e3334ade5580a9 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 30 Dec 2019 16:57:34 +0000 Subject: [PATCH 010/516] Trim newlines --- src/commands/cwg_updatecert.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/commands/cwg_updatecert.ts b/src/commands/cwg_updatecert.ts index 7f2b6aa..13d0c25 100644 --- a/src/commands/cwg_updatecert.ts +++ b/src/commands/cwg_updatecert.ts @@ -46,18 +46,18 @@ export default class CWG_UpdateCert extends Command { } public isValidCertificateChain(cert: string) { - if (!cert.startsWith('-----BEGIN CERTIFICATE-----')) return false; - if (!cert.endsWith('-----END CERTIFICATE-----')) return false; - if (this.checkOccurance(cert, '-----BEGIN CERTIFICATE-----') !== 2) return false; - if (this.checkOccurance(cert, '-----END CERTIFICATE-----') !== 2) 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 (this.checkOccurance(cert.replace(/^\s+|\s+$/g, ''), '-----BEGIN CERTIFICATE-----') !== 2) return false; + if (this.checkOccurance(cert.replace(/^\s+|\s+$/g, ''), '-----END CERTIFICATE-----') !== 2) return false; return true; } public isValidPrivateKey(key: string) { - if (!key.startsWith('-----BEGIN PRIVATE KEY-----')) return false; - if (!key.endsWith('-----END PRIVATE KEY-----')) return false; - if (this.checkOccurance(key, '-----BEGIN PRIVATE KEY-----') !== 1) return false; - if (this.checkOccurance(key, '-----END PRIVATE KEY-----') !== 1) 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 (this.checkOccurance(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; return true; } } -- 2.20.1 From fe31d925a3e398d3f565104189bc5e398ed94c06 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 30 Dec 2019 16:59:22 +0000 Subject: [PATCH 011/516] Fix markdown --- src/commands/cwg_updatecert.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/cwg_updatecert.ts b/src/commands/cwg_updatecert.ts index 13d0c25..fca080c 100644 --- a/src/commands/cwg_updatecert.ts +++ b/src/commands/cwg_updatecert.ts @@ -35,7 +35,7 @@ export default class CWG_UpdateCert extends Command { const writeTasks = [writeFile(cert, certAndPrivateKey[0], { encoding: 'utf8' }), writeFile(key, certAndPrivateKey[1], { encoding: 'utf8' })]; await Promise.all(writeTasks); - return message.channel.createMessage(`${this.client.stores.emojis.success} ***Updated certificate certificate for ${domain} on port ${port}`); + return message.channel.createMessage(`${this.client.stores.emojis.success} ***Updated certificate certificate for ${domain} on port ${port}***`); } catch (error) { return this.client.util.handleError(error, message, this); } -- 2.20.1 From a14e4eb6cfb5500d7eed74ac11e82de15cd1463b Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 30 Dec 2019 17:00:48 +0000 Subject: [PATCH 012/516] And typo --- src/commands/cwg_updatecert.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/cwg_updatecert.ts b/src/commands/cwg_updatecert.ts index fca080c..05ec502 100644 --- a/src/commands/cwg_updatecert.ts +++ b/src/commands/cwg_updatecert.ts @@ -35,7 +35,7 @@ export default class CWG_UpdateCert extends Command { const writeTasks = [writeFile(cert, certAndPrivateKey[0], { encoding: 'utf8' }), writeFile(key, certAndPrivateKey[1], { encoding: 'utf8' })]; await Promise.all(writeTasks); - return message.channel.createMessage(`${this.client.stores.emojis.success} ***Updated certificate certificate for ${domain} on port ${port}***`); + return message.channel.createMessage(`${this.client.stores.emojis.success} ***Updated certificate for ${domain} on port ${port}***`); } catch (error) { return this.client.util.handleError(error, message, this); } -- 2.20.1 From 5b600571f628bfabb79825c0b2bad6439392672c Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 30 Dec 2019 17:03:17 +0000 Subject: [PATCH 013/516] Update perms --- src/commands/load.ts | 2 +- src/commands/pull.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/load.ts b/src/commands/load.ts index f76b4b9..7853617 100644 --- a/src/commands/load.ts +++ b/src/commands/load.ts @@ -8,7 +8,7 @@ export default class Load extends Command { this.name = 'load'; this.description = '(Re)loads command, config or util'; this.aliases = ['reload']; - this.permissions = { users: ['253600545972027394', '278620217221971968'] }; + this.permissions = { roles: ['525441307037007902'] }; this.enabled = true; } diff --git a/src/commands/pull.ts b/src/commands/pull.ts index 6205880..4ccdf81 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -9,7 +9,7 @@ export default class Pull extends Command { this.description = 'Fetches the latest commit from Gitlab'; this.aliases = ['update']; this.enabled = true; - this.permissions = { users: ['253600545972027394', '278620217221971968'] }; + this.permissions = { roles: ['525441307037007902'] }; } public async run(message: Message) { -- 2.20.1 From 49f8d48cfd7649f51c42d58f214ea05a32d4d9c6 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 30 Dec 2019 17:54:45 -0500 Subject: [PATCH 014/516] update build file --- build.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build.sh b/build.sh index 8b38d4c..1bd63a7 100644 --- a/build.sh +++ b/build.sh @@ -1,5 +1,7 @@ # This file builds the Go binaries. Hardcoded by LOC Engineering -go build -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go +CGO_ENABLED=0 go build -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go file dist/bin/storage -go build -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go +CGO_ENABLED=0 go build -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go file dist/bin/checkCertificate +CGO_ENABLED=0 go build -o dist/bin/checkCertSignatures src/go/checkCertSignatures/checkCertSignatures.go +file /dist/bin/checkCertSignatures -- 2.20.1 From d464d3fa1c1d4b32544626b6a811ed317dda0e8c Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 30 Dec 2019 17:58:39 -0500 Subject: [PATCH 015/516] set env variables for Util.exec --- src/class/Util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index c51c484..282e209 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -29,7 +29,7 @@ export default class Util { let result: string; // eslint-disable-next-line no-useless-catch try { - const res = await ex(command); + const res = await ex(command, { env: { HOME: '/root' } }); result = res.stderr || res.stdout; } catch (err) { return Promise.reject(new Error(`Command failed: ${err.cmd}\n${err.stderr || err.stdout}`)); -- 2.20.1 From 2e88d683013fae2d19b75ab517770fb3de3c8629 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 30 Dec 2019 17:59:07 -0500 Subject: [PATCH 016/516] add cert/priv key signature checker --- .../checkCertSignatures.go | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/go/checkCertSignatures/checkCertSignatures.go diff --git a/src/go/checkCertSignatures/checkCertSignatures.go b/src/go/checkCertSignatures/checkCertSignatures.go new file mode 100644 index 0000000..8d6bcdf --- /dev/null +++ b/src/go/checkCertSignatures/checkCertSignatures.go @@ -0,0 +1,28 @@ +package main + +import ( + "fmt" + "encoding/json" + "crypto/tls" + "os" +) + +// ReturnValue the struct for what the JSON should return +type ReturnValue struct { + Ok bool `json:"ok"` + Message string `json:"message"` +} + +func main() { + _, err := tls.LoadX509KeyPair(os.Args[1], os.Args[2]) + if err != nil && err.Error() == "tls: private key does not match public key" { + json, _ := json.Marshal(&ReturnValue{Ok: false, Message: "PUBLIC KEY DOES NOT MATCH PRIVATE KEY"}) + fmt.Printf("%s", string(json)) + return + } else if err != nil { + panic(err) + } else { + json, _ := json.Marshal(&ReturnValue{Ok: true, Message: "PUBLIC KEY MATCHES PRIVATE KEY"}) + fmt.Printf("%s", string(json)) + } +} \ No newline at end of file -- 2.20.1 From a9cd35b21a89cdaf9cc91f6e9ad5a7d3cfefc1b3 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 30 Dec 2019 18:14:09 -0500 Subject: [PATCH 017/516] add coal to eval & exec user array --- src/commands/eval.ts | 2 +- src/commands/exec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index 16d9fc3..cdbe4d4 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -12,7 +12,7 @@ export default class Eval extends Command { this.aliases = ['e']; this.description = 'Evaluate JavaScript code'; this.enabled = true; - this.permissions = { users: ['253600545972027394', '278620217221971968'] }; + this.permissions = { users: ['253600545972027394', '278620217221971968', '155698776512790528'] }; this.guildOnly = false; } diff --git a/src/commands/exec.ts b/src/commands/exec.ts index 164efcf..5ac0b34 100644 --- a/src/commands/exec.ts +++ b/src/commands/exec.ts @@ -10,7 +10,7 @@ export default class Exec extends Command { this.description = 'Executes command'; this.aliases = ['ex']; this.enabled = true; - this.permissions = { users: ['253600545972027394', '278620217221971968'] }; + this.permissions = { users: ['253600545972027394', '278620217221971968', '155698776512790528'] }; this.guildOnly = false; } -- 2.20.1 From da29adac493478b20c75efe0964b2c52a4bf1889 Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 03:28:57 +0000 Subject: [PATCH 018/516] Improvements --- src/commands/parse.ts | 32 +++++++++++++++++--------------- src/commands/parseall.ts | 22 +++++++++++++++------- src/functions/index.ts | 2 ++ 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/commands/parse.ts b/src/commands/parse.ts index acd293f..fcd0765 100644 --- a/src/commands/parse.ts +++ b/src/commands/parse.ts @@ -3,6 +3,7 @@ import { parseCert } from '@ghaiklor/x509'; import { Message } from 'eris'; import { Client } from '..'; import { Command, RichEmbed } from '../class'; +import { parseCertificate } from '../functions'; export default class Parse extends Command { constructor(client: Client) { @@ -25,18 +26,19 @@ export default class Parse extends Command { return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate Validation directory.***`); } if (!dir.length) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate certificate.***`); - const cert = parseCert(`${account.homepath}/Validation/${dir[0]}`); - const subjectCommonName = cert.subject.commonName ? cert.subject.commonName : 'Not Specified'; - const subjectEmailAddress = cert.subject.emailAddress ? cert.subject.emailAddress : 'Not Specified'; - const subjectOrganization = cert.subject.organizationName ? cert.subject.organizationName : 'Not Specified'; - const subjectOrganizationalUnit = cert.subject.organizationalUnitName ? cert.subject.organizationalUnitName : 'Not Specified'; - const subjectCountry = cert.subject.countryName ? cert.subject.countryName : 'Not Specified'; - const issuerCommonName = cert.issuer.commonName ? cert.issuer.commonName : 'Not Specified'; - const issuerEmailAddress = cert.issuer.emailAddress ? cert.issuer.emailAddress : 'Not Specified'; - const issuerOrganization = cert.issuer.organizationName ? cert.issuer.organizationName : 'Not Specified'; - const issuerOrganizationalUnit = cert.issuer.organizationalUnitName ? cert.issuer.organizationalUnitName : 'Not Specified'; - const issuerCountry = cert.issuer.countryName ? cert.issuer.countryName : 'Not Specified'; - const user = this.client.users.get(account.userID) ? this.client.users.get(account.userID) : await this.client.getRESTUser(account.userID); + const cert = await parseCertificate(this.client, dir[0]); + // const cert = parseCert(`${account.homepath}/Validation/${dir[0]}`); + const subjectCommonName = cert.subject.commonName || 'Not Specified'; + const subjectEmailAddress = cert.subject.emailAddress || 'Not Specified'; + const subjectOrganization = cert.subject.organizationName || 'Not Specified'; + const subjectOrganizationalUnit = cert.subject.organizationalUnitName || 'Not Specified'; + const subjectCountry = cert.subject.countryName || 'Not Specified'; + const issuerCommonName = cert.issuer.commonName || 'Not Specified'; + const issuerEmailAddress = cert.issuer.emailAddress || 'Not Specified'; + const issuerOrganization = cert.issuer.organizationName || 'Not Specified'; + const issuerOrganizationalUnit = cert.issuer.organizationalUnitName || 'Not Specified'; + const issuerCountry = cert.issuer.countryName || 'Not Specified'; + const user = this.client.users.get(account.userID) || await this.client.getRESTUser(account.userID); const embed = new RichEmbed(); embed.setTitle('Parse x509 Certificate'); embed.setDescription(`${account.homepath}/Validation/${dir[0]} | ${account.username} <@${user.id}>`); @@ -46,10 +48,10 @@ export default class Parse extends Command { embed.addField('Serial Number', cert.serial, true); embed.addField('Fingerprint', cert.fingerPrint, true); embed.addField('Signature Algorithm', cert.signatureAlgorithm, true); - embed.addField('Public Key Algorithm', cert.publicKey.algorithm, true); + embed.addField('Public Key Algorithm', cert.publicKeyAlgorithm, true); embed.addField('Key Usage', cert.extensions.keyUsage, true); - embed.addField('Extended Key Usage', cert.extensions.extendedKeyUsage, true); - embed.addField('Policies', cert.extensions.certificatePolicies, true); + embed.addField('Extended Key Usage', cert.extensions.extendedKeyUsage.join(', '), true); + embed.addField('Policies', cert.extensions.certificatePolicies.join(', '), true); embed.addField('Issued On', new Date(cert.notBefore).toLocaleString('en-us'), true); embed.addField('Expires On', new Date(cert.notAfter).toLocaleString('en-us'), true); embed.setFooter(this.client.user.username, this.client.user.avatarURL); diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 9d9d246..887df58 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -24,20 +24,28 @@ export default class Parseall extends Command { embed.setFooter(`Requested by ${message.member.username}#${message.member.discriminator}`, message.member.avatarURL); embed.setTimestamp(); const search = await this.client.db.Account.find(); - const accounts = search.map((acc) => acc.homepath); + const accounts = search; const final: string[] = []; accounts.forEach(async (a) => { try { - const certFile = readdirSync(`${a}/Validation`)[0]; - const { notAfter } = parseCert(`${a}/Validation/${certFile}`); + const certFile = readdirSync(`${a.homepath}/Validation`)[0]; + const { notAfter } = parseCert(`${a.homepath}/Validation/${certFile}`); // @ts-ignore - const time = moment.preciseDiff(new Date(), notAfter); + const timeObject: {years: number, months: number, days: number, hours: number, minutes: number, seconds: number, firstDateWasLater: boolean} = moment.preciseDiff(new Date(), notAfter, true); + const precise: [number, string][] = []; + // @ts-ignore + const timeArray: number[] = Object.values(timeObject).filter((v) => !isNaN(v)).forEach((t: number) => { // eslint-disable-line + const index = timeArray.indexOf(t); + const measurements = ['yr', 'mo', 'd', 'h', 'm', 's']; + precise.push([t, measurements[index]]); + }); + const time = precise.map(((v) => v.join(''))).join(', '); - if (notAfter < new Date()) final.push(`${this.client.stores.emojis.error} **${a}** Certificate expired ${time} ago`); - else final.push(`${this.client.stores.emojis.success} **${a}** Certificate expires in ${time}`); + if (notAfter < new Date()) final.push(`${this.client.stores.emojis.error} **${a.username}** Certificate expired ${time} ago`); + else final.push(`${this.client.stores.emojis.success} **${a.username}** Certificate expires in ${time}`); } catch (error) { - if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) final.push(`${this.client.stores.emojis.error} **${a}** Unable to locate certificate`); + if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) final.push(`${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`); else throw error; } }); diff --git a/src/functions/index.ts b/src/functions/index.ts index b4047fb..4395294 100644 --- a/src/functions/index.ts +++ b/src/functions/index.ts @@ -1,2 +1,4 @@ export { default as checkLock } from './checkLock'; export { default as dataConversion } from './dataConversion'; +export { default as checkSS } from './checkSS'; +export { default as parseCertificate } from './parseCertificate'; -- 2.20.1 From 817ac0aa97f6399b83d3ebb7be53d2b12e9f2d1c Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 12:50:52 +0000 Subject: [PATCH 019/516] Check if cert and private key match --- src/commands/cwg_updatecert.ts | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/commands/cwg_updatecert.ts b/src/commands/cwg_updatecert.ts index 05ec502..aa11590 100644 --- a/src/commands/cwg_updatecert.ts +++ b/src/commands/cwg_updatecert.ts @@ -1,4 +1,4 @@ -import { writeFile } from 'fs-extra'; +import { writeFile, unlink } from 'fs-extra'; import axios from 'axios'; import { Message } from 'eris'; import { Command } from '../class'; @@ -20,7 +20,7 @@ export default class CWG_UpdateCert extends Command { if (!args[2]) return this.client.commands.get('help').run(message, ['cwg', this.name]); const dom = await this.client.db.Domain.findOne({ $or: [{ domain: args[0] }, { port: Number(args[0]) || '' }] }); if (!dom) return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); - const { domain, port, x509 } = dom; + const { domain, port, x509, account } = dom; const { cert, key } = x509; const urls = args.slice(1, 3); // eslint-disable-line @@ -32,7 +32,16 @@ export default class CWG_UpdateCert extends Command { if (!this.isValidCertificateChain(certAndPrivateKey[0])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid Certificate Chain***`); if (!this.isValidPrivateKey(certAndPrivateKey[1])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid Private Key***`); - const writeTasks = [writeFile(cert, certAndPrivateKey[0], { encoding: 'utf8' }), writeFile(key, certAndPrivateKey[1], { encoding: 'utf8' })]; + const path = `/var/CloudServices/temp/${account.id}`; + const temp = [writeFile(`${path}.chain.crt`, certAndPrivateKey[0]), writeFile(`${path}.key.pem`, certAndPrivateKey[1])]; + const removeFiles = [unlink(`${path}.chain.crt`), unlink(`${path}.key.pem`)]; + await Promise.all(temp); + if (!this.isMatchingPair(`${path}.chain.crt`, `${path}.key.pem`)) { + await Promise.all(removeFiles); + return message.channel.createMessage(`${this.client.stores.emojis.error} ***Certificate and private key do not match***`); + } + + const writeTasks = [writeFile(cert, certAndPrivateKey[0], { encoding: 'utf8' }), writeFile(key, certAndPrivateKey[1], { encoding: 'utf8' }), ...removeFiles]; await Promise.all(writeTasks); return message.channel.createMessage(`${this.client.stores.emojis.success} ***Updated certificate for ${domain} on port ${port}***`); @@ -60,4 +69,10 @@ export default class CWG_UpdateCert extends Command { if (this.checkOccurance(key.replace(/^\s+|\s+$/g, ''), '-----END PRIVATE KEY-----') !== 1) return false; return true; } + + public async isMatchingPair(cert: string, privateKey: string) { + const result: string = await this.client.util.exec(`${__dirname}/../bin/checkCertSignatures ${cert} ${privateKey}`); + const { ok }: { ok: boolean } = JSON.parse(result); + return ok; + } } -- 2.20.1 From 2a60c7dcf2ec7899d3fcb57f0bde9a1b27581a46 Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 13:07:47 +0000 Subject: [PATCH 020/516] Fix cert pathing --- src/commands/parse.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/parse.ts b/src/commands/parse.ts index fcd0765..5c1abf3 100644 --- a/src/commands/parse.ts +++ b/src/commands/parse.ts @@ -26,7 +26,7 @@ export default class Parse extends Command { return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate Validation directory.***`); } if (!dir.length) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate certificate.***`); - const cert = await parseCertificate(this.client, dir[0]); + const cert = await parseCertificate(this.client, `${account.homepath}/Validation/${dir[0]}`); // const cert = parseCert(`${account.homepath}/Validation/${dir[0]}`); const subjectCommonName = cert.subject.commonName || 'Not Specified'; const subjectEmailAddress = cert.subject.emailAddress || 'Not Specified'; -- 2.20.1 From e21140ce58d2dc4cc6b6515f9e73c3ac7123481d Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 13:19:31 +0000 Subject: [PATCH 021/516] Fix array errors if null --- src/functions/parseCertificate.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/functions/parseCertificate.ts b/src/functions/parseCertificate.ts index 2f45301..f9d78ca 100644 --- a/src/functions/parseCertificate.ts +++ b/src/functions/parseCertificate.ts @@ -35,16 +35,16 @@ export default async function parseCertificate(client: Client, pathToCertificate subject: { commonName: parsedObject.RawParse.Subject.CommonName, emailAddress: parsedObject.AbstractParse.EmailAddress, - organizationName: parsedObject.RawParse.Subject.Organization[0], - organizationalUnitName: parsedObject.RawParse.Subject.OrganizationalUnit[0], - countryName: parsedObject.RawParse.Subject.Country[0], + organizationName: parsedObject.RawParse.Subject.Organization ? parsedObject.RawParse.Subject.Organization[0] : null, + organizationalUnitName: parsedObject.RawParse.Subject.OrganizationalUnit ? parsedObject.RawParse.Subject.OrganizationalUnit[0] : null, + countryName: parsedObject.RawParse.Subject.Country ? parsedObject.RawParse.Subject.Country[0] : null, }, issuer: { commonName: parsedObject.RawParse.Issuer.CommonName, emailAddress: null, - organizationName: parsedObject.RawParse.Issuer.Organization[0], - organizationalUnitName: parsedObject.RawParse.Issuer.OrganizationalUnit[0], - countryName: parsedObject.RawParse.Issuer.Country[0], + organizationName: parsedObject.RawParse.Issuer.Organization ? parsedObject.RawParse.Issuer.Organization[0] : null, + organizationalUnitName: parsedObject.RawParse.Issuer.OrganizationalUnit ? parsedObject.RawParse.Issuer.OrganizationalUnit[0] : null, + countryName: parsedObject.RawParse.Issuer.Country ? parsedObject.RawParse.Issuer.Country[0] : null, }, extensions: { keyUsage: '[ Not implemented by executable ]', -- 2.20.1 From 5bb02c85f0a71c31327067c69707eb986d0b60cc Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 15:10:12 +0000 Subject: [PATCH 022/516] Should fix certificate status not showing --- src/commands/parseall.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 887df58..ea119c5 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -35,7 +35,8 @@ export default class Parseall extends Command { const timeObject: {years: number, months: number, days: number, hours: number, minutes: number, seconds: number, firstDateWasLater: boolean} = moment.preciseDiff(new Date(), notAfter, true); const precise: [number, string][] = []; // @ts-ignore - const timeArray: number[] = Object.values(timeObject).filter((v) => !isNaN(v)).forEach((t: number) => { // eslint-disable-line + const timeArray: number[] = Object.values(timeObject).filter((v) => typeof v === 'number'); + timeArray.forEach((t) => { // eslint-disable-line const index = timeArray.indexOf(t); const measurements = ['yr', 'mo', 'd', 'h', 'm', 's']; precise.push([t, measurements[index]]); -- 2.20.1 From 18b534f1a89ee24033d71aa3a31637c3f7de7d6f Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 15:14:41 +0000 Subject: [PATCH 023/516] Fix build? --- build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.sh b/build.sh index 1bd63a7..1a8e4a2 100644 --- a/build.sh +++ b/build.sh @@ -1,7 +1,7 @@ # This file builds the Go binaries. Hardcoded by LOC Engineering -CGO_ENABLED=0 go build -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go +CGO_ENABLED=0 go build -o dist/bin/storage ./src/go/storage/storage.go src/go/storage/dirsize.go file dist/bin/storage -CGO_ENABLED=0 go build -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go +CGO_ENABLED=0 go build -o dist/bin/checkCertificate ./src/go/checkCertificate/checkCertificate.go file dist/bin/checkCertificate -CGO_ENABLED=0 go build -o dist/bin/checkCertSignatures src/go/checkCertSignatures/checkCertSignatures.go +CGO_ENABLED=0 go build -o dist/bin/checkCertSignatures ./src/go/checkCertSignatures/checkCertSignatures.go file /dist/bin/checkCertSignatures -- 2.20.1 From fe382652093e5fd84add61eb4e947128251c8fcd Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 15:17:10 +0000 Subject: [PATCH 024/516] Revert --- build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.sh b/build.sh index 1a8e4a2..1bd63a7 100644 --- a/build.sh +++ b/build.sh @@ -1,7 +1,7 @@ # This file builds the Go binaries. Hardcoded by LOC Engineering -CGO_ENABLED=0 go build -o dist/bin/storage ./src/go/storage/storage.go src/go/storage/dirsize.go +CGO_ENABLED=0 go build -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go file dist/bin/storage -CGO_ENABLED=0 go build -o dist/bin/checkCertificate ./src/go/checkCertificate/checkCertificate.go +CGO_ENABLED=0 go build -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go file dist/bin/checkCertificate -CGO_ENABLED=0 go build -o dist/bin/checkCertSignatures ./src/go/checkCertSignatures/checkCertSignatures.go +CGO_ENABLED=0 go build -o dist/bin/checkCertSignatures src/go/checkCertSignatures/checkCertSignatures.go file /dist/bin/checkCertSignatures -- 2.20.1 From b2196186be9b5e367634579d0f2c1830bc14476c Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 15:27:42 +0000 Subject: [PATCH 025/516] Revert "Fix cert pathing" This reverts commit 2a60c7dcf2ec7899d3fcb57f0bde9a1b27581a46. --- src/commands/parse.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/parse.ts b/src/commands/parse.ts index 5c1abf3..fcd0765 100644 --- a/src/commands/parse.ts +++ b/src/commands/parse.ts @@ -26,7 +26,7 @@ export default class Parse extends Command { return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate Validation directory.***`); } if (!dir.length) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate certificate.***`); - const cert = await parseCertificate(this.client, `${account.homepath}/Validation/${dir[0]}`); + const cert = await parseCertificate(this.client, dir[0]); // const cert = parseCert(`${account.homepath}/Validation/${dir[0]}`); const subjectCommonName = cert.subject.commonName || 'Not Specified'; const subjectEmailAddress = cert.subject.emailAddress || 'Not Specified'; -- 2.20.1 From adad62cf960174e3b9d8237d25404a3b75da22a0 Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 15:32:33 +0000 Subject: [PATCH 026/516] idk anymore --- src/commands/parse.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/parse.ts b/src/commands/parse.ts index fcd0765..5c1abf3 100644 --- a/src/commands/parse.ts +++ b/src/commands/parse.ts @@ -26,7 +26,7 @@ export default class Parse extends Command { return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate Validation directory.***`); } if (!dir.length) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate certificate.***`); - const cert = await parseCertificate(this.client, dir[0]); + const cert = await parseCertificate(this.client, `${account.homepath}/Validation/${dir[0]}`); // const cert = parseCert(`${account.homepath}/Validation/${dir[0]}`); const subjectCommonName = cert.subject.commonName || 'Not Specified'; const subjectEmailAddress = cert.subject.emailAddress || 'Not Specified'; -- 2.20.1 From bde6439c25453236b262522644e3ee3109691a6a Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 15:39:09 +0000 Subject: [PATCH 027/516] Seeing if this does anything --- src/go/checkCertificate/checkCertificate.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/go/checkCertificate/checkCertificate.go b/src/go/checkCertificate/checkCertificate.go index b9cebdd..3430629 100644 --- a/src/go/checkCertificate/checkCertificate.go +++ b/src/go/checkCertificate/checkCertificate.go @@ -2,14 +2,14 @@ package main import ( - "crypto/sha1" - "crypto/x509" - "encoding/hex" - "encoding/json" - "encoding/pem" - "encoding/xml" + "./sha1" + "./x509" + "./hex" + "./json" + "./pem" + "./xml" "fmt" - "io/ioutil" + "./ioutil" "os" ) -- 2.20.1 From b77a0491af22cc047284f4fd6c7959dad0c56abe Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 15:40:28 +0000 Subject: [PATCH 028/516] ugh --- src/go/checkCertificate/checkCertificate.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/go/checkCertificate/checkCertificate.go b/src/go/checkCertificate/checkCertificate.go index 3430629..b9cebdd 100644 --- a/src/go/checkCertificate/checkCertificate.go +++ b/src/go/checkCertificate/checkCertificate.go @@ -2,14 +2,14 @@ package main import ( - "./sha1" - "./x509" - "./hex" - "./json" - "./pem" - "./xml" + "crypto/sha1" + "crypto/x509" + "encoding/hex" + "encoding/json" + "encoding/pem" + "encoding/xml" "fmt" - "./ioutil" + "io/ioutil" "os" ) -- 2.20.1 From a56895c22cbd146df118ef191bee5cd236c1688e Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 15:44:24 +0000 Subject: [PATCH 029/516] idek --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e710b4a..25c9234 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "dist/Client.js", "scripts": { "lint": "eslint ./ --ext ts --fix", - "build": "tsc -p ./tsconfig.json && sh ./build.sh", + "build": "tsc -p ./tsconfig.json && sh /var/CloudServices/build.sh", "lint-find": "eslint ./ --ext ts" }, "author": "Library of Code sp-us Engineering Team", -- 2.20.1 From 125e5815f9f8956e4f7319bb97daf955b93076a2 Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 15:45:29 +0000 Subject: [PATCH 030/516] Nope --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 25c9234..e710b4a 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "dist/Client.js", "scripts": { "lint": "eslint ./ --ext ts --fix", - "build": "tsc -p ./tsconfig.json && sh /var/CloudServices/build.sh", + "build": "tsc -p ./tsconfig.json && sh ./build.sh", "lint-find": "eslint ./ --ext ts" }, "author": "Library of Code sp-us Engineering Team", -- 2.20.1 From 2fa5a2a5ff71b27afffdaab6935dcc275530c238 Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 15:46:19 +0000 Subject: [PATCH 031/516] try this --- build.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/build.sh b/build.sh index 1bd63a7..9890e17 100644 --- a/build.sh +++ b/build.sh @@ -1,7 +1,6 @@ # This file builds the Go binaries. Hardcoded by LOC Engineering -CGO_ENABLED=0 go build -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go +go build -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go file dist/bin/storage -CGO_ENABLED=0 go build -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go +go build -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go file dist/bin/checkCertificate -CGO_ENABLED=0 go build -o dist/bin/checkCertSignatures src/go/checkCertSignatures/checkCertSignatures.go -file /dist/bin/checkCertSignatures + -- 2.20.1 From 221680c248727a8ae59da2e1e622f68266f7f748 Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 15:47:05 +0000 Subject: [PATCH 032/516] nope --- build.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/build.sh b/build.sh index 9890e17..1bd63a7 100644 --- a/build.sh +++ b/build.sh @@ -1,6 +1,7 @@ # This file builds the Go binaries. Hardcoded by LOC Engineering -go build -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go +CGO_ENABLED=0 go build -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go file dist/bin/storage -go build -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go +CGO_ENABLED=0 go build -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go file dist/bin/checkCertificate - +CGO_ENABLED=0 go build -o dist/bin/checkCertSignatures src/go/checkCertSignatures/checkCertSignatures.go +file /dist/bin/checkCertSignatures -- 2.20.1 From b4ad5d40558c603fbe3e9394d54cabe9b64235bc Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 15:57:21 +0000 Subject: [PATCH 033/516] . --- build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.sh b/build.sh index 1bd63a7..c682eab 100644 --- a/build.sh +++ b/build.sh @@ -1,7 +1,7 @@ # This file builds the Go binaries. Hardcoded by LOC Engineering -CGO_ENABLED=0 go build -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go +CGO_ENABLED=0 go build -o ./dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go file dist/bin/storage -CGO_ENABLED=0 go build -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go +CGO_ENABLED=0 go build -o ./dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go file dist/bin/checkCertificate -CGO_ENABLED=0 go build -o dist/bin/checkCertSignatures src/go/checkCertSignatures/checkCertSignatures.go +CGO_ENABLED=0 go build -o ./dist/bin/checkCertSignatures src/go/checkCertSignatures/checkCertSignatures.go file /dist/bin/checkCertSignatures -- 2.20.1 From 54c7cb77f191aee0e9b3749916e36b4215597c63 Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 15:59:24 +0000 Subject: [PATCH 034/516] . --- build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.sh b/build.sh index c682eab..4c2ccac 100644 --- a/build.sh +++ b/build.sh @@ -1,7 +1,7 @@ # This file builds the Go binaries. Hardcoded by LOC Engineering -CGO_ENABLED=0 go build -o ./dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go +CGO_ENABLED=0 go build -o ./dist/bin/storage ./src/go/storage/storage.go ./src/go/storage/dirsize.go file dist/bin/storage -CGO_ENABLED=0 go build -o ./dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go +CGO_ENABLED=0 go build -o ./dist/bin/checkCertificate ./src/go/checkCertificate/checkCertificate.go file dist/bin/checkCertificate -CGO_ENABLED=0 go build -o ./dist/bin/checkCertSignatures src/go/checkCertSignatures/checkCertSignatures.go +CGO_ENABLED=0 go build -o ./dist/bin/checkCertSignatures ./src/go/checkCertSignatures/checkCertSignatures.go file /dist/bin/checkCertSignatures -- 2.20.1 From 4910ba62db2199014d7441e8ab0ea1ab082d7dec Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 16:13:51 +0000 Subject: [PATCH 035/516] remove 0 values --- src/commands/parseall.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index ea119c5..18af83c 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -41,7 +41,7 @@ export default class Parseall extends Command { const measurements = ['yr', 'mo', 'd', 'h', 'm', 's']; precise.push([t, measurements[index]]); }); - const time = precise.map(((v) => v.join(''))).join(', '); + const time = precise.filter((n) => n[0]).map(((v) => v.join(''))).join(', '); if (notAfter < new Date()) final.push(`${this.client.stores.emojis.error} **${a.username}** Certificate expired ${time} ago`); else final.push(`${this.client.stores.emojis.success} **${a.username}** Certificate expires in ${time}`); -- 2.20.1 From 92dec14df815667e4b5ddb488fde0cbff62ddd46 Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 16:31:19 +0000 Subject: [PATCH 036/516] Fix something? --- build.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.sh b/build.sh index 4c2ccac..0a3a3d8 100644 --- a/build.sh +++ b/build.sh @@ -1,7 +1,7 @@ # This file builds the Go binaries. Hardcoded by LOC Engineering -CGO_ENABLED=0 go build -o ./dist/bin/storage ./src/go/storage/storage.go ./src/go/storage/dirsize.go +CGO_ENABLED=0 go build -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go file dist/bin/storage -CGO_ENABLED=0 go build -o ./dist/bin/checkCertificate ./src/go/checkCertificate/checkCertificate.go +CGO_ENABLED=0 go build -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go file dist/bin/checkCertificate -CGO_ENABLED=0 go build -o ./dist/bin/checkCertSignatures ./src/go/checkCertSignatures/checkCertSignatures.go -file /dist/bin/checkCertSignatures +CGO_ENABLED=0 go build -o dist/bin/checkCertSignatures src/go/checkCertSignatures/checkCertSignatures.go +file dist/bin/checkCertSignatures -- 2.20.1 From ae971f9f32bb82fd1e8654b32fbe7be7d6ba83f3 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Wed, 1 Jan 2020 15:55:43 -0500 Subject: [PATCH 037/516] optional args to Util.exec --- src/class/Util.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index 282e209..83feb14 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -24,12 +24,26 @@ export default class Util { }); } - public async exec(command: string): Promise { + /** + * Executes a terminal command async. + * @param command The command to execute + * @param options childProcess.ExecOptions, the env option is automatically set if not provided. + */ + public async exec(command: string, options?: childProcess.ExecOptions): Promise { const ex = promisify(childProcess.exec); let result: string; // eslint-disable-next-line no-useless-catch + let args: childProcess.ExecOptions; try { - const res = await ex(command, { env: { HOME: '/root' } }); + if (options) { + args = options; + if (!args.env) { + args.env = { HOME: '/root' }; + } + } else { + args.env = { HOME: '/root' }; + } + const res = await ex(command, args); result = res.stderr || res.stdout; } catch (err) { return Promise.reject(new Error(`Command failed: ${err.cmd}\n${err.stderr || err.stdout}`)); -- 2.20.1 From 65bf8e04868ca84c4c4b8fb3e1786867b75c999d Mon Sep 17 00:00:00 2001 From: Matthew R Date: Wed, 1 Jan 2020 15:55:58 -0500 Subject: [PATCH 038/516] small fixes to build.sh --- build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.sh b/build.sh index 1bd63a7..1d5e3fa 100644 --- a/build.sh +++ b/build.sh @@ -1,7 +1,7 @@ # This file builds the Go binaries. Hardcoded by LOC Engineering -CGO_ENABLED=0 go build -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go +go build -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go file dist/bin/storage -CGO_ENABLED=0 go build -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go +go build -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go file dist/bin/checkCertificate -CGO_ENABLED=0 go build -o dist/bin/checkCertSignatures src/go/checkCertSignatures/checkCertSignatures.go +go build -o dist/bin/checkCertSignatures src/go/checkCertSignatures/checkCertSignatures.go file /dist/bin/checkCertSignatures -- 2.20.1 From e9430a85e6a564f6c78cdb8202e5b2ef3fd648c6 Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 21:35:42 +0000 Subject: [PATCH 039/516] made it so much less clusterfuck --- src/class/Util.ts | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index 83feb14..e8580de 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -32,18 +32,9 @@ export default class Util { public async exec(command: string, options?: childProcess.ExecOptions): Promise { const ex = promisify(childProcess.exec); let result: string; - // eslint-disable-next-line no-useless-catch - let args: childProcess.ExecOptions; try { - if (options) { - args = options; - if (!args.env) { - args.env = { HOME: '/root' }; - } - } else { - args.env = { HOME: '/root' }; - } - const res = await ex(command, args); + if (!options || (!options.env)) options.env = { HOME: '/root' }; + const res = await ex(command, options); result = res.stderr || res.stdout; } catch (err) { return Promise.reject(new Error(`Command failed: ${err.cmd}\n${err.stderr || err.stdout}`)); -- 2.20.1 From 41f42c2f9d3e0a8e457197aecc68b57bbc7410ee Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 21:37:20 +0000 Subject: [PATCH 040/516] same as prev --- src/class/Util.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index e8580de..a24364d 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -29,11 +29,11 @@ export default class Util { * @param command The command to execute * @param options childProcess.ExecOptions, the env option is automatically set if not provided. */ - public async exec(command: string, options?: childProcess.ExecOptions): Promise { + public async exec(command: string, options: childProcess.ExecOptions = {}): Promise { const ex = promisify(childProcess.exec); let result: string; try { - if (!options || (!options.env)) options.env = { HOME: '/root' }; + if (!options.env) options.env = { HOME: '/root' }; const res = await ex(command, options); result = res.stderr || res.stdout; } catch (err) { -- 2.20.1 From d5be7f6e0f504781358ff45821b7660241c1d2c6 Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 21:39:55 +0000 Subject: [PATCH 041/516] Set CWD --- src/commands/pull.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commands/pull.ts b/src/commands/pull.ts index 4ccdf81..39d7920 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -20,7 +20,7 @@ export default class Pull extends Command { let pull: string; try { - pull = await this.client.util.exec('git pull'); + pull = await this.client.util.exec('git pull', { cwd: '/var/CloudServices' }); } catch (error) { const updatedMessage = updateMessage.content.replace(`${this.client.stores.emojis.loading} ***Fetching latest commit...***`, `${this.client.stores.emojis.error} ***Could not fetch latest commit***`) .replace(/```$/, `${error.message}\n\`\`\``); @@ -46,7 +46,7 @@ export default class Pull extends Command { let install: string; try { - install = await this.client.util.exec('yarn install'); + install = await this.client.util.exec('yarn install', { cwd: '/var/CloudServices' }); } catch (error) { this.client.updating = false; const updatedMessage = passedPull.content.replace(`${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`, `${this.client.stores.emojis.error} ***Failed to reinstall dependencies***`) @@ -71,7 +71,7 @@ export default class Pull extends Command { let build: string; try { - build = await this.client.util.exec('yarn run build'); + build = await this.client.util.exec('yarn run build', { cwd: '/var/CloudServices' }); } catch (error) { const updatedMessage = updatedPackages.content.replace(`${this.client.stores.emojis.loading} ***Rebuilding files...***`, `${this.client.stores.emojis.error} ***Failed to rebuild files***`) .replace(/```$/, `${error.message}\n\`\`\``); -- 2.20.1 From 7b3963dc547f592dc91c267af6c7f181d2b298bf Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 21:45:46 +0000 Subject: [PATCH 042/516] Use golang parseCertificate --- src/commands/parseall.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 18af83c..999365b 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -4,6 +4,7 @@ import { readdirSync } from 'fs'; import moment from 'moment'; import { Client } from '..'; import { Command, RichEmbed } from '../class'; +import { parseCertificate } from '../functions'; export default class Parseall extends Command { constructor(client: Client) { @@ -30,7 +31,7 @@ export default class Parseall extends Command { accounts.forEach(async (a) => { try { const certFile = readdirSync(`${a.homepath}/Validation`)[0]; - const { notAfter } = parseCert(`${a.homepath}/Validation/${certFile}`); + const { notAfter } = await parseCertificate(this.client, `${a.homepath}/Validation/${certFile}`); // @ts-ignore const timeObject: {years: number, months: number, days: number, hours: number, minutes: number, seconds: number, firstDateWasLater: boolean} = moment.preciseDiff(new Date(), notAfter, true); const precise: [number, string][] = []; @@ -43,8 +44,8 @@ export default class Parseall extends Command { }); const time = precise.filter((n) => n[0]).map(((v) => v.join(''))).join(', '); - if (notAfter < new Date()) final.push(`${this.client.stores.emojis.error} **${a.username}** Certificate expired ${time} ago`); - else final.push(`${this.client.stores.emojis.success} **${a.username}** Certificate expires in ${time}`); + if (notAfter < new Date()) final.push(`${this.client.stores.emojis.error} **${a.username}** Expired ${time} ago`); + else final.push(`${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`); } catch (error) { if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) final.push(`${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`); else throw error; -- 2.20.1 From ab30afd7bc4ac0b57b644ecf059497538c55dc9b Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 22:00:08 +0000 Subject: [PATCH 043/516] Change result return --- src/class/Util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index a24364d..f050ef6 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -35,7 +35,7 @@ export default class Util { try { if (!options.env) options.env = { HOME: '/root' }; const res = await ex(command, options); - result = res.stderr || res.stdout; + result = `${res.stdout}${res.stderr}`; } catch (err) { return Promise.reject(new Error(`Command failed: ${err.cmd}\n${err.stderr || err.stdout}`)); } -- 2.20.1 From df58a9c4fe10bf6bc8d7f406df32ac739cc6c57c Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 22:04:13 +0000 Subject: [PATCH 044/516] set cwd --- src/commands/exec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/exec.ts b/src/commands/exec.ts index 5ac0b34..0a9cc2f 100644 --- a/src/commands/exec.ts +++ b/src/commands/exec.ts @@ -21,7 +21,7 @@ export default class Exec extends Command { const response = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Executing \`${args.join(' ')}\`***`); let result: string; try { - result = await this.client.util.exec(args.join(' ')); + result = await this.client.util.exec(args.join(' '), { cwd: '/var/CloudServices' }); } catch (error) { result = error.message; } -- 2.20.1 From bee69c5041e0b6c2d8c52eb6c523e2a643df559d Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 22:06:43 +0000 Subject: [PATCH 045/516] Change reject message --- src/class/Util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index f050ef6..c52ac58 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -37,7 +37,7 @@ export default class Util { const res = await ex(command, options); result = `${res.stdout}${res.stderr}`; } catch (err) { - return Promise.reject(new Error(`Command failed: ${err.cmd}\n${err.stderr || err.stdout}`)); + return Promise.reject(new Error(`Command failed: ${err.cmd}\n${err.stderr}${err.stdout}`)); } return result; } -- 2.20.1 From 6390276306604a97be6b48e995bf77378f44c546 Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 22:09:15 +0000 Subject: [PATCH 046/516] Check something --- src/commands/pull.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/pull.ts b/src/commands/pull.ts index 39d7920..421289a 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -71,7 +71,7 @@ export default class Pull extends Command { let build: string; try { - build = await this.client.util.exec('yarn run build', { cwd: '/var/CloudServices' }); + build = await this.client.util.exec('ls && yarn run build', { cwd: '/var/CloudServices' }); } catch (error) { const updatedMessage = updatedPackages.content.replace(`${this.client.stores.emojis.loading} ***Rebuilding files...***`, `${this.client.stores.emojis.error} ***Failed to rebuild files***`) .replace(/```$/, `${error.message}\n\`\`\``); -- 2.20.1 From 91c7b0c6f5f62e451a83bcdee63cdbedae59c9ad Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 22:21:41 +0000 Subject: [PATCH 047/516] Error catching for invalid certificates --- src/commands/parse.ts | 9 +++++++-- src/commands/parseall.ts | 1 + src/functions/index.ts | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/commands/parse.ts b/src/commands/parse.ts index 5c1abf3..2bd957b 100644 --- a/src/commands/parse.ts +++ b/src/commands/parse.ts @@ -3,7 +3,7 @@ import { parseCert } from '@ghaiklor/x509'; import { Message } from 'eris'; import { Client } from '..'; import { Command, RichEmbed } from '../class'; -import { parseCertificate } from '../functions'; +import { parseCertificate, Certificate } from '../functions'; export default class Parse extends Command { constructor(client: Client) { @@ -26,7 +26,12 @@ export default class Parse extends Command { return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate Validation directory.***`); } if (!dir.length) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate certificate.***`); - const cert = await parseCertificate(this.client, `${account.homepath}/Validation/${dir[0]}`); + let cert: Certificate; + try { + cert = await parseCertificate(this.client, `${account.homepath}/Validation/${dir[0]}`); + } catch (error) { + if (error.message.includes('panic: Certificate PEM Encode == nil')) return message.channel.createMessage(`***${this.client.stores.emojis.error} Invalid certificate.***`); + } // const cert = parseCert(`${account.homepath}/Validation/${dir[0]}`); const subjectCommonName = cert.subject.commonName || 'Not Specified'; const subjectEmailAddress = cert.subject.emailAddress || 'Not Specified'; diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 999365b..b2a1cf0 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -48,6 +48,7 @@ export default class Parseall extends Command { else final.push(`${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`); } catch (error) { if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) final.push(`${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`); + if (error.message.includes('panic: Certificate PEM Encode == nil')) final.push(`${this.client.stores.emojis.error} ** ${a.username}** Invalid certificate`); else throw error; } }); diff --git a/src/functions/index.ts b/src/functions/index.ts index 4395294..bf1b87c 100644 --- a/src/functions/index.ts +++ b/src/functions/index.ts @@ -1,4 +1,4 @@ export { default as checkLock } from './checkLock'; export { default as dataConversion } from './dataConversion'; export { default as checkSS } from './checkSS'; -export { default as parseCertificate } from './parseCertificate'; +export { default as parseCertificate, Certificate } from './parseCertificate'; -- 2.20.1 From c9f49a5fce0e554f9e137bfd00b6dd7c1af090ea Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 22:38:23 +0000 Subject: [PATCH 048/516] Remove env autoset --- src/class/Util.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index c52ac58..0bbf3c5 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -27,13 +27,12 @@ export default class Util { /** * Executes a terminal command async. * @param command The command to execute - * @param options childProcess.ExecOptions, the env option is automatically set if not provided. + * @param options childProcess.ExecOptions */ public async exec(command: string, options: childProcess.ExecOptions = {}): Promise { const ex = promisify(childProcess.exec); let result: string; try { - if (!options.env) options.env = { HOME: '/root' }; const res = await ex(command, options); result = `${res.stdout}${res.stderr}`; } catch (err) { -- 2.20.1 From af44d30a7ab6cb0dd5dc8b8385c075d4bd9714c8 Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 22:39:26 +0000 Subject: [PATCH 049/516] Remove ls --- src/commands/pull.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/pull.ts b/src/commands/pull.ts index 421289a..39d7920 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -71,7 +71,7 @@ export default class Pull extends Command { let build: string; try { - build = await this.client.util.exec('ls && yarn run build', { cwd: '/var/CloudServices' }); + build = await this.client.util.exec('yarn run build', { cwd: '/var/CloudServices' }); } catch (error) { const updatedMessage = updatedPackages.content.replace(`${this.client.stores.emojis.loading} ***Rebuilding files...***`, `${this.client.stores.emojis.error} ***Failed to rebuild files***`) .replace(/```$/, `${error.message}\n\`\`\``); -- 2.20.1 From 72655080bbef453a26acb617b232ec1e993654d9 Mon Sep 17 00:00:00 2001 From: Bsian Date: Wed, 1 Jan 2020 22:43:13 +0000 Subject: [PATCH 050/516] Fix no file error in go build --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 1d5e3fa..2972b52 100644 --- a/build.sh +++ b/build.sh @@ -4,4 +4,4 @@ file dist/bin/storage go build -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go file dist/bin/checkCertificate go build -o dist/bin/checkCertSignatures src/go/checkCertSignatures/checkCertSignatures.go -file /dist/bin/checkCertSignatures +file dist/bin/checkCertSignatures -- 2.20.1 From 4a20e88566f8df1155667a1fc7cf863951930bfd Mon Sep 17 00:00:00 2001 From: john doe <5-unknown@libraryofcode.org> Date: Fri, 3 Jan 2020 02:10:25 -0500 Subject: [PATCH 051/516] Update lock.ts add usage, and add marshal role to allowed roles. --- src/commands/lock.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/lock.ts b/src/commands/lock.ts index 3648fa0..4a3f33f 100644 --- a/src/commands/lock.ts +++ b/src/commands/lock.ts @@ -8,7 +8,8 @@ export default class Lock extends Command { super(client); this.name = 'lock'; this.description = 'Locks an account.'; - this.permissions = { roles: ['455972169449734144', '643619219988152321'] }; + this.usage = `${this.client.config.prefix}lock [username || user ID] [Reason]`; + this.permissions = { roles: ['455972169449734144', '643619219988152321', '662163685439045632'] }; this.enabled = true; } -- 2.20.1 From beac839970a19f68a92f3c9ced90896f8a37424d Mon Sep 17 00:00:00 2001 From: john doe <5-unknown@libraryofcode.org> Date: Fri, 3 Jan 2020 02:11:55 -0500 Subject: [PATCH 052/516] Update unlock.ts add command usage, and marshal role to allowed roles --- src/commands/unlock.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/unlock.ts b/src/commands/unlock.ts index 56bc38c..9f7f49f 100644 --- a/src/commands/unlock.ts +++ b/src/commands/unlock.ts @@ -7,7 +7,8 @@ export default class Unlock extends Command { super(client); this.name = 'unlock'; this.description = 'Unlocks an account.'; - this.permissions = { roles: ['455972169449734144', '643619219988152321'] }; + this.usage = `${this.client.config.prefix}unlock [username || user ID] [Reason]`; + this.permissions = { roles: ['455972169449734144', '643619219988152321', '662163685439045632'] }; this.enabled = true; } -- 2.20.1 From 0a4be74bc2fba4154f7677a1c54c06f1af501675 Mon Sep 17 00:00:00 2001 From: Bsian Date: Fri, 3 Jan 2020 15:15:30 +0000 Subject: [PATCH 053/516] Update perms --- src/commands/announce.ts | 2 +- src/commands/createaccount.ts | 2 +- src/commands/deleteaccount.ts | 4 ++-- src/commands/lock.ts | 2 +- src/commands/resetpassword.ts | 2 +- src/commands/unban.ts | 2 +- src/commands/unlock.ts | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/commands/announce.ts b/src/commands/announce.ts index f0b271f..1b0207b 100644 --- a/src/commands/announce.ts +++ b/src/commands/announce.ts @@ -9,7 +9,7 @@ export default class Announce extends Command { this.description = 'Sends an announcement to all active terminals'; this.usage = `${this.client.config.prefix}announce Hi there! | ${this.client.config.prefix}announce -e EMERGENCY!`; this.aliases = ['ann']; - this.permissions = { roles: ['475817826251440128', '525441307037007902'] }; + this.permissions = { roles: ['662163685439045632'] }; this.enabled = true; } diff --git a/src/commands/createaccount.ts b/src/commands/createaccount.ts index 9e6eb35..6ca42a7 100644 --- a/src/commands/createaccount.ts +++ b/src/commands/createaccount.ts @@ -10,7 +10,7 @@ export default class CreateAccount extends Command { this.description = 'Create an account on the Cloud VM'; this.usage = `${this.client.config.prefix}createaccount [User ID] [Email] [Account name]`; this.aliases = ['createacc', 'cacc', 'caccount', 'create']; - this.permissions = { roles: ['475817826251440128', '525441307037007902'] }; + this.permissions = { roles: ['662163685439045632'] }; this.enabled = true; } diff --git a/src/commands/deleteaccount.ts b/src/commands/deleteaccount.ts index 32dc9aa..5abe7d2 100644 --- a/src/commands/deleteaccount.ts +++ b/src/commands/deleteaccount.ts @@ -10,7 +10,7 @@ export default class DeleteAccount extends Command { this.description = 'Delete an account on the Cloud VM'; this.usage = `${this.client.config.prefix}deleteaccount [User Name | User ID | Email Address] [Reason]`; this.aliases = ['deleteacc', 'dacc', 'daccount', 'delete']; - this.permissions = { roles: ['475817826251440128', '525441307037007902'] }; + this.permissions = { roles: ['662163685439045632'] }; this.guildOnly = true; this.enabled = true; } @@ -48,7 +48,7 @@ export default class DeleteAccount extends Command { subject: 'Your account has been deleted', html: `

Library of Code | Cloud Services

-

Your Cloud Account has been deleted by our Engineers. There is no way to recover your files and this decision cannot be appealed. We're sorry to see you go.

+

Your Cloud Account has been deleted by our Engineers. If your account was deleted due to infractions, this will not be appealable. We're sorry to see you go.

Reason: ${reason}

Engineer: ${message.author.username}

diff --git a/src/commands/lock.ts b/src/commands/lock.ts index 3648fa0..239cc4b 100644 --- a/src/commands/lock.ts +++ b/src/commands/lock.ts @@ -8,7 +8,7 @@ export default class Lock extends Command { super(client); this.name = 'lock'; this.description = 'Locks an account.'; - this.permissions = { roles: ['455972169449734144', '643619219988152321'] }; + this.permissions = { roles: ['455972169449734144', '662163685439045632'] }; this.enabled = true; } diff --git a/src/commands/resetpassword.ts b/src/commands/resetpassword.ts index 5310f00..c0ce814 100644 --- a/src/commands/resetpassword.ts +++ b/src/commands/resetpassword.ts @@ -10,7 +10,7 @@ export default class ResetPassword extends Command { this.description = 'Reset a cloud account password'; this.aliases = ['resetpasswd', 'resetpw']; this.usage = `${this.client.config.prefix}resetpassword [Username | User ID | Email]`; - this.permissions = { roles: ['525441307037007902', '475817826251440128'] }; + this.permissions = { roles: ['662163685439045632'] }; this.enabled = true; } diff --git a/src/commands/unban.ts b/src/commands/unban.ts index 8366434..a443c99 100644 --- a/src/commands/unban.ts +++ b/src/commands/unban.ts @@ -10,7 +10,7 @@ export default class Unban extends Command { this.description = 'Unban an IP from Cloud/NGINX'; this.aliases = ['unbanip']; this.usage = `${this.client.config.prefix}unban [service] [ip]`; - this.permissions = { roles: ['455972169449734144', '643619219988152321'] }; + this.permissions = { roles: ['455972169449734144', '662163685439045632'] }; this.enabled = true; } diff --git a/src/commands/unlock.ts b/src/commands/unlock.ts index 56bc38c..e4ee5da 100644 --- a/src/commands/unlock.ts +++ b/src/commands/unlock.ts @@ -7,7 +7,7 @@ export default class Unlock extends Command { super(client); this.name = 'unlock'; this.description = 'Unlocks an account.'; - this.permissions = { roles: ['455972169449734144', '643619219988152321'] }; + this.permissions = { roles: ['455972169449734144', '662163685439045632'] }; this.enabled = true; } -- 2.20.1 From c60b3ca216deae378d98628559e70b29c5ae5c28 Mon Sep 17 00:00:00 2001 From: Bsian Date: Fri, 3 Jan 2020 15:23:00 +0000 Subject: [PATCH 054/516] Fix typos --- src/commands/index.ts | 2 +- src/commands/load.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/index.ts b/src/commands/index.ts index f8e4bf7..f9d20aa 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,6 +1,6 @@ export { default as announce } from './announce'; export { default as bearer } from './bearer'; -export { default as createAccount } from './createaccount'; +export { default as createaccount } from './createaccount'; export { default as cwg } from './cwg'; export { default as deleteaccount } from './deleteaccount'; export { default as disk } from './disk'; diff --git a/src/commands/load.ts b/src/commands/load.ts index 7853617..1c94df7 100644 --- a/src/commands/load.ts +++ b/src/commands/load.ts @@ -42,7 +42,7 @@ export default class Load extends Command { delete require.cache[`${corepath}/commands/${args[1]}.js`]; Object.keys(require.cache).filter((path) => path.includes(`${args[1]}_`)).forEach((path) => delete require.cache[path]); } catch (error) { - if (error.message.includes('Cannot find module')) return message.channel.createMessage(`${this.client.stores.emojis} ***Cannot find file***`); + if (error.message.includes('Cannot find module')) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Could not find file***`); throw error; } } -- 2.20.1 From bdfbb94ce79d03aba28e3c7de82d0cf034dd8925 Mon Sep 17 00:00:00 2001 From: Bsian Date: Fri, 3 Jan 2020 15:34:31 +0000 Subject: [PATCH 055/516] Auto init --- src/functions/checkSS.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/functions/checkSS.ts b/src/functions/checkSS.ts index 0b132d6..0367324 100644 --- a/src/functions/checkSS.ts +++ b/src/functions/checkSS.ts @@ -7,21 +7,25 @@ export default function checkSS(client: Client) { setInterval(async () => { try { const accounts = await client.db.Account.find(); - const hashes = accounts.filter((h) => h.hash); - for (const { userID, homepath } of hashes) { + for (const { userID, homepath, hash } of accounts) { try { - const hash = client.util.getAcctHash(homepath); + const Authorization = client.util.getAcctHash(homepath); if (hash === null) throw new Error('Unable to locate auth file, homepath is probably incorrect'); await axios({ method: 'get', url: 'https://api.securesign.org/account/details', - headers: { Authorization: hash }, + headers: { Authorization }, }); + if (!hash) { + await client.db.Account.updateOne({ userID }, { $set: { hash: true } }); + client.getDMChannel(userID).then((channel) => channel.createMessage('Your SecureSign account has been automatically initialized via the SecureSign CLI.')).catch(); + } } catch (error) { + if (!hash) return; const { status } = error.response; if (status === 400 || status === 401 || status === 403 || status === 404) { await client.db.Account.updateOne({ userID }, { $set: { hash: false } }); - client.getDMChannel(userID).then((channel) => channel.createMessage('Your SecureSign password has been reset - please reinitialize your SecureSign account')).catch(); + client.getDMChannel(userID).then((channel) => channel.createMessage('Your SecureSign password has been reset - please reinitialize your SecureSign account. Run `=securesign init` for more information')).catch(); } } } -- 2.20.1 From 7a38e68048df8730f0ae58b4be22e6379f7c5060 Mon Sep 17 00:00:00 2001 From: Bsian Date: Fri, 3 Jan 2020 15:55:23 +0000 Subject: [PATCH 056/516] Allow clearing of function --- src/functions/checkLock.ts | 11 +++++++++-- src/functions/checkSS.ts | 8 +++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/functions/checkLock.ts b/src/functions/checkLock.ts index 8ef6313..da8d33f 100644 --- a/src/functions/checkLock.ts +++ b/src/functions/checkLock.ts @@ -1,7 +1,9 @@ import { Client } from '..'; -export default function checkLock(client: Client): void { - setInterval(async () => { +let interval: NodeJS.Timeout; + +export default function checkLock(client: Client) { + interval = setInterval(async () => { try { const moderations = await client.db.Moderation.find(); moderations.forEach(async (moderation) => { @@ -21,4 +23,9 @@ export default function checkLock(client: Client): void { await client.util.handleError(error); } }, 10000); + return interval; +} + +export function clear() { + clearInterval(interval); } diff --git a/src/functions/checkSS.ts b/src/functions/checkSS.ts index 0367324..3a8e75e 100644 --- a/src/functions/checkSS.ts +++ b/src/functions/checkSS.ts @@ -3,8 +3,9 @@ import axios from 'axios'; import { inspect } from 'util'; import { Client } from '..'; +let interval: NodeJS.Timeout; export default function checkSS(client: Client) { - setInterval(async () => { + interval = setInterval(async () => { try { const accounts = await client.db.Account.find(); for (const { userID, homepath, hash } of accounts) { @@ -33,4 +34,9 @@ export default function checkSS(client: Client) { client.util.handleError(error); } }, 60000); + return interval; +} + +export function clear() { + clearTimeout(interval); } -- 2.20.1 From cf23a073ea4ac3d6e07269b613dff0134695a7e3 Mon Sep 17 00:00:00 2001 From: Bsian Date: Fri, 3 Jan 2020 15:57:18 +0000 Subject: [PATCH 057/516] Include functions in export --- src/functions/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/functions/index.ts b/src/functions/index.ts index bf1b87c..a349b65 100644 --- a/src/functions/index.ts +++ b/src/functions/index.ts @@ -1,4 +1,4 @@ -export { default as checkLock } from './checkLock'; +export { default as checkLock, clear as clearLock } from './checkLock'; export { default as dataConversion } from './dataConversion'; -export { default as checkSS } from './checkSS'; +export { default as checkSS, clear as clearSS } from './checkSS'; export { default as parseCertificate, Certificate } from './parseCertificate'; -- 2.20.1 From 7b63e5c77facbca9b6e268e45c6653509e864d5e Mon Sep 17 00:00:00 2001 From: Bsian Date: Fri, 3 Jan 2020 19:54:58 +0000 Subject: [PATCH 058/516] Add flags --- src/commands/eval.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index cdbe4d4..f12e6cb 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -19,12 +19,24 @@ export default class Eval extends Command { public async run(message: Message, args: string[]) { try { // const evalMessage = message.content.slice(this.client.config.prefix.length).split(' ').slice(1).join(' '); + let evalString = args.join(' ').trim(); let evaled: any; + let depth = 0; + + if (args[0] && args[0].startsWith('-d')) { + depth = Number(args[0].replace('-d', '')); + if (!depth || depth < 0) depth = 0; + args.shift(); + } + if (args[0] === '-a' || args[0] === '-async') { + evalString = `(async () => { ${evalString} })()`; + args.shift(); + } try { - evaled = await eval(args.join(' ').trim()); + evaled = await eval(evalString); if (typeof evaled !== 'string') { - evaled = inspect(evaled, { depth: 0 }); + evaled = inspect(evaled, { depth }); } if (evaled === undefined) { evaled = 'undefined'; -- 2.20.1 From fae34861481c4b2de72af212d28fb06754e88ab7 Mon Sep 17 00:00:00 2001 From: Bsian Date: Fri, 3 Jan 2020 20:05:16 +0000 Subject: [PATCH 059/516] Correct order --- src/commands/eval.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index f12e6cb..a757ce3 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -29,8 +29,8 @@ export default class Eval extends Command { args.shift(); } if (args[0] === '-a' || args[0] === '-async') { - evalString = `(async () => { ${evalString} })()`; args.shift(); + evalString = `(async () => { ${evalString} })()`; } try { -- 2.20.1 From 8cad4a87dbad909e9a3c7a3b766261145c7b94a6 Mon Sep 17 00:00:00 2001 From: Bsian Date: Fri, 3 Jan 2020 20:09:21 +0000 Subject: [PATCH 060/516] Fix args --- src/commands/eval.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index a757ce3..dce0b14 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -19,7 +19,7 @@ export default class Eval extends Command { public async run(message: Message, args: string[]) { try { // const evalMessage = message.content.slice(this.client.config.prefix.length).split(' ').slice(1).join(' '); - let evalString = args.join(' ').trim(); + let evalString: string; let evaled: any; let depth = 0; @@ -27,10 +27,11 @@ export default class Eval extends Command { depth = Number(args[0].replace('-d', '')); if (!depth || depth < 0) depth = 0; args.shift(); + evalString = args.join(' ').trim(); } if (args[0] === '-a' || args[0] === '-async') { args.shift(); - evalString = `(async () => { ${evalString} })()`; + evalString = `(async () => { ${args.join(' ').trim()} })()`; } try { -- 2.20.1 From f5ae4392be681749171edd5a54f61d53113141b8 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 11:06:55 +0000 Subject: [PATCH 061/516] Diagnosis --- src/commands/eval.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index dce0b14..319423c 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -22,47 +22,67 @@ export default class Eval extends Command { let evalString: string; let evaled: any; let depth = 0; + this.client.signale.note('Received'); if (args[0] && args[0].startsWith('-d')) { + this.client.signale.note('Depth flag'); depth = Number(args[0].replace('-d', '')); if (!depth || depth < 0) depth = 0; + this.client.signale.note('Depth set'); args.shift(); evalString = args.join(' ').trim(); + this.client.signale.note('Eval reconfigured'); } if (args[0] === '-a' || args[0] === '-async') { + this.client.signale.note('Async flag'); args.shift(); evalString = `(async () => { ${args.join(' ').trim()} })()`; + this.client.signale.note('Eval reconfigured'); } + this.client.signale.note('Main'); try { evaled = await eval(evalString); + this.client.signale.note('evaluated with success'); if (typeof evaled !== 'string') { + this.client.signale.note('Eval returned not a string'); evaled = inspect(evaled, { depth }); + this.client.signale.note('Inspected'); } if (evaled === undefined) { + this.client.signale.note('Eval undefined'); evaled = 'undefined'; } } catch (error) { + this.client.signale.note('Error caught'); evaled = error.stack; } + this.client.signale.note('Eval finished'); evaled = evaled.replace(new RegExp(this.client.config.token, 'gi'), 'juul'); evaled = evaled.replace(new RegExp(this.client.config.emailPass, 'gi'), 'juul'); evaled = evaled.replace(new RegExp(this.client.config.cloudflare, 'gi'), 'juul'); + this.client.signale.note('Masked'); const display = this.client.util.splitString(evaled, 1975); + this.client.signale.note('Split output'); if (display[5]) { + this.client.signale.note('Output greater than 5 messages'); try { const { data } = await axios.post('https://snippets.cloud.libraryofcode.org/documents', display.join('')); + this.client.signale.note('Data sent'); return message.channel.createMessage(`${this.client.stores.emojis.success} Your evaluation evaled can be found on https://snippets.cloud.libraryofcode.org/${data.key}`); } catch (error) { + this.client.signale.note('Error posting'); return message.channel.createMessage(`${this.client.stores.emojis.error} ${error}`); } } + this.client.signale.note('Single message'); return display.forEach((m) => message.channel.createMessage(`\`\`\`js\n${m}\n\`\`\``)); } catch (error) { + this.client.signale.note('Global error caught'); return this.client.util.handleError(error, message, this); } } -- 2.20.1 From 59ae64b08fa1d7a796533bc7608f401cfdcd274a Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 11:13:22 +0000 Subject: [PATCH 062/516] More diagnosis --- src/commands/eval.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index 319423c..7127763 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -23,6 +23,8 @@ export default class Eval extends Command { let evaled: any; let depth = 0; this.client.signale.note('Received'); + this.client.signale.note(message); + this.client.signale.note(args); if (args[0] && args[0].startsWith('-d')) { this.client.signale.note('Depth flag'); @@ -32,20 +34,26 @@ export default class Eval extends Command { args.shift(); evalString = args.join(' ').trim(); this.client.signale.note('Eval reconfigured'); + this.client.signale.note(args); } if (args[0] === '-a' || args[0] === '-async') { this.client.signale.note('Async flag'); args.shift(); evalString = `(async () => { ${args.join(' ').trim()} })()`; this.client.signale.note('Eval reconfigured'); + this.client.signale.note(args); } this.client.signale.note('Main'); + this.client.signale.note(args); try { evaled = await eval(evalString); this.client.signale.note('evaluated with success'); + this.client.signale.note(evaled); + this.client.signale.note(typeof evaled); if (typeof evaled !== 'string') { - this.client.signale.note('Eval returned not a string'); + this.client.signale.note('Eval returned not a string. Depth setting:'); + this.client.signale.note(depth); evaled = inspect(evaled, { depth }); this.client.signale.note('Inspected'); } -- 2.20.1 From 9809f32ee0d857d186ea2e8a346803066586588b Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 11:18:38 +0000 Subject: [PATCH 063/516] Order fix and more diagnosis --- src/commands/eval.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index 7127763..19b0fb4 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -47,20 +47,21 @@ export default class Eval extends Command { this.client.signale.note('Main'); this.client.signale.note(args); try { + this.client.signale.note(evalString); evaled = await eval(evalString); this.client.signale.note('evaluated with success'); this.client.signale.note(evaled); this.client.signale.note(typeof evaled); + if (evaled === undefined) { + this.client.signale.note('Eval undefined'); + evaled = 'undefined'; + } if (typeof evaled !== 'string') { this.client.signale.note('Eval returned not a string. Depth setting:'); this.client.signale.note(depth); evaled = inspect(evaled, { depth }); this.client.signale.note('Inspected'); } - if (evaled === undefined) { - this.client.signale.note('Eval undefined'); - evaled = 'undefined'; - } } catch (error) { this.client.signale.note('Error caught'); evaled = error.stack; -- 2.20.1 From 0b443e82973a645aab17b08b9b6294546f06183e Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 11:21:53 +0000 Subject: [PATCH 064/516] Fix eval undefined if no args --- src/commands/eval.ts | 37 ++++--------------------------------- 1 file changed, 4 insertions(+), 33 deletions(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index 19b0fb4..f0748dd 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -19,79 +19,50 @@ export default class Eval extends Command { public async run(message: Message, args: string[]) { try { // const evalMessage = message.content.slice(this.client.config.prefix.length).split(' ').slice(1).join(' '); - let evalString: string; + let evalString = args.join(' ').trim(); let evaled: any; let depth = 0; - this.client.signale.note('Received'); - this.client.signale.note(message); - this.client.signale.note(args); if (args[0] && args[0].startsWith('-d')) { - this.client.signale.note('Depth flag'); depth = Number(args[0].replace('-d', '')); if (!depth || depth < 0) depth = 0; - this.client.signale.note('Depth set'); args.shift(); evalString = args.join(' ').trim(); - this.client.signale.note('Eval reconfigured'); - this.client.signale.note(args); } if (args[0] === '-a' || args[0] === '-async') { - this.client.signale.note('Async flag'); args.shift(); evalString = `(async () => { ${args.join(' ').trim()} })()`; - this.client.signale.note('Eval reconfigured'); - this.client.signale.note(args); } - this.client.signale.note('Main'); - this.client.signale.note(args); try { - this.client.signale.note(evalString); evaled = await eval(evalString); - this.client.signale.note('evaluated with success'); - this.client.signale.note(evaled); - this.client.signale.note(typeof evaled); + if (typeof evaled !== 'string') { + evaled = inspect(evaled, { depth }); + } if (evaled === undefined) { - this.client.signale.note('Eval undefined'); evaled = 'undefined'; } - if (typeof evaled !== 'string') { - this.client.signale.note('Eval returned not a string. Depth setting:'); - this.client.signale.note(depth); - evaled = inspect(evaled, { depth }); - this.client.signale.note('Inspected'); - } } catch (error) { - this.client.signale.note('Error caught'); evaled = error.stack; } - this.client.signale.note('Eval finished'); evaled = evaled.replace(new RegExp(this.client.config.token, 'gi'), 'juul'); evaled = evaled.replace(new RegExp(this.client.config.emailPass, 'gi'), 'juul'); evaled = evaled.replace(new RegExp(this.client.config.cloudflare, 'gi'), 'juul'); - this.client.signale.note('Masked'); const display = this.client.util.splitString(evaled, 1975); - this.client.signale.note('Split output'); if (display[5]) { - this.client.signale.note('Output greater than 5 messages'); try { const { data } = await axios.post('https://snippets.cloud.libraryofcode.org/documents', display.join('')); - this.client.signale.note('Data sent'); return message.channel.createMessage(`${this.client.stores.emojis.success} Your evaluation evaled can be found on https://snippets.cloud.libraryofcode.org/${data.key}`); } catch (error) { - this.client.signale.note('Error posting'); return message.channel.createMessage(`${this.client.stores.emojis.error} ${error}`); } } - this.client.signale.note('Single message'); return display.forEach((m) => message.channel.createMessage(`\`\`\`js\n${m}\n\`\`\``)); } catch (error) { - this.client.signale.note('Global error caught'); return this.client.util.handleError(error, message, this); } } -- 2.20.1 From a77f417e883c8d06e60e9f35ab95e6500f65a6dc Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 12:49:47 +0000 Subject: [PATCH 065/516] Fix? --- src/commands/eval.ts | 2 +- src/commands/parseall.ts | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index f0748dd..06fb02c 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -31,7 +31,7 @@ export default class Eval extends Command { } if (args[0] === '-a' || args[0] === '-async') { args.shift(); - evalString = `(async () => { ${args.join(' ').trim()} })()`; + evalString = `const top = this; (async () => { ${args.join(' ').trim()} })()`; } try { diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index b2a1cf0..ad8867e 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -25,13 +25,12 @@ export default class Parseall extends Command { embed.setFooter(`Requested by ${message.member.username}#${message.member.discriminator}`, message.member.avatarURL); embed.setTimestamp(); const search = await this.client.db.Account.find(); - const accounts = search; const final: string[] = []; - accounts.forEach(async (a) => { + for (const a of search) { try { const certFile = readdirSync(`${a.homepath}/Validation`)[0]; - const { notAfter } = await parseCertificate(this.client, `${a.homepath}/Validation/${certFile}`); + const { notAfter } = await parseCertificate(this.client, `${a.homepath}/Validation/${certFile}`); // eslint-disable-line // @ts-ignore const timeObject: {years: number, months: number, days: number, hours: number, minutes: number, seconds: number, firstDateWasLater: boolean} = moment.preciseDiff(new Date(), notAfter, true); const precise: [number, string][] = []; @@ -51,7 +50,7 @@ export default class Parseall extends Command { if (error.message.includes('panic: Certificate PEM Encode == nil')) final.push(`${this.client.stores.emojis.error} ** ${a.username}** Invalid certificate`); else throw error; } - }); + } if (final.join('\n').length < 2048) embed.setDescription(final.join('\n')); else { -- 2.20.1 From 78b926678ae7200958e224704abc46936f93c2ad Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 13:03:29 +0000 Subject: [PATCH 066/516] Stop error --- src/commands/parseall.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index ad8867e..dfd72b5 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -47,7 +47,7 @@ export default class Parseall extends Command { else final.push(`${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`); } catch (error) { if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) final.push(`${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`); - if (error.message.includes('panic: Certificate PEM Encode == nil')) final.push(`${this.client.stores.emojis.error} ** ${a.username}** Invalid certificate`); + else if (error.message.includes('panic: Certificate PEM Encode == nil')) final.push(`${this.client.stores.emojis.error} ** ${a.username}** Invalid certificate`); else throw error; } } -- 2.20.1 From cf94993dc96b6a84e935e1eab03a3cea466a3aa6 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 13:15:55 +0000 Subject: [PATCH 067/516] Speed increase i hope --- src/commands/parseall.ts | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index dfd72b5..d33da59 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -25,12 +25,22 @@ export default class Parseall extends Command { embed.setFooter(`Requested by ${message.member.username}#${message.member.discriminator}`, message.member.avatarURL); embed.setTimestamp(); const search = await this.client.db.Account.find(); - const final: string[] = []; - for (const a of search) { + const certificates = search.map((a) => { + let certFile: string; try { - const certFile = readdirSync(`${a.homepath}/Validation`)[0]; - const { notAfter } = await parseCertificate(this.client, `${a.homepath}/Validation/${certFile}`); // eslint-disable-line + certFile = readdirSync(`${a.homepath}/Validation`)[0]; // eslint-disable-line + } catch (error) { + if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) certFile = 'not_found.crt'; + else throw error; + } + return parseCertificate(this.client, `${a.homepath}/Validation/${certFile}`); + }); + + const parsed = await Promise.all(certificates); + const final = search.map((a) => { + try { + const { notAfter } = parsed[search.findIndex((acc) => acc === a)]; // @ts-ignore const timeObject: {years: number, months: number, days: number, hours: number, minutes: number, seconds: number, firstDateWasLater: boolean} = moment.preciseDiff(new Date(), notAfter, true); const precise: [number, string][] = []; @@ -43,14 +53,14 @@ export default class Parseall extends Command { }); const time = precise.filter((n) => n[0]).map(((v) => v.join(''))).join(', '); - if (notAfter < new Date()) final.push(`${this.client.stores.emojis.error} **${a.username}** Expired ${time} ago`); - else final.push(`${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`); + if (notAfter < new Date()) return `${this.client.stores.emojis.error} **${a.username}** Expired ${time} ago`; + return `${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`; } catch (error) { - if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) final.push(`${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`); - else if (error.message.includes('panic: Certificate PEM Encode == nil')) final.push(`${this.client.stores.emojis.error} ** ${a.username}** Invalid certificate`); - else throw error; + if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) return `${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`; + if (error.message.includes('panic: Certificate PEM Encode == nil')) return `${this.client.stores.emojis.error} ** ${a.username}** Invalid certificate`; + throw error; } - } + }); if (final.join('\n').length < 2048) embed.setDescription(final.join('\n')); else { -- 2.20.1 From 2e1bf68cc077cccdcb654730fabc418c7fc25ce8 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 13:18:22 +0000 Subject: [PATCH 068/516] Correct placement --- src/commands/parseall.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index d33da59..bd2fe86 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -37,9 +37,9 @@ export default class Parseall extends Command { return parseCertificate(this.client, `${a.homepath}/Validation/${certFile}`); }); - const parsed = await Promise.all(certificates); - const final = search.map((a) => { + const final = search.map(async (a) => { try { + const parsed = await Promise.all(certificates); const { notAfter } = parsed[search.findIndex((acc) => acc === a)]; // @ts-ignore const timeObject: {years: number, months: number, days: number, hours: number, minutes: number, seconds: number, firstDateWasLater: boolean} = moment.preciseDiff(new Date(), notAfter, true); -- 2.20.1 From 350e5c021de91690e54ef06b45bf57c5eebc9b88 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 13:47:54 +0000 Subject: [PATCH 069/516] Use Promise.allSettled --- src/commands/parseall.ts | 45 ++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index bd2fe86..755b981 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -4,7 +4,7 @@ import { readdirSync } from 'fs'; import moment from 'moment'; import { Client } from '..'; import { Command, RichEmbed } from '../class'; -import { parseCertificate } from '../functions'; +import { parseCertificate, Certificate } from '../functions'; export default class Parseall extends Command { constructor(client: Client) { @@ -36,30 +36,31 @@ export default class Parseall extends Command { } return parseCertificate(this.client, `${a.homepath}/Validation/${certFile}`); }); + // @ts-ignore + const parsed: {status: 'fulfilled', value: Certificate}[] | {status: 'rejected', reason: Error}[] = await Promise.allSettled(certificates); const final = search.map(async (a) => { - try { - const parsed = await Promise.all(certificates); - const { notAfter } = parsed[search.findIndex((acc) => acc === a)]; - // @ts-ignore - const timeObject: {years: number, months: number, days: number, hours: number, minutes: number, seconds: number, firstDateWasLater: boolean} = moment.preciseDiff(new Date(), notAfter, true); - const precise: [number, string][] = []; - // @ts-ignore - const timeArray: number[] = Object.values(timeObject).filter((v) => typeof v === 'number'); - timeArray.forEach((t) => { // eslint-disable-line - const index = timeArray.indexOf(t); - const measurements = ['yr', 'mo', 'd', 'h', 'm', 's']; - precise.push([t, measurements[index]]); - }); - const time = precise.filter((n) => n[0]).map(((v) => v.join(''))).join(', '); - - if (notAfter < new Date()) return `${this.client.stores.emojis.error} **${a.username}** Expired ${time} ago`; - return `${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`; - } catch (error) { - if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) return `${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`; - if (error.message.includes('panic: Certificate PEM Encode == nil')) return `${this.client.stores.emojis.error} ** ${a.username}** Invalid certificate`; - throw error; + const result = parsed[search.findIndex((acc) => acc === a)]; + if (result.status === 'rejected') { + if (result.reason.message.includes('no such file or directory') || result.reason.message.includes('File doesn\'t exist.')) return `${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`; + if (result.reason.message.includes('panic: Certificate PEM Encode == nil')) return `${this.client.stores.emojis.error} ** ${a.username}** Invalid certificate`; + throw result.reason; } + const { notAfter } = result.value; + // @ts-ignore + const timeObject: {years: number, months: number, days: number, hours: number, minutes: number, seconds: number, firstDateWasLater: boolean} = moment.preciseDiff(new Date(), notAfter, true); + const precise: [number, string][] = []; + // @ts-ignore + const timeArray: number[] = Object.values(timeObject).filter((v) => typeof v === 'number'); + timeArray.forEach((t) => { // eslint-disable-line + const index = timeArray.indexOf(t); + const measurements = ['yr', 'mo', 'd', 'h', 'm', 's']; + precise.push([t, measurements[index]]); + }); + const time = precise.filter((n) => n[0]).map(((v) => v.join(''))).join(', '); + + if (notAfter < new Date()) return `${this.client.stores.emojis.error} **${a.username}** Expired ${time} ago`; + return `${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`; }); if (final.join('\n').length < 2048) embed.setDescription(final.join('\n')); -- 2.20.1 From dd1dacfe304e0b6422b12cfa358fd7e6919164aa Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 14:06:10 +0000 Subject: [PATCH 070/516] Promises --- src/commands/parseall.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 755b981..97b6428 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -37,10 +37,10 @@ export default class Parseall extends Command { return parseCertificate(this.client, `${a.homepath}/Validation/${certFile}`); }); // @ts-ignore - const parsed: {status: 'fulfilled', value: Certificate}[] | {status: 'rejected', reason: Error}[] = await Promise.allSettled(certificates); + const parsed: Promise<{status: 'fulfilled', value: Certificate}>[] | Promise<{status: 'rejected', reason: Error}>[] = await Promise.allSettled(certificates); const final = search.map(async (a) => { - const result = parsed[search.findIndex((acc) => acc === a)]; + const result = await parsed[search.findIndex((acc) => acc === a)]; if (result.status === 'rejected') { if (result.reason.message.includes('no such file or directory') || result.reason.message.includes('File doesn\'t exist.')) return `${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`; if (result.reason.message.includes('panic: Certificate PEM Encode == nil')) return `${this.client.stores.emojis.error} ** ${a.username}** Invalid certificate`; -- 2.20.1 From 1bae7f52a24868fdd00da57bf4f28908276647d6 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 14:28:20 +0000 Subject: [PATCH 071/516] Solution? --- src/commands/parseall.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 97b6428..7c6a452 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -39,7 +39,7 @@ export default class Parseall extends Command { // @ts-ignore const parsed: Promise<{status: 'fulfilled', value: Certificate}>[] | Promise<{status: 'rejected', reason: Error}>[] = await Promise.allSettled(certificates); - const final = search.map(async (a) => { + const final = await search.map(async (a) => { const result = await parsed[search.findIndex((acc) => acc === a)]; if (result.status === 'rejected') { if (result.reason.message.includes('no such file or directory') || result.reason.message.includes('File doesn\'t exist.')) return `${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`; -- 2.20.1 From 51b888848f9b5a5cf358ea5f0c9a7b34e90c9a58 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 15:05:05 +0000 Subject: [PATCH 072/516] Proper solution? --- src/commands/parseall.ts | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 7c6a452..f7a34e8 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -26,24 +26,20 @@ export default class Parseall extends Command { embed.setTimestamp(); const search = await this.client.db.Account.find(); - const certificates = search.map((a) => { - let certFile: string; - try { - certFile = readdirSync(`${a.homepath}/Validation`)[0]; // eslint-disable-line - } catch (error) { - if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) certFile = 'not_found.crt'; - else throw error; - } - return parseCertificate(this.client, `${a.homepath}/Validation/${certFile}`); + const files = search.map((acc) => { + let certfile: string; + try { certfile = readdirSync(`${acc.homepath}/Validation`)[0] } catch (error) { if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) certfile = 'not_found.crt' } // eslint-disable-line + return `${acc.homepath}/Validation/${certfile}`; }); - // @ts-ignore - const parsed: Promise<{status: 'fulfilled', value: Certificate}>[] | Promise<{status: 'rejected', reason: Error}>[] = await Promise.allSettled(certificates); - const final = await search.map(async (a) => { + // @ts-ignore + const parsed = await Promise.allSettled(files.map((c) => parseCertificate(this.client, c))); + + const final = search.map(async (a) => { const result = await parsed[search.findIndex((acc) => acc === a)]; if (result.status === 'rejected') { if (result.reason.message.includes('no such file or directory') || result.reason.message.includes('File doesn\'t exist.')) return `${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`; - if (result.reason.message.includes('panic: Certificate PEM Encode == nil')) return `${this.client.stores.emojis.error} ** ${a.username}** Invalid certificate`; + if (result.reason.message.includes('panic: Certificate PEM Encode == nil')) return `${this.client.stores.emojis.error} **${a.username}** Invalid certificate`; throw result.reason; } const { notAfter } = result.value; -- 2.20.1 From 2558c3e78b32f27326f251dfb1b1acc041c612a8 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 15:17:03 +0000 Subject: [PATCH 073/516] Diagnosis --- src/commands/parseall.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index f7a34e8..4eec7e4 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -29,14 +29,19 @@ export default class Parseall extends Command { const files = search.map((acc) => { let certfile: string; try { certfile = readdirSync(`${acc.homepath}/Validation`)[0] } catch (error) { if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) certfile = 'not_found.crt' } // eslint-disable-line + this.client.signale.note('Cert directory set:'); + this.client.signale.note(`${acc.homepath}/Validation/${certfile}`); return `${acc.homepath}/Validation/${certfile}`; }); // @ts-ignore const parsed = await Promise.allSettled(files.map((c) => parseCertificate(this.client, c))); + this.client.signale.note('Promise settled:'); + this.client.signale.note(parsed); const final = search.map(async (a) => { const result = await parsed[search.findIndex((acc) => acc === a)]; + this.client.signale.note(result); if (result.status === 'rejected') { if (result.reason.message.includes('no such file or directory') || result.reason.message.includes('File doesn\'t exist.')) return `${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`; if (result.reason.message.includes('panic: Certificate PEM Encode == nil')) return `${this.client.stores.emojis.error} **${a.username}** Invalid certificate`; -- 2.20.1 From 4f314051b74e6fb50fde09b0074e4a9185c141f5 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 15:25:22 +0000 Subject: [PATCH 074/516] Diagnosis --- src/commands/parseall.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 4eec7e4..f14c97f 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -35,19 +35,20 @@ export default class Parseall extends Command { }); // @ts-ignore - const parsed = await Promise.allSettled(files.map((c) => parseCertificate(this.client, c))); + const parsed: ({ status: 'fulfilled', value: Certificate } | { status: 'rejected', reason: Error })[] = await Promise.allSettled(files.map((c) => parseCertificate(this.client, c))); this.client.signale.note('Promise settled:'); this.client.signale.note(parsed); const final = search.map(async (a) => { const result = await parsed[search.findIndex((acc) => acc === a)]; - this.client.signale.note(result); if (result.status === 'rejected') { + this.client.signale.info(result.reason); if (result.reason.message.includes('no such file or directory') || result.reason.message.includes('File doesn\'t exist.')) return `${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`; if (result.reason.message.includes('panic: Certificate PEM Encode == nil')) return `${this.client.stores.emojis.error} **${a.username}** Invalid certificate`; throw result.reason; } const { notAfter } = result.value; + this.client.signale.info(notAfter); // @ts-ignore const timeObject: {years: number, months: number, days: number, hours: number, minutes: number, seconds: number, firstDateWasLater: boolean} = moment.preciseDiff(new Date(), notAfter, true); const precise: [number, string][] = []; -- 2.20.1 From 6b2bb7293a2c112cfa451c97ad28957956306044 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 15:27:58 +0000 Subject: [PATCH 075/516] Diagnosis --- src/commands/parseall.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index f14c97f..8e1158f 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -48,7 +48,6 @@ export default class Parseall extends Command { throw result.reason; } const { notAfter } = result.value; - this.client.signale.info(notAfter); // @ts-ignore const timeObject: {years: number, months: number, days: number, hours: number, minutes: number, seconds: number, firstDateWasLater: boolean} = moment.preciseDiff(new Date(), notAfter, true); const precise: [number, string][] = []; @@ -60,6 +59,7 @@ export default class Parseall extends Command { precise.push([t, measurements[index]]); }); const time = precise.filter((n) => n[0]).map(((v) => v.join(''))).join(', '); + this.client.signale.info(time); if (notAfter < new Date()) return `${this.client.stores.emojis.error} **${a.username}** Expired ${time} ago`; return `${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`; -- 2.20.1 From 542bed168be5e631f6d99ac3f031afa78a42c335 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 15:28:48 +0000 Subject: [PATCH 076/516] Diagnosis --- src/commands/parseall.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 8e1158f..e593e97 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -29,15 +29,11 @@ export default class Parseall extends Command { const files = search.map((acc) => { let certfile: string; try { certfile = readdirSync(`${acc.homepath}/Validation`)[0] } catch (error) { if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) certfile = 'not_found.crt' } // eslint-disable-line - this.client.signale.note('Cert directory set:'); - this.client.signale.note(`${acc.homepath}/Validation/${certfile}`); return `${acc.homepath}/Validation/${certfile}`; }); // @ts-ignore const parsed: ({ status: 'fulfilled', value: Certificate } | { status: 'rejected', reason: Error })[] = await Promise.allSettled(files.map((c) => parseCertificate(this.client, c))); - this.client.signale.note('Promise settled:'); - this.client.signale.note(parsed); const final = search.map(async (a) => { const result = await parsed[search.findIndex((acc) => acc === a)]; -- 2.20.1 From 3a40a6cc2ba51f7ebd13d77da6ce1f4cc0c4dd4c Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 15:30:19 +0000 Subject: [PATCH 077/516] Diagnosis --- src/commands/parseall.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index e593e97..60d9151 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -38,7 +38,6 @@ export default class Parseall extends Command { const final = search.map(async (a) => { const result = await parsed[search.findIndex((acc) => acc === a)]; if (result.status === 'rejected') { - this.client.signale.info(result.reason); if (result.reason.message.includes('no such file or directory') || result.reason.message.includes('File doesn\'t exist.')) return `${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`; if (result.reason.message.includes('panic: Certificate PEM Encode == nil')) return `${this.client.stores.emojis.error} **${a.username}** Invalid certificate`; throw result.reason; @@ -55,11 +54,11 @@ export default class Parseall extends Command { precise.push([t, measurements[index]]); }); const time = precise.filter((n) => n[0]).map(((v) => v.join(''))).join(', '); - this.client.signale.info(time); if (notAfter < new Date()) return `${this.client.stores.emojis.error} **${a.username}** Expired ${time} ago`; return `${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`; }); + this.client.signale.info(final); if (final.join('\n').length < 2048) embed.setDescription(final.join('\n')); else { -- 2.20.1 From 198aea79f675031669d7a8560f0cc959b7e9584f Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 15:34:21 +0000 Subject: [PATCH 078/516] Diagnosis --- src/commands/parseall.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 60d9151..2254abc 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -35,8 +35,9 @@ export default class Parseall extends Command { // @ts-ignore const parsed: ({ status: 'fulfilled', value: Certificate } | { status: 'rejected', reason: Error })[] = await Promise.allSettled(files.map((c) => parseCertificate(this.client, c))); - const final = search.map(async (a) => { - const result = await parsed[search.findIndex((acc) => acc === a)]; + // @ts-ignore + const final: string[] = await Promise.allSettled(search.map(async (a) => { + const result = parsed[search.findIndex((acc) => acc === a)]; if (result.status === 'rejected') { if (result.reason.message.includes('no such file or directory') || result.reason.message.includes('File doesn\'t exist.')) return `${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`; if (result.reason.message.includes('panic: Certificate PEM Encode == nil')) return `${this.client.stores.emojis.error} **${a.username}** Invalid certificate`; @@ -57,7 +58,7 @@ export default class Parseall extends Command { if (notAfter < new Date()) return `${this.client.stores.emojis.error} **${a.username}** Expired ${time} ago`; return `${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`; - }); + })); this.client.signale.info(final); if (final.join('\n').length < 2048) embed.setDescription(final.join('\n')); -- 2.20.1 From dee2e6a82029c951e4a9877550478d400b94f0e5 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 15:37:37 +0000 Subject: [PATCH 079/516] FINALLY --- src/commands/parseall.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 2254abc..712542c 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -36,7 +36,7 @@ export default class Parseall extends Command { const parsed: ({ status: 'fulfilled', value: Certificate } | { status: 'rejected', reason: Error })[] = await Promise.allSettled(files.map((c) => parseCertificate(this.client, c))); // @ts-ignore - const final: string[] = await Promise.allSettled(search.map(async (a) => { + const final: {status: 'fulfilled', value: string}[] = await Promise.allSettled(search.map(async (a) => { const result = parsed[search.findIndex((acc) => acc === a)]; if (result.status === 'rejected') { if (result.reason.message.includes('no such file or directory') || result.reason.message.includes('File doesn\'t exist.')) return `${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`; @@ -59,9 +59,8 @@ export default class Parseall extends Command { if (notAfter < new Date()) return `${this.client.stores.emojis.error} **${a.username}** Expired ${time} ago`; return `${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`; })); - this.client.signale.info(final); - if (final.join('\n').length < 2048) embed.setDescription(final.join('\n')); + if (final.map((a) => a.value).join('\n').length < 2048) embed.setDescription(final.join('\n')); else { const split = this.client.util.splitString(final.join('\n'), 1024); split.forEach((s) => embed.addField('\u200B', s)); -- 2.20.1 From fa5de93c8d338e15d64ad569f4d9f165d05e5161 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 15:40:00 +0000 Subject: [PATCH 080/516] oop fix --- src/commands/parseall.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 712542c..03598d7 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -60,9 +60,11 @@ export default class Parseall extends Command { return `${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`; })); - if (final.map((a) => a.value).join('\n').length < 2048) embed.setDescription(final.join('\n')); + const result = final.map((a) => a.value); + + if (result.join('\n').length < 2048) embed.setDescription(result.join('\n')); else { - const split = this.client.util.splitString(final.join('\n'), 1024); + const split = this.client.util.splitString(result.join('\n'), 1024); split.forEach((s) => embed.addField('\u200B', s)); } -- 2.20.1 From 9549c99ebb57c9794022c648c8df2452bf3ceeaf Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 15:43:45 +0000 Subject: [PATCH 081/516] no need to use promise.allsettled --- src/commands/parseall.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 03598d7..1aa5fc2 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -35,8 +35,7 @@ export default class Parseall extends Command { // @ts-ignore const parsed: ({ status: 'fulfilled', value: Certificate } | { status: 'rejected', reason: Error })[] = await Promise.allSettled(files.map((c) => parseCertificate(this.client, c))); - // @ts-ignore - const final: {status: 'fulfilled', value: string}[] = await Promise.allSettled(search.map(async (a) => { + const final: string[] = await Promise.all(search.map(async (a) => { const result = parsed[search.findIndex((acc) => acc === a)]; if (result.status === 'rejected') { if (result.reason.message.includes('no such file or directory') || result.reason.message.includes('File doesn\'t exist.')) return `${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`; @@ -59,12 +58,11 @@ export default class Parseall extends Command { if (notAfter < new Date()) return `${this.client.stores.emojis.error} **${a.username}** Expired ${time} ago`; return `${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`; })); + this.client.signale.info(final); - const result = final.map((a) => a.value); - - if (result.join('\n').length < 2048) embed.setDescription(result.join('\n')); + if (final.join('\n').length < 2048) embed.setDescription(final.join('\n')); else { - const split = this.client.util.splitString(result.join('\n'), 1024); + const split = this.client.util.splitString(final.join('\n'), 1024); split.forEach((s) => embed.addField('\u200B', s)); } -- 2.20.1 From 56c94a5e33a30525f3f6e09e39dd08d6e5cb82fb Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 4 Jan 2020 16:14:08 +0000 Subject: [PATCH 082/516] add loading message --- src/commands/parseall.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 1aa5fc2..65e1531 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -19,6 +19,7 @@ export default class Parseall extends Command { public async run(message: Message, args: string[]) { try { + const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Loading...***`); const embed = new RichEmbed(); embed.setTitle('Certificate Validation'); embed.setAuthor(this.client.user.username, this.client.user.avatarURL); @@ -58,7 +59,6 @@ export default class Parseall extends Command { if (notAfter < new Date()) return `${this.client.stores.emojis.error} **${a.username}** Expired ${time} ago`; return `${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`; })); - this.client.signale.info(final); if (final.join('\n').length < 2048) embed.setDescription(final.join('\n')); else { @@ -67,7 +67,7 @@ export default class Parseall extends Command { } // @ts-ignore - return await message.channel.createMessage({ embed }); + return await msg.edit({ content: '', embed }); } catch (error) { return this.client.util.handleError(error, message, this); } -- 2.20.1 From 26e31dece0ed502416279cc84b85477d057c17c9 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sun, 5 Jan 2020 13:27:12 +0000 Subject: [PATCH 083/516] Added system process check --- src/commands/cwg_data.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/commands/cwg_data.ts b/src/commands/cwg_data.ts index f916223..60dad9a 100644 --- a/src/commands/cwg_data.ts +++ b/src/commands/cwg_data.ts @@ -3,7 +3,6 @@ import moment from 'moment'; import x509 from '@ghaiklor/x509'; import { createPaginationEmbed } from 'eris-pagination'; import { Message } from 'eris'; -import { promisify } from 'util'; import { Command, RichEmbed } from '../class'; import { Client } from '..'; @@ -21,7 +20,17 @@ export default class CWG_Data extends Command { try { if (!args[0]) return this.client.commands.get('help').run(message, ['cwg', this.name]); const dom = await this.client.db.Domain.find({ $or: [{ domain: args[0] }, { port: Number(args[0]) || '' }] }); - if (!dom.length) return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); + if (!dom.length) { + if (!Number.isNaN(Number(args[0]))) { + try { + await this.client.util.exec(`fuser ${args[0]}/tcp`); + return message.channel.createMessage(`***${this.client.stores.emojis.error} The port you provided is being used by a system process.***`); + } catch (error) { + return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); + } + } + return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); + } const embeds = dom.map((domain) => { const cert = fs.readFileSync(domain.x509.cert, { encoding: 'utf8' }); const embed = new RichEmbed(); -- 2.20.1 From 9ba2265e60d0411bab3a4e8d3e26bf8cfe642c89 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 5 Jan 2020 14:59:28 -0500 Subject: [PATCH 084/516] mask ip in =whois to non-marshals --- src/commands/whois.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/commands/whois.ts b/src/commands/whois.ts index e54ad1f..58082cb 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -27,7 +27,14 @@ export default class Whois extends Command { embed.setTitle('Account Information'); if (this.client.users.get(account.userID)) embed.setThumbnail(this.client.users.get(account.userID).avatarURL); embed.setColor(0x36393f); - embed.setDescription(`${await this.client.util.exec(`finger ${account.username}`)}\n${await this.client.util.exec(`chage -l ${account.username}`)}`); + let fingerInformation: string; + const result = await this.client.util.exec(`finger ${account.username}`); + if (message.member && !message.member.roles.includes('143414786913206272')) { + fingerInformation = result.replace(/((^\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, '[MASKED IP ADDRESS]'); + } else { + fingerInformation = result; + } + embed.setDescription(`${fingerInformation}\n${await this.client.util.exec(`chage -l ${account.username}`)}`); embed.addField('Username', `${account.username} | <@${account.userID}>`, true); embed.addField('ID', account.userID, true); embed.addField('Email Address', account.emailAddress, true); -- 2.20.1 From 641ac31796c846bb0e55c486c24995f7ddac52d6 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sun, 5 Jan 2020 20:53:04 +0000 Subject: [PATCH 085/516] Prompt password reset --- src/commands/resetpassword.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/resetpassword.ts b/src/commands/resetpassword.ts index c0ce814..ca38507 100644 --- a/src/commands/resetpassword.ts +++ b/src/commands/resetpassword.ts @@ -23,7 +23,7 @@ export default class ResetPassword extends Command { const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Resetting password for ${account.username}...***`); const tempPass = this.client.util.randomPassword(); - await this.client.util.exec(`echo '${account.username}:${tempPass}' | chpasswd`); + 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}\`***`; const dmChannel = await this.client.getDMChannel(account.userID); -- 2.20.1 From ca36c554a7e815d34c9e0d2872fb7e81c78ce31d Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 13 Jan 2020 18:15:11 -0500 Subject: [PATCH 086/516] update storage set --- src/go/storage/storage.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/go/storage/storage.go b/src/go/storage/storage.go index 9771d68..ae75010 100644 --- a/src/go/storage/storage.go +++ b/src/go/storage/storage.go @@ -95,11 +95,14 @@ func handler(status* bool) { func checkAccountSizeAndUpdate(username string, id string) { var size float64 = 0 var userHomeDirectory string = strings.Replace(strings.Join([]string{"/home/", string(username)}, ""), "\"", "", -1) - fmt.Println(userHomeDirectory) sizeHome := DirSize(&userHomeDirectory) size += sizeHome sizeMail := DirSize(&userHomeDirectory) size += sizeMail - RedisClient.Set("storage"+"-"+string(id), size, 0) + status := RedisClient.Set("storage"+"-"+string(username), size, 0) + fmt.Println(status.Name()) + if status.Err() != nil { + fmt.Println(status.Err()) + } fmt.Printf("Set Call | Username: %v, ID: %v | Bytes: %f\n", string(username), string(id), size) } -- 2.20.1 From a6c546dfeda841ff25b1c83d54f8922edf8fedce Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 13 Jan 2020 18:32:43 -0500 Subject: [PATCH 087/516] update storage set --- src/go/storage/storage.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/go/storage/storage.go b/src/go/storage/storage.go index ae75010..5ac393d 100644 --- a/src/go/storage/storage.go +++ b/src/go/storage/storage.go @@ -95,11 +95,12 @@ func handler(status* bool) { func checkAccountSizeAndUpdate(username string, id string) { var size float64 = 0 var userHomeDirectory string = strings.Replace(strings.Join([]string{"/home/", string(username)}, ""), "\"", "", -1) + usernameFormat := strings.Replace(username, "\"", "", -1) sizeHome := DirSize(&userHomeDirectory) size += sizeHome sizeMail := DirSize(&userHomeDirectory) size += sizeMail - status := RedisClient.Set("storage"+"-"+string(username), size, 0) + status := RedisClient.Set("storage"+"-"+usernameFormat, size, 0) fmt.Println(status.Name()) if status.Err() != nil { fmt.Println(status.Err()) -- 2.20.1 From cab6be3f401c4ab7927244b195c2b2c64dca138a Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 18 Jan 2020 00:11:32 -0500 Subject: [PATCH 088/516] add makefile --- Makefile | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f620957 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +check_certificate_files := $(wildcard src/go/checkCertificate/*.go) +check_certificate_signatures_files := $(wildcard src/go/checkCertSignatures/*.go) +storage_files := $(wildcard src/go/storage/*.go) + +all: check_certificate check_cert_signatures storage + +check_certificate: + HOME=/root go build -v -ldflags="-s -w" -o dist/bin/checkCertificate ${check_certificate_files} + @chmod 740 dist/bin/checkCertificate + file dist/bin/checkCertificate + +check_cert_signatures: + HOME=/root go build -v -ldflags="-s -w" -o dist/bin/checkCertSignatures ${check_certificate_signatures_files} + @chmod 740 dist/bin/checkCertSignatures + file dist/bin/checkCertSignatures + +storage: + HOME=/root go build -v -ldflags="-s -w" -o dist/bin/storage ${storage_files} + @chmod 740 dist/bin/storage + file dist/bin/storage -- 2.20.1 From 30714fb625af46fa2cd7ceb270b2763f46bf2482 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 18 Jan 2020 00:11:44 -0500 Subject: [PATCH 089/516] deprecate build.sh --- build.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/build.sh b/build.sh index 2972b52..b6536fc 100644 --- a/build.sh +++ b/build.sh @@ -1,7 +1,8 @@ # This file builds the Go binaries. Hardcoded by LOC Engineering -go build -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go +# DEPRECATED, USE MAKEFILE INSTEAD +go build -ldflags="-s -w" -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go file dist/bin/storage -go build -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go +go build -ldflags="-s -w" -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go file dist/bin/checkCertificate -go build -o dist/bin/checkCertSignatures src/go/checkCertSignatures/checkCertSignatures.go +go build -ldflags="-s -w" -o dist/bin/checkCertSignatures src/go/checkCertSignatures/checkCertSignatures.go file dist/bin/checkCertSignatures -- 2.20.1 From 751490a8b9d1c8cc0d42bac730a0ab12ec118dbb Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 18 Jan 2020 00:12:50 -0500 Subject: [PATCH 090/516] change email address in cmds that send notification mail --- src/commands/createaccount.ts | 2 +- src/commands/cwg_create.ts | 2 +- src/commands/deleteaccount.ts | 2 +- src/commands/lock.ts | 2 +- src/commands/notify.ts | 2 +- src/commands/warn.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/commands/createaccount.ts b/src/commands/createaccount.ts index 6ca42a7..93f85e6 100644 --- a/src/commands/createaccount.ts +++ b/src/commands/createaccount.ts @@ -48,7 +48,7 @@ export default class CreateAccount extends Command { this.client.util.transport.sendMail({ to: args[1], - from: 'Library of Code sp-us | Cloud Services ', + from: 'Library of Code sp-us | Cloud Services ', subject: 'Your account has been created', html: ` diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index ef145c1..7ac1ee0 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -68,7 +68,7 @@ export default class CWG_Create extends Command { this.client.getDMChannel(account.userID).then((r) => r.createMessage({ embed })); await this.client.util.transport.sendMail({ to: account.emailAddress, - from: 'Library of Code sp-us | Support Team ', + from: 'Library of Code sp-us | Support Team ', subject: 'Your domain has been binded', html: `

Library of Code sp-us | Cloud Services

diff --git a/src/commands/deleteaccount.ts b/src/commands/deleteaccount.ts index 5abe7d2..694fb79 100644 --- a/src/commands/deleteaccount.ts +++ b/src/commands/deleteaccount.ts @@ -44,7 +44,7 @@ export default class DeleteAccount extends Command { this.client.util.transport.sendMail({ to: account.emailAddress, - from: 'Library of Code sp-us | Cloud Services ', + from: 'Library of Code sp-us | Cloud Services ', subject: 'Your account has been deleted', html: `

Library of Code | Cloud Services

diff --git a/src/commands/lock.ts b/src/commands/lock.ts index 239cc4b..b85ec33 100644 --- a/src/commands/lock.ts +++ b/src/commands/lock.ts @@ -35,7 +35,7 @@ export default class Lock extends Command { this.client.util.transport.sendMail({ to: account.emailAddress, - from: 'Library of Code sp-us | Cloud Services ', + from: 'Library of Code sp-us | Cloud Services ', subject: 'Your account has been locked', html: `

Library of Code | Cloud Services

diff --git a/src/commands/notify.ts b/src/commands/notify.ts index e326a0f..ff3ff1e 100644 --- a/src/commands/notify.ts +++ b/src/commands/notify.ts @@ -34,7 +34,7 @@ export default class Notify extends Command { this.client.createMessage('580950455581147146', { embed }); this.client.util.transport.sendMail({ to: account.emailAddress, - from: 'Library of Code sp-us | Cloud Services ', + from: 'Library of Code sp-us | Cloud Services ', subject: 'Notification', html: `

Library of Code sp-us | Cloud Services

diff --git a/src/commands/warn.ts b/src/commands/warn.ts index bd5ce22..49d66af 100644 --- a/src/commands/warn.ts +++ b/src/commands/warn.ts @@ -25,7 +25,7 @@ export default class Warn extends Command { edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been warned by Moderator ${message.author.username}#${message.author.discriminator}.***`); this.client.util.transport.sendMail({ to: account.emailAddress, - from: 'Library of Code sp-us | Cloud Services ', + from: 'Library of Code sp-us | Cloud Services ', subject: 'Your account has been warned', html: `

Library of Code sp-us | Cloud Services

-- 2.20.1 From 711e924109a33e253819ce80b8d44868d77a6ff1 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 18 Jan 2020 00:13:46 -0500 Subject: [PATCH 091/516] run make command instead of build.sh --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e710b4a..1785d79 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "dist/Client.js", "scripts": { "lint": "eslint ./ --ext ts --fix", - "build": "tsc -p ./tsconfig.json && sh ./build.sh", + "build": "tsc -p ./tsconfig.json && make", "lint-find": "eslint ./ --ext ts" }, "author": "Library of Code sp-us Engineering Team", -- 2.20.1 From c15f2c62d58e2ddcf835ee15b75a54af600dbc3c Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 18 Jan 2020 00:15:42 -0500 Subject: [PATCH 092/516] ignore .idea --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 484ef4b..2873450 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ htmlEmail_templates yarn-error.log src/keys.json dist -securesign_genrsa.ts \ No newline at end of file +securesign_genrsa.ts +.idea -- 2.20.1 From 9544e231eebda58dbc5de9783c84dce9946a4ec4 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 18 Jan 2020 00:17:19 -0500 Subject: [PATCH 093/516] ignore .vscode --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2873450..6039e6a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ src/keys.json dist securesign_genrsa.ts .idea +.vscode -- 2.20.1 From 36f7660afdfa3db8f79db8cc530ed6079dc11f69 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 18 Jan 2020 02:05:22 -0500 Subject: [PATCH 094/516] Add TS building in makefile; yarn run build now just runs HOME=/root go build -v -ldflags="-s -w" -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go --- Makefile | 7 ++++++- package.json | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index f620957..6be4d86 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,10 @@ +# Builds TypeScript & Go + check_certificate_files := $(wildcard src/go/checkCertificate/*.go) check_certificate_signatures_files := $(wildcard src/go/checkCertSignatures/*.go) storage_files := $(wildcard src/go/storage/*.go) -all: check_certificate check_cert_signatures storage +all: check_certificate check_cert_signatures storage typescript check_certificate: HOME=/root go build -v -ldflags="-s -w" -o dist/bin/checkCertificate ${check_certificate_files} @@ -18,3 +20,6 @@ storage: HOME=/root go build -v -ldflags="-s -w" -o dist/bin/storage ${storage_files} @chmod 740 dist/bin/storage file dist/bin/storage + +typescript: + tsc -p ./tsconfig.json diff --git a/package.json b/package.json index 1785d79..8a7d054 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "dist/Client.js", "scripts": { "lint": "eslint ./ --ext ts --fix", - "build": "tsc -p ./tsconfig.json && make", + "build": "make", "lint-find": "eslint ./ --ext ts" }, "author": "Library of Code sp-us Engineering Team", -- 2.20.1 From 4c7f211ceec4ac5712904e75bfc682429659979f Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 20 Jan 2020 10:53:44 +0000 Subject: [PATCH 095/516] Stop throwing errors with C3 ECC --- src/commands/securesign_createcrt.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/securesign_createcrt.ts b/src/commands/securesign_createcrt.ts index 05d9937..1128cf3 100644 --- a/src/commands/securesign_createcrt.ts +++ b/src/commands/securesign_createcrt.ts @@ -24,6 +24,7 @@ export default class SecureSign_Init extends Command { if (options.s && options.s.toLowerCase() !== 'ecc' && options.s.toLowerCase() !== 'rsa') return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid signing type, choose between \`ecc\` or \`rsa\``); if (options.c && (!Number(options.c) || Number(options.c) < 1 || Number(options.c) > 3)) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid class selected, choose between Class \`1\`, \`2\` or \`3\``); if (options.m && (!Number(options.m) || (options.m !== '256' && options.m !== '384' && options.m !== '512'))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid SHA Digest selected, choose between \`256\`, \`384\` or \`512\``); + if (Number(options.c) === 3 && (!options.s || options.s === 'ecc')) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Class 3 ECC certificates are not supported, please use the \`-s rsa\` option instead***`); const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Creating certificate...***`); const hash = this.client.util.getAcctHash(account.homepath); -- 2.20.1 From 66d28e4e753474cc871f068a886e8e554bfe037f Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 20 Jan 2020 19:59:43 +0000 Subject: [PATCH 096/516] Fix --- src/commands/securesign_createcrt.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/securesign_createcrt.ts b/src/commands/securesign_createcrt.ts index 1128cf3..21cc1dc 100644 --- a/src/commands/securesign_createcrt.ts +++ b/src/commands/securesign_createcrt.ts @@ -24,7 +24,7 @@ export default class SecureSign_Init extends Command { if (options.s && options.s.toLowerCase() !== 'ecc' && options.s.toLowerCase() !== 'rsa') return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid signing type, choose between \`ecc\` or \`rsa\``); if (options.c && (!Number(options.c) || Number(options.c) < 1 || Number(options.c) > 3)) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid class selected, choose between Class \`1\`, \`2\` or \`3\``); if (options.m && (!Number(options.m) || (options.m !== '256' && options.m !== '384' && options.m !== '512'))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid SHA Digest selected, choose between \`256\`, \`384\` or \`512\``); - if (Number(options.c) === 3 && (!options.s || options.s === 'ecc')) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Class 3 ECC certificates are not supported, please use the \`-s rsa\` option instead***`); + if (Number(options.c) === 3 && (!options.s || options.s.toLowerCase() === 'ecc')) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Class 3 ECC certificates are not supported, please use the \`-s rsa\` option instead***`); const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Creating certificate...***`); const hash = this.client.util.getAcctHash(account.homepath); -- 2.20.1 From 4549da9ba354896d1bb955a83a2e615a52aaa418 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 20 Jan 2020 23:01:01 +0000 Subject: [PATCH 097/516] Better error handling --- src/functions/checkSS.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/functions/checkSS.ts b/src/functions/checkSS.ts index 3a8e75e..e6ed824 100644 --- a/src/functions/checkSS.ts +++ b/src/functions/checkSS.ts @@ -23,10 +23,14 @@ export default function checkSS(client: Client) { } } catch (error) { if (!hash) return; - const { status } = error.response; - if (status === 400 || status === 401 || status === 403 || status === 404) { - await client.db.Account.updateOne({ userID }, { $set: { hash: false } }); - client.getDMChannel(userID).then((channel) => channel.createMessage('Your SecureSign password has been reset - please reinitialize your SecureSign account. Run `=securesign init` for more information')).catch(); + try { + const { status } = error.response; + if (status === 400 || status === 401 || status === 403 || status === 404) { + await client.db.Account.updateOne({ userID }, { $set: { hash: false } }); + client.getDMChannel(userID).then((channel) => channel.createMessage('Your SecureSign password has been reset - please reinitialize your SecureSign account. Run `=securesign init` for more information')).catch(); + } + } catch (e) { + throw error; } } } -- 2.20.1 From f341f5364d0bac00e0a31e2abc64a4d885009954 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 20 Jan 2020 23:41:06 -0500 Subject: [PATCH 098/516] Security.keyBase changed to protected/readonly --- src/api/Security.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/Security.ts b/src/api/Security.ts index 2058619..2dc019f 100644 --- a/src/api/Security.ts +++ b/src/api/Security.ts @@ -7,7 +7,7 @@ import { AccountInterface } from '../models'; export default class Security { public client: Client; - private keyBase: { key: string, iv: string }; + protected readonly keyBase: { key: string, iv: string }; constructor(client: Client) { this.client = client; -- 2.20.1 From e6ec7801bb8450e0815b3dd89d5d56eb31917da3 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 20 Jan 2020 23:41:24 -0500 Subject: [PATCH 099/516] Route constructor changed to protected --- src/class/Route.ts | 58 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/src/class/Route.ts b/src/class/Route.ts index d15f936..d96e24b 100644 --- a/src/class/Route.ts +++ b/src/class/Route.ts @@ -9,7 +9,7 @@ export default class Route { public conf: { path: string, deprecated?: boolean, maintenance?: boolean }; - constructor(server: Server, conf: { path: string, deprecated?: boolean, maintenance?: boolean }) { + protected constructor(server: Server, conf: { path: string, deprecated?: boolean, maintenance?: boolean }) { this.server = server; this.router = router(); this.conf = conf; @@ -61,22 +61,76 @@ export default class Route { get constants() { return { codes: { + /** + * SUCCESS 100 + * Used if the request was processed successfully. + */ SUCCESS: 100, + /** + * UNAUTHORIZED 101 + * Used if the client calling the request couldn't be correctly authenticated. + */ UNAUTHORIZED: 101, - PERMISSION_DENIED: 104, + /** + * PERMISSION DENIED 103 + * Used if the client calling the request doesn't have access to the resource specified. + */ + PERMISSION_DENIED: 103, + /** + * NOT FOUND 104 + * Used if the resource the client requested doesn't exist. + */ NOT_FOUND: 104, + /** + * ACCOUNT NOT FOUND 1041 + * Used if the account specified by the client couldn't be found. + */ ACCOUNT_NOT_FOUND: 1041, + /** + * CLIENT ERROR 1044 + * Used in cases of user error. Examples are incorrect parameters, incorrect headers, or an invalid request. + */ CLIENT_ERROR: 1044, + /** + * SERVER ERROR 105 + * Used in cases of an internal error that caused the bind() function to throw. + */ SERVER_ERROR: 105, + /** + * DEPRECATED 1051 + * Returned back to the user if the resource requested is deprecated. + */ DEPRECATED: 1051, + /** + * MAINTENANCE OR UNAVAILABLE 1053 + * Used if the resource requested is currently in maintenance, not finished, or temporarily disabled. + */ MAINTENANCE_OR_UNAVAILABLE: 1053, }, messages: { + /** + * 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. + */ PERMISSION_DENIED: ['PERMISSION_DENIED', 'You do not have valid credentials to access this resource.'], + /** + * 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. + */ 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. + */ 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. + */ MAINTENANCE_OR_UNAVAILABLE: ['SERVICE_UNAVAILABLE', 'The endpoint or resource you\'re trying to access is either in maintenance or is not available.'], }, }; -- 2.20.1 From 715570992409bbb81196ec6bcf351f3c005933a5 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 25 Jan 2020 13:16:58 +0000 Subject: [PATCH 100/516] Fixes to options and caps --- src/commands/securesign_createcrt.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/securesign_createcrt.ts b/src/commands/securesign_createcrt.ts index 21cc1dc..80e5d8a 100644 --- a/src/commands/securesign_createcrt.ts +++ b/src/commands/securesign_createcrt.ts @@ -20,13 +20,14 @@ export default class SecureSign_Init extends Command { if (!account.hash) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not initialized***`); // @ts-ignore - const options: { s?: string, c?: string, m?: string } = args.length ? Object.fromEntries(` ${args.join(' ')}`.split(' -').filter((a) => a).map((a) => a.split(' '))) : {}; // eslint-disable-line + const options: { s?: string, c?: string, m?: string } = args.length ? Object.fromEntries(` ${args.join(' ')}`.split(' -').filter((a) => a).map((a) => a.split(/ (.+)/)).filter((a) => a.length > 1)) : {}; if (options.s && options.s.toLowerCase() !== 'ecc' && options.s.toLowerCase() !== 'rsa') return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid signing type, choose between \`ecc\` or \`rsa\``); if (options.c && (!Number(options.c) || Number(options.c) < 1 || Number(options.c) > 3)) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid class selected, choose between Class \`1\`, \`2\` or \`3\``); if (options.m && (!Number(options.m) || (options.m !== '256' && options.m !== '384' && options.m !== '512'))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid SHA Digest selected, choose between \`256\`, \`384\` or \`512\``); if (Number(options.c) === 3 && (!options.s || options.s.toLowerCase() === 'ecc')) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Class 3 ECC certificates are not supported, please use the \`-s rsa\` option instead***`); const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Creating certificate...***`); + if (options.s) options.s = options.s.toLowerCase(); const hash = this.client.util.getAcctHash(account.homepath); // Check if they can generate certificate -- 2.20.1 From 87fd47adce08a7a8d5d764c52fdadb6ee395adae Mon Sep 17 00:00:00 2001 From: Bsian Date: Fri, 13 Mar 2020 21:49:51 +0000 Subject: [PATCH 101/516] Rework command --- src/class/RichEmbed.ts | 352 ++++++++++++------------- src/class/Util.ts | 511 +++++++++++++++++++------------------ src/commands/cwg_create.ts | 374 ++++++++++++++++----------- types/eris.d.ts | 8 + 4 files changed, 669 insertions(+), 576 deletions(-) create mode 100644 types/eris.d.ts diff --git a/src/class/RichEmbed.ts b/src/class/RichEmbed.ts index 49d798d..678cccd 100644 --- a/src/class/RichEmbed.ts +++ b/src/class/RichEmbed.ts @@ -1,176 +1,176 @@ -/* 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 `.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; - } -} +/* 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 `.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; + } +} diff --git a/src/class/Util.ts b/src/class/Util.ts index 0bbf3c5..22f7b5a 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -1,253 +1,258 @@ -/* eslint-disable no-param-reassign */ -import { promisify } from 'util'; -import childProcess from 'child_process'; -import nodemailer from 'nodemailer'; -import { Message, PrivateChannel, GroupChannel, Member, User } from 'eris'; -import uuid from 'uuid/v4'; -import moment from 'moment'; -import fs from 'fs'; -import os from 'os'; -import { Client } from '..'; -import { Command, RichEmbed } from '.'; -import { ModerationInterface, AccountInterface } from '../models'; - -export default class Util { - public client: Client; - - public transport: nodemailer.Transporter; - - constructor(client: Client) { - this.client = client; - this.transport = nodemailer.createTransport({ - host: 'staff.libraryofcode.org', - auth: { user: 'support', pass: this.client.config.emailPass }, - }); - } - - /** - * Executes a terminal command async. - * @param command The command to execute - * @param options childProcess.ExecOptions - */ - public async exec(command: string, options: childProcess.ExecOptions = {}): Promise { - const ex = promisify(childProcess.exec); - let result: string; - try { - const res = await ex(command, options); - result = `${res.stdout}${res.stderr}`; - } catch (err) { - return Promise.reject(new Error(`Command failed: ${err.cmd}\n${err.stderr}${err.stdout}`)); - } - return result; - } - - /** - * Resolves a command - * @param query Command input - * @param message Only used to check for errors - */ - public resolveCommand(query: string | string[], message?: Message): Promise<{cmd: Command, args: string[] }> { - try { - let resolvedCommand: Command; - if (typeof query === 'string') query = query.split(' '); - const commands = this.client.commands.toArray(); - resolvedCommand = commands.find((c) => c.name === query[0].toLowerCase() || c.aliases.includes(query[0].toLowerCase())); - - if (!resolvedCommand) return Promise.resolve(null); - query.shift(); - while (resolvedCommand.subcommands.size && query.length) { - const subCommands = resolvedCommand.subcommands.toArray(); - const found = subCommands.find((c) => c.name === query[0].toLowerCase() || c.aliases.includes(query[0].toLowerCase())); - if (!found) break; - resolvedCommand = found; - query.shift(); - } - return Promise.resolve({ cmd: resolvedCommand, args: query }); - } catch (error) { - if (message) this.handleError(error, message); - else this.handleError(error); - return Promise.reject(error); - } - } - - public async handleError(error: Error, message?: Message, command?: Command): Promise { - try { - this.client.signale.error(error); - const info = { content: `\`\`\`js\n${error.stack}\n\`\`\``, embed: null }; - if (message) { - const embed = new RichEmbed(); - embed.setColor('FF0000'); - embed.setAuthor(`Error caused by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL); - embed.setTitle('Message content'); - embed.setDescription(message.content); - embed.addField('User', `${message.author.mention} (\`${message.author.id}\`)`, true); - embed.addField('Channel', message.channel.mention, true); - let guild: string; - if (message.channel instanceof PrivateChannel || message.channel instanceof GroupChannel) guild = '@me'; - else guild = message.channel.guild.id; - embed.addField('Message link', `[Click here](https://discordapp.com/channels/${guild}/${message.channel.id}/${message.id})`, true); - embed.setTimestamp(new Date(message.timestamp)); - info.embed = embed; - } - await this.client.createMessage('595788220764127272', info); - 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 (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.' : ''}***`); - } catch (err) { - this.client.signale.error(err); - } - } - - public splitFields(fields: { name: string, value: string, inline?: boolean }[]): { name: string, value: string, inline?: boolean }[][] { - let index = 0; - const array: {name: string, value: string, inline?: boolean}[][] = [[]]; - while (fields.length) { - if (array[index].length >= 25) { index += 1; array[index] = []; } - array[index].push(fields[0]); fields.shift(); - } - return array; - } - - public splitString(string: string, length: number): string[] { - if (!string) return []; - if (Array.isArray(string)) string = string.join('\n'); - if (string.length <= length) return [string]; - const arrayString: string[] = []; - let str: string = ''; - let pos: number; - while (string.length > 0) { - pos = string.length > length ? string.lastIndexOf('\n', length) : string.length; - if (pos > length) pos = length; - str = string.substr(0, pos); - string = string.substr(pos); - arrayString.push(str); - } - return arrayString; - } - - - public async createHash(password: string): Promise { - const hashed = await this.exec(`mkpasswd -m sha-512 "${password}"`); - return hashed; - } - - public isValidEmail(email: string): boolean { - const checkAt = email.indexOf('@'); - if (checkAt < 1) return false; - const checkDomain = email.indexOf('.', checkAt + 2); - if (checkDomain < checkAt) return false; - return true; - } - - public randomPassword(): string { - let tempPass = ''; const passChars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0']; - while (tempPass.length < 5) { tempPass += passChars[Math.floor(Math.random() * passChars.length)]; } - return tempPass; - } - - public async createAccount(hash: string, etcPasswd: string, username: string, userID: string, emailAddress: string, moderatorID: string): Promise { - await this.exec(`useradd -m -p ${hash} -c ${etcPasswd} -s /bin/zsh ${username}`); - await this.exec(`chage -d0 ${username}`); - - const account = new this.client.db.Account({ - username, userID, emailAddress, createdBy: moderatorID, createdAt: new Date(), locked: false, ssInit: false, homepath: `/home/${username}`, - }); - return account.save(); - } - - public async deleteAccount(username: string): Promise { - const account = await this.client.db.Account.findOne({ username }); - if (!account) throw new Error('Account not found'); - this.exec(`lock ${username}`); - const tasks = [ - this.exec(`deluser ${username} --remove-home --backup-to /management/Archives && rm -rf -R ${account.homepath}`), - this.client.db.Account.deleteOne({ username }), - ]; - this.client.removeGuildMemberRole('446067825673633794', account.userID, '546457886440685578', 'Cloud Account Deleted').catch(); - // @ts-ignore - await Promise.all(tasks); - } - - public async messageCollector(message: Message, question: string, timeout: number, shouldDelete = false, choices: string[] = null, filter = (msg: Message): boolean|void => {}): Promise { - const msg = await message.channel.createMessage(question); - return new Promise((res, rej) => { - setTimeout(() => { if (shouldDelete) msg.delete().catch(); rej(new Error('Did not supply a valid input in time')); }, timeout); - this.client.on('messageCreate', (Msg) => { - if (filter(Msg) === false) return; - const verif = choices ? choices.includes(Msg.content) : Msg.content; - if (verif) { if (shouldDelete) msg.delete().catch(); res(Msg); } - }); - }); - } - - /** - * @param type `0` - Create - * - * `1` - Warn - * - * `2` - Lock - * - * `3` - Unlock - * - * `4` - Delete - */ - public async createModerationLog(user: string, moderator: Member|User, type: number, reason?: string, duration?: number): Promise { - const moderatorID = moderator.id; - const account = await this.client.db.Account.findOne({ $or: [{ username: user }, { userID: user }] }); - if (!account) return Promise.reject(new Error(`Account ${user} not found`)); - const { username, userID } = account; - const logInput: { username: string, userID: string, logID: string, moderatorID: string, reason?: string, type: number, date: Date, expiration?: { date: Date, processed: boolean }} = { - username, userID, logID: uuid(), moderatorID, type, date: new Date(), - }; - - const now: number = Date.now(); - let date: Date; - let processed = true; - if (reason) logInput.reason = reason; - if (type === 2) { - if (duration) { - date = new Date(now + duration); - processed = false; - } else date = null; - } - - const expiration = { date, processed }; - - logInput.expiration = expiration; - const log = new this.client.db.Moderation(logInput); - await log.save(); - - let embedTitle: string; - let color: string; - let archType: string; - switch (type) { - default: archType = 'Staff'; embedTitle = 'Cloud Account | Generic'; color = '0892e1'; break; - case 0: archType = 'Administrator'; embedTitle = 'Cloud Account | Create'; color = '00ff00'; break; - case 1: archType = 'Staff'; embedTitle = 'Account Warning | Warn'; color = 'ffff00'; break; - case 2: archType = 'Moderator'; embedTitle = 'Account Infraction | Lock'; color = 'ff6600'; break; - case 3: archType = 'Moderator'; embedTitle = 'Account Reclaim | Unlock'; color = '0099ff'; break; - case 4: archType = 'Administrator'; embedTitle = 'Cloud Account | Delete'; color = 'ff0000'; break; - } - const embed = new RichEmbed() - .setTitle(embedTitle) - .setColor(color) - .addField('User', `${username} | <@${userID}>`, true) - .addField(archType, moderatorID === this.client.user.id ? 'SYSTEM' : `<@${moderatorID}>`, true) - .setFooter(this.client.user.username, this.client.user.avatarURL) - .setTimestamp(); - 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'}`); - // @ts-ignore - this.client.createMessage('580950455581147146', { embed }); this.client.getDMChannel(userID).then((channel) => channel.createMessage({ embed })).catch(); - - return Promise.resolve(log); - } - - public getAcctHash(userpath: string) { - try { - return fs.readFileSync(`${userpath}/.securesign/auth`).toString(); - } catch (error) { - return null; - } - } -} +/* eslint-disable no-param-reassign */ +import { promisify } from 'util'; +import childProcess from 'child_process'; +import nodemailer from 'nodemailer'; +import { Message, PrivateChannel, GroupChannel, Member, User } from 'eris'; +import uuid from 'uuid/v4'; +import moment from 'moment'; +import fs from 'fs'; +import os from 'os'; +import { Client } from '..'; +import { Command, RichEmbed } from '.'; +import { ModerationInterface, AccountInterface } from '../models'; + +export default class Util { + public client: Client; + + public transport: nodemailer.Transporter; + + constructor(client: Client) { + this.client = client; + this.transport = nodemailer.createTransport({ + host: 'staff.libraryofcode.org', + auth: { user: 'support', pass: this.client.config.emailPass }, + }); + } + + /** + * Executes a terminal command async. + * @param command The command to execute + * @param options childProcess.ExecOptions + */ + public async exec(command: string, options: childProcess.ExecOptions = {}): Promise { + const ex = promisify(childProcess.exec); + let result: string; + try { + const res = await ex(command, options); + result = `${res.stdout}${res.stderr}`; + } catch (err) { + return Promise.reject(new Error(`Command failed: ${err.cmd}\n${err.stderr}${err.stdout}`)); + } + return result; + } + + /** + * Resolves a command + * @param query Command input + * @param message Only used to check for errors + */ + public resolveCommand(query: string | string[], message?: Message): Promise<{cmd: Command, args: string[] }> { + try { + let resolvedCommand: Command; + if (typeof query === 'string') query = query.split(' '); + const commands = this.client.commands.toArray(); + resolvedCommand = commands.find((c) => c.name === query[0].toLowerCase() || c.aliases.includes(query[0].toLowerCase())); + + if (!resolvedCommand) return Promise.resolve(null); + query.shift(); + while (resolvedCommand.subcommands.size && query.length) { + const subCommands = resolvedCommand.subcommands.toArray(); + const found = subCommands.find((c) => c.name === query[0].toLowerCase() || c.aliases.includes(query[0].toLowerCase())); + if (!found) break; + resolvedCommand = found; + query.shift(); + } + return Promise.resolve({ cmd: resolvedCommand, args: query }); + } catch (error) { + if (message) this.handleError(error, message); + else this.handleError(error); + return Promise.reject(error); + } + } + + public async handleError(error: Error, message?: Message, command?: Command): Promise { + try { + this.client.signale.error(error); + const info = { content: `\`\`\`js\n${error.stack}\n\`\`\``, embed: null }; + if (message) { + const embed = new RichEmbed(); + embed.setColor('FF0000'); + embed.setAuthor(`Error caused by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL); + embed.setTitle('Message content'); + embed.setDescription(message.content); + embed.addField('User', `${message.author.mention} (\`${message.author.id}\`)`, true); + embed.addField('Channel', message.channel.mention, true); + let guild: string; + if (message.channel instanceof PrivateChannel || message.channel instanceof GroupChannel) guild = '@me'; + else guild = message.channel.guild.id; + embed.addField('Message link', `[Click here](https://discordapp.com/channels/${guild}/${message.channel.id}/${message.id})`, true); + embed.setTimestamp(new Date(message.timestamp)); + info.embed = embed; + } + await this.client.createMessage('595788220764127272', info); + 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 (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.' : ''}***`); + } catch (err) { + this.client.signale.error(err); + } + } + + public splitFields(fields: { name: string, value: string, inline?: boolean }[]): { name: string, value: string, inline?: boolean }[][] { + let index = 0; + const array: {name: string, value: string, inline?: boolean}[][] = [[]]; + while (fields.length) { + if (array[index].length >= 25) { index += 1; array[index] = []; } + array[index].push(fields[0]); fields.shift(); + } + return array; + } + + public splitString(string: string, length: number): string[] { + if (!string) return []; + if (Array.isArray(string)) string = string.join('\n'); + if (string.length <= length) return [string]; + const arrayString: string[] = []; + let str: string = ''; + let pos: number; + while (string.length > 0) { + pos = string.length > length ? string.lastIndexOf('\n', length) : string.length; + if (pos > length) pos = length; + str = string.substr(0, pos); + string = string.substr(pos); + arrayString.push(str); + } + return arrayString; + } + + + public async createHash(password: string): Promise { + const hashed = await this.exec(`mkpasswd -m sha-512 "${password}"`); + return hashed; + } + + public isValidEmail(email: string): boolean { + const checkAt = email.indexOf('@'); + if (checkAt < 1) return false; + const checkDomain = email.indexOf('.', checkAt + 2); + if (checkDomain < checkAt) return false; + return true; + } + + public randomPassword(): string { + let tempPass = ''; const passChars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0']; + while (tempPass.length < 5) { tempPass += passChars[Math.floor(Math.random() * passChars.length)]; } + return tempPass; + } + + public async createAccount(hash: string, etcPasswd: string, username: string, userID: string, emailAddress: string, moderatorID: string): Promise { + await this.exec(`useradd -m -p ${hash} -c ${etcPasswd} -s /bin/zsh ${username}`); + await this.exec(`chage -d0 ${username}`); + + const account = new this.client.db.Account({ + username, userID, emailAddress, createdBy: moderatorID, createdAt: new Date(), locked: false, ssInit: false, homepath: `/home/${username}`, + }); + return account.save(); + } + + public async deleteAccount(username: string): Promise { + const account = await this.client.db.Account.findOne({ username }); + if (!account) throw new Error('Account not found'); + this.exec(`lock ${username}`); + const tasks = [ + this.exec(`deluser ${username} --remove-home --backup-to /management/Archives && rm -rf -R ${account.homepath}`), + this.client.db.Account.deleteOne({ username }), + ]; + this.client.removeGuildMemberRole('446067825673633794', account.userID, '546457886440685578', 'Cloud Account Deleted').catch(); + // @ts-ignore + await Promise.all(tasks); + } + + public async messageCollector(message: Message, question: string, timeout: number, shouldDelete = false, choices: string[] = null, filter = (msg: Message): boolean|void => {}): Promise { + const msg = await message.channel.createMessage(question); + return new Promise((res, rej) => { + const func = (Msg: Message) => { + if (filter(Msg) === false) return; + const verif = choices ? choices.includes(Msg.content) : Msg.content; + if (verif) { if (shouldDelete) msg.delete().catch(); res(Msg); } + }; + + setTimeout(() => { + if (shouldDelete) msg.delete().catch(); rej(new Error('Did not supply a valid input in time')); + this.client.removeListener('messageCreate', func); + }, timeout); + this.client.on('messageCreate', func); + }); + } + + /** + * @param type `0` - Create + * + * `1` - Warn + * + * `2` - Lock + * + * `3` - Unlock + * + * `4` - Delete + */ + public async createModerationLog(user: string, moderator: Member|User, type: number, reason?: string, duration?: number): Promise { + const moderatorID = moderator.id; + const account = await this.client.db.Account.findOne({ $or: [{ username: user }, { userID: user }] }); + if (!account) return Promise.reject(new Error(`Account ${user} not found`)); + const { username, userID } = account; + const logInput: { username: string, userID: string, logID: string, moderatorID: string, reason?: string, type: number, date: Date, expiration?: { date: Date, processed: boolean }} = { + username, userID, logID: uuid(), moderatorID, type, date: new Date(), + }; + + const now: number = Date.now(); + let date: Date; + let processed = true; + if (reason) logInput.reason = reason; + if (type === 2) { + if (duration) { + date = new Date(now + duration); + processed = false; + } else date = null; + } + + const expiration = { date, processed }; + + logInput.expiration = expiration; + const log = new this.client.db.Moderation(logInput); + await log.save(); + + let embedTitle: string; + let color: string; + let archType: string; + switch (type) { + default: archType = 'Staff'; embedTitle = 'Cloud Account | Generic'; color = '0892e1'; break; + case 0: archType = 'Administrator'; embedTitle = 'Cloud Account | Create'; color = '00ff00'; break; + case 1: archType = 'Staff'; embedTitle = 'Account Warning | Warn'; color = 'ffff00'; break; + case 2: archType = 'Moderator'; embedTitle = 'Account Infraction | Lock'; color = 'ff6600'; break; + case 3: archType = 'Moderator'; embedTitle = 'Account Reclaim | Unlock'; color = '0099ff'; break; + case 4: archType = 'Administrator'; embedTitle = 'Cloud Account | Delete'; color = 'ff0000'; break; + } + const embed = new RichEmbed() + .setTitle(embedTitle) + .setColor(color) + .addField('User', `${username} | <@${userID}>`, true) + .addField(archType, moderatorID === this.client.user.id ? 'SYSTEM' : `<@${moderatorID}>`, true) + .setFooter(this.client.user.username, this.client.user.avatarURL) + .setTimestamp(); + 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'}`); + // @ts-ignore + this.client.createMessage('580950455581147146', { embed }); this.client.getDMChannel(userID).then((channel) => channel.createMessage({ embed })).catch(); + + return Promise.resolve(log); + } + + public getAcctHash(userpath: string) { + try { + return fs.readFileSync(`${userpath}/.securesign/auth`).toString(); + } catch (error) { + return null; + } + } +} diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index 7ac1ee0..fa738af 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -1,147 +1,227 @@ -import fs from 'fs-extra'; -import axios from 'axios'; -import x509 from '@ghaiklor/x509'; -import { Message } from 'eris'; -import { AccountInterface } from '../models'; -import { Command, RichEmbed } from '../class'; -import { Client } from '..'; - -export default class CWG_Create extends Command { - constructor(client: Client) { - super(client); - this.name = 'create'; - this.description = 'Bind a domain to the CWG'; - this.usage = `${this.client.config.prefix}cwg create [User ID | Username] [Domain] [Port] `; - this.permissions = { roles: ['525441307037007902'] }; - this.aliases = ['bind']; - this.enabled = true; - } - - public async run(message: Message, args: string[]) { - /* - args[0] should be the user's ID OR account username; required - args[1] should be the domain; required - args[2] should be the port; required - args[3] should be the path to the x509 certificate; not required - args[4] should be the path to the x509 key; not required - */ - try { - if (!args[2]) return this.client.commands.get('help').run(message, ['cwg', this.name]); - const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Binding domain...***`); - const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }] }); - if (!account) return edit.edit(`${this.client.stores.emojis.error} Cannot locate account, please try again.`); - if (args[3] && !args[4]) return edit.edit(`${this.client.stores.emojis.error} x509 Certificate key required`); - let certs: { cert?: string, key?: string }; if (args[4]) certs = { cert: args[3], key: args[4] }; - if (await this.client.db.Domain.exists({ domain: args[1] })) return edit.edit(`***${this.client.stores.emojis.error} This domain already exists.***`); - if (await this.client.db.Domain.exists({ port: Number(args[2]) })) { - // await edit.edit(`***${this.client.stores.emojis.error} This port is already binded to a domain. Do you wish to continue? (y/n)***`); - let answer: Message; - try { - answer = await this.client.util.messageCollector(message, - `***${this.client.stores.emojis.error} This port is already binded 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); - } catch (error) { - return edit.edit(`***${this.client.stores.emojis.error} Bind request cancelled***`); - } - if (answer.content === 'n') return edit.edit(`***${this.client.stores.emojis.error} Bind request cancelled***`); - } - const domain = await this.createDomain(account, args[1], Number(args[2]), certs); - const embed = new RichEmbed(); - embed.setTitle('Domain Creation'); - embed.setColor(3066993); - embed.addField('Account Username', account.username, true); - embed.addField('Account ID', account.id, true); - embed.addField('Engineer', `<@${message.author.id}>`, true); - embed.addField('Domain', domain.domain, true); - embed.addField('Port', String(domain.port), true); - const cert = x509.parseCert(await fs.readFile(domain.x509.cert, { encoding: 'utf8' })); - embed.addField('Certificate Issuer', cert.issuer.organizationName, true); - embed.addField('Certificate Subject', cert.subject.commonName, true); - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - embed.setTimestamp(new Date(message.timestamp)); - message.delete(); - await this.client.util.exec('systemctl reload nginx'); - edit.edit(`***${this.client.stores.emojis.success} Successfully binded ${domain.domain} to port ${domain.port} for ${account.userID}.***`); - // @ts-ignore - this.client.createMessage('580950455581147146', { embed }); - // @ts-ignore - this.client.getDMChannel(account.userID).then((r) => r.createMessage({ embed })); - await this.client.util.transport.sendMail({ - to: account.emailAddress, - from: 'Library of Code sp-us | Support Team ', - subject: 'Your domain has been binded', - html: ` -

Library of Code sp-us | Cloud Services

-

Hello, this is an email informing you that a new domain under your account has been binded. - Information is below.

- Domain: ${domain.domain}
- Port: ${domain.port}
- Certificate Issuer: ${cert.issuer.organizationName}
- Certificate Subject: ${cert.subject.commonName}
- Responsible Engineer: ${message.author.username}#${message.author.discriminator}

- - 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.
- - Library of Code sp-us | Support Team - `, - }); - 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.`; - this.client.getDMChannel(account.userID).then((r) => r.createMessage(content)); - } - return domain; - } catch (err) { - await fs.unlink(`/etc/nginx/sites-available/${args[1]}`); - await fs.unlink(`/etc/nginx/sites-enabled/${args[1]}`); - await this.client.db.Domain.deleteMany({ domain: args[1] }); - return this.client.util.handleError(err, message, this); - } - } - - /** - * This function binds a domain to a port on the CWG. - * @param account The account of the user. - * @param subdomain The domain to use. `mydomain.cloud.libraryofcode.org` - * @param port The port to use, must be between 1024 and 65535. - * @param x509 The paths to the certificate and key files. Must be already existant. - * @example await CWG.createDomain('mydomain.cloud.libraryofcode.org', 6781); - */ - public async createDomain(account: AccountInterface, domain: string, port: number, x509Certificate: { cert?: string, key?: string } = { cert: '/etc/nginx/ssl/cloud-org.chain.crt', key: '/etc/nginx/ssl/cloud-org.key.pem' }) { - try { - if (port <= 1024 || port >= 65535) throw new RangeError(`Port range must be between 1024 and 65535, received ${port}.`); - if (await this.client.db.Domain.exists({ domain })) throw new Error(`Domain ${domain} already exists in the database.`); - if (!await this.client.db.Account.exists({ userID: account.userID })) throw new Error(`Cannot find account ${account.userID}.`); - await fs.access(x509Certificate.cert, fs.constants.R_OK); - await fs.access(x509Certificate.key, fs.constants.R_OK); - let cfg = await fs.readFile('/var/CloudServices/dist/static/nginx.conf', { encoding: 'utf8' }); - cfg = cfg.replace(/\[DOMAIN]/g, domain); - cfg = cfg.replace(/\[PORT]/g, String(port)); - cfg = cfg.replace(/\[CERTIFICATE]/g, x509Certificate.cert); - cfg = cfg.replace(/\[KEY]/g, x509Certificate.key); - await fs.writeFile(`/etc/nginx/sites-available/${domain}`, cfg, { encoding: 'utf8' }); - await fs.symlink(`/etc/nginx/sites-available/${domain}`, `/etc/nginx/sites-enabled/${domain}`); - const entry = new this.client.db.Domain({ - account, - domain, - port, - x509: x509Certificate, - enabled: true, - }); - if (domain.includes('cloud.libraryofcode.org')) { - const dmn = domain.split('.'); - await axios({ - method: 'post', - url: 'https://api.cloudflare.com/client/v4/zones/5e82fc3111ed4fbf9f58caa34f7553a7/dns_records', - headers: { Authorization: `Bearer ${this.client.config.cloudflare}`, 'Content-Type': 'application/json' }, - data: JSON.stringify({ type: 'CNAME', name: `${dmn[0]}.${dmn[1]}`, content: 'cloud.libraryofcode.org', proxied: false }), - }); - } - return entry.save(); - } catch (error) { - await fs.unlink(`/etc/nginx/sites-enabled/${domain}`); - await fs.unlink(`/etc/nginx/sites-available/${domain}`); - await this.client.db.Domain.deleteMany({ domain }); - throw error; - } - } -} +import fs, { writeFile, unlink } from 'fs-extra'; +import axios from 'axios'; +import { Message } from 'eris'; +import { AccountInterface } from '../models'; +import { Command, RichEmbed } from '../class'; +import { Client } from '..'; +import { parseCertificate } from '../functions'; + +export default class CWG_Create extends Command { + public urlRegex: RegExp; + + constructor(client: Client) { + super(client); + this.name = 'create'; + this.description = 'Bind a domain to the CWG'; + this.usage = `${this.client.config.prefix}cwg create [User ID | Username] [Domain] [Port] || Use snippets raw URL`; + this.permissions = { roles: ['525441307037007902'] }; + this.aliases = ['bind']; + this.enabled = true; + this.urlRegex = /^[a-zA-Z0-9\-._~:/?#[\]@!$&'()*+,;=]+$/; + } + + public async run(message: Message, args: string[]) { + /* + args[0] should be the user's ID OR account username; required + args[1] should be the domain; required + args[2] should be the port; required + args[3] should be the path to the x509 certificate; not required + args[4] should be the path to the x509 key; not required + */ + try { + if (!args[2]) return this.client.commands.get('help').run(message, ['cwg', this.name]); + + let certs: { cert: string, key: string }; + + if (!this.urlRegex.test(args[1])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid URL***`); + if (Number(args[2]) < 1024 || Number(args[2]) > 65535) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Port must be greater than 1024 and less than 65535***`); + if (!args[1].endsWith('.cloud.libraryofcode.org') && !args[4]) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Certificate Chain and Private Key are required for custom domains***`); + + const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }] }); + if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} Cannot locate account, please try again.`); + + if (await this.client.db.Domain.exists({ domain: args[1] })) return message.channel.createMessage(`${this.client.stores.emojis.error} ***This domain already exists***`); + + if (await this.client.db.Domain.exists({ port: Number(args[2]) })) { + let answer: Message; + try { + answer = await this.client.util.messageCollector( + message, + `***${this.client.stores.emojis.error} ***This port is already binded 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, + ); + } catch (error) { + return message.channel.createMessage(`${this.client.stores.emojis.error} ***Bind request cancelled***`); + } + if (answer.content === 'n') return message.channel.createMessage(`${this.client.stores.emojis.error} ***Bind request cancelled***`); + } + + const edit = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Binding domain...***`); + + if (!args[1].endsWith('.cloud.libraryofcode.org')) { + const urls = args.slice(3, 5); + if (urls.some((l) => !l.includes('snippets.cloud.libraryofcode.org/raw/'))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid snippets URL***`); + + const tasks = urls.map((l) => axios({ method: 'GET', url: l })); + const response = await Promise.all(tasks); + const certAndPrivateKey: string[] = response.map((r) => r.data); + + if (!this.isValidCertificateChain(certAndPrivateKey[0])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid Certificate Chain***`); + if (!this.isValidPrivateKey(certAndPrivateKey[1])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid Private Key***`); + + certs = { cert: certAndPrivateKey[0], key: certAndPrivateKey[1] }; + } + + const domain = await this.createDomain(account, args[1], Number(args[2]), certs); + + const tasks = [message.delete(), this.client.util.exec('systemctl reload')]; + // @ts-ignore + await Promise.all(tasks); + + const embed = new RichEmbed() + .setTitle('Domain Creation') + .setColor(3066993) + .addField('Account Username', account.username, true) + .addField('Account ID', account.id, true) + .addField('Engineer', `<@${message.author.id}>`, true) + .addField('Domain', domain.domain, true) + .addField('Port', String(domain.port), true); + + const cert = await parseCertificate(this.client, domain.x509.cert); + + embed.addField('Certificate Issuer', cert.issuer.organizationName, true) + .addField('Certificate Subject', cert.subject.commonName, true) + .setFooter(this.client.user.username, this.client.user.avatarURL) + .setTimestamp(new Date(message.timestamp)); + + const completed = [ + edit.edit(`***${this.client.stores.emojis.success} Successfully binded ${domain.domain} to port ${domain.port} for ${account.userID}.***`), + this.client.createMessage('580950455581147146', { embed }), + this.client.getDMChannel(account.userID).then((r) => r.createMessage({ embed })), + this.client.util.transport.sendMail({ + to: account.emailAddress, + from: 'Library of Code sp-us | Support Team ', + subject: 'Your domain has been binded', + html: ` +

Library of Code sp-us | Cloud Services

+

Hello, this is an email informing you that a new domain under your account has been binded. + Information is below.

+ Domain: ${domain.domain}
+ Port: ${domain.port}
+ Certificate Issuer: ${cert.issuer.organizationName}
+ Certificate Subject: ${cert.subject.commonName}
+ Responsible Engineer: ${message.author.username}#${message.author.discriminator}

+ + 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.
+ + Library of Code sp-us | Support Team + `, + }), + ]; + + 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.`; + completed.push(this.client.getDMChannel(account.userID).then((r) => r.createMessage(content))); + } + + return Promise.all(completed); + } catch (err) { + await fs.unlink(`/etc/nginx/sites-available/${args[1]}`); + await fs.unlink(`/etc/nginx/sites-enabled/${args[1]}`); + await this.client.db.Domain.deleteMany({ domain: args[1] }); + return this.client.util.handleError(err, message, this); + } + } + + /** + * This function binds a domain to a port on the CWG. + * @param account The account of the user. + * @param subdomain The domain to use. `mydomain.cloud.libraryofcode.org` + * @param port The port to use, must be between 1024 and 65535. + * @param x509Certificate The contents the certificate and key files. + * @example await CWG.createDomain(account, 'mydomain.cloud.libraryofcode.org', 6781); + */ + public async createDomain(account: AccountInterface, domain: string, port: number, x509Certificate: { cert?: string, key?: string }) { + try { + if (port <= 1024 || port >= 65535) throw new RangeError(`Port range must be between 1024 and 65535, received ${port}.`); + if (await this.client.db.Domain.exists({ domain })) throw new Error(`Domain ${domain} already exists in the database.`); + if (!await this.client.db.Account.exists({ userID: account.userID })) throw new Error(`Cannot find account ${account.userID}.`); + let x509: { cert: string, key: string }; + if (x509Certificate) { + x509 = await this.createCertAndPrivateKey(domain, x509Certificate.cert, x509Certificate.key); + } + let cfg = await fs.readFile('/var/CloudServices/dist/static/nginx.conf', { encoding: 'utf8' }); + cfg = cfg.replace(/\[DOMAIN]/g, domain); + cfg = cfg.replace(/\[PORT]/g, String(port)); + cfg = cfg.replace(/\[CERTIFICATE]/g, x509.cert); + cfg = cfg.replace(/\[KEY]/g, x509.key); + await fs.writeFile(`/etc/nginx/sites-available/${domain}`, cfg, { encoding: 'utf8' }); + await fs.symlink(`/etc/nginx/sites-available/${domain}`, `/etc/nginx/sites-enabled/${domain}`); + const entry = new this.client.db.Domain({ + account, + domain, + port, + x509, + enabled: true, + }); + if (domain.includes('cloud.libraryofcode.org')) { + const dmn = domain.split('.'); + await axios({ + method: 'post', + url: 'https://api.cloudflare.com/client/v4/zones/5e82fc3111ed4fbf9f58caa34f7553a7/dns_records', + headers: { Authorization: `Bearer ${this.client.config.cloudflare}`, 'Content-Type': 'application/json' }, + data: JSON.stringify({ type: 'CNAME', name: `${dmn[0]}.${dmn[1]}`, content: 'cloud.libraryofcode.org', proxied: false }), + }); + } + return entry.save(); + } catch (error) { + await fs.unlink(`/etc/nginx/sites-enabled/${domain}`); + await fs.unlink(`/etc/nginx/sites-available/${domain}`); + await this.client.db.Domain.deleteMany({ domain }); + throw error; + } + } + + public async createCertAndPrivateKey(domain: string, certChain: string, privateKey: string) { + if (!this.isValidCertificateChain(certChain)) throw new Error('Invalid Certificate Chain'); + if (!this.isValidPrivateKey(privateKey)) throw new Error('Invalid Private Key'); + const path = `/var/CloudServices/temp/${domain}`; + const temp = [writeFile(`${path}.chain.crt`, certChain), writeFile(`${path}.key.pem`, privateKey)]; + const removeFiles = [unlink(`${path}.chain.crt`), unlink(`${path}.key.pem`)]; + await Promise.all(temp); + if (!this.isMatchingPair(`${path}.chain.crt`, `${path}.key.pem`)) { + await Promise.all(removeFiles); + throw new Error('Certificate and Private Key do not match'); + } + + const tasks = [writeFile(`/etc/nginx/ssl/${domain}.chain.crt`, certChain), writeFile(`/etc/nginx/ssl/${domain}.key.pem`, privateKey)]; + await Promise.all(tasks); + return { cert: `/etc/nginx/ssl/${domain}.chain.crt`, key: `/etc/nginx/ssl/${domain}.key.pem` }; + } + + public checkOccurance(text: string, query: string) { + return (text.match(new RegExp(query, 'g')) || []).length; + } + + public isValidCertificateChain(cert: string) { + if (!cert.replace(/^\s+|\s+$/g, '').startsWith('-----BEGIN 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.checkOccurance(cert.replace(/^\s+|\s+$/g, ''), '-----END CERTIFICATE-----') !== 2) return false; + return true; + } + + public isValidPrivateKey(key: string) { + 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 (this.checkOccurance(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; + return true; + } + + public async isMatchingPair(cert: string, privateKey: string) { + const result: string = await this.client.util.exec(`${__dirname}/../bin/checkCertSignatures ${cert} ${privateKey}`); + const { ok }: { ok: boolean } = JSON.parse(result); + return ok; + } +} diff --git a/types/eris.d.ts b/types/eris.d.ts new file mode 100644 index 0000000..e9a3c05 --- /dev/null +++ b/types/eris.d.ts @@ -0,0 +1,8 @@ +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 }; + } +} -- 2.20.1 From 6903b3f304e709cfd4169700557bd68c1246d264 Mon Sep 17 00:00:00 2001 From: Bsian Date: Fri, 13 Mar 2020 23:57:16 +0000 Subject: [PATCH 102/516] Got rid of as many errors as possible --- package.json | 95 +++++---- src/class/Collection.ts | 308 +++++++++++++-------------- src/class/Util.ts | 1 - src/commands/cwg_data.ts | 114 +++++----- src/commands/cwg_delete.ts | 124 ++++++----- src/commands/disk.ts | 88 ++++---- src/commands/help.ts | 137 ++++++------ src/commands/lock.ts | 109 +++++----- src/commands/modlogs.ts | 133 ++++++------ src/commands/notify.ts | 104 +++++---- src/commands/parse.ts | 139 ++++++------ src/commands/parseall.ts | 147 +++++++------ src/commands/securesign_account.ts | 93 ++++---- src/commands/securesign_build.ts | 71 +++--- src/commands/securesign_createcrt.ts | 129 ++++++----- src/commands/securesign_init.ts | 111 +++++----- src/commands/sysinfo.ts | 71 +++--- src/commands/whois.ts | 127 ++++++----- src/commands/whois_user.ts | 105 +++++---- src/index.ts | 14 +- tsconfig.json | 128 +++++------ types/moment.d.ts | 15 ++ 22 files changed, 1176 insertions(+), 1187 deletions(-) create mode 100644 types/moment.d.ts diff --git a/package.json b/package.json index 8a7d054..c503294 100644 --- a/package.json +++ b/package.json @@ -1,47 +1,48 @@ -{ - "name": "cloudservices-rewrite", - "version": "1.2.0", - "description": "The official LOC Cloud Services system, this is a rewrite of the original version. ", - "main": "dist/Client.js", - "scripts": { - "lint": "eslint ./ --ext ts --fix", - "build": "make", - "lint-find": "eslint ./ --ext ts" - }, - "author": "Library of Code sp-us Engineering Team", - "license": "AGPL-3.0-only", - "private": false, - "dependencies": { - "@ghaiklor/x509": "^1.0.0", - "axios": "^0.19.0", - "body-parser": "^1.19.0", - "eris": "abalabahaha/eris#dev", - "eris-pagination": "bsian03/eris-pagination", - "express": "^4.17.1", - "fs-extra": "^8.1.0", - "helmet": "^3.21.2", - "ioredis": "^4.14.1", - "moment": "^2.24.0", - "moment-precise-range-plugin": "^1.3.0", - "mongoose": "^5.7.4", - "nodemailer": "^6.3.1", - "signale": "^1.4.0", - "uuid": "^3.3.3" - }, - "devDependencies": { - "@types/express": "^4.17.2", - "@types/fs-extra": "^8.0.0", - "@types/helmet": "^0.0.45", - "@types/ioredis": "^4.0.18", - "@types/mongoose": "^5.5.20", - "@types/nodemailer": "^6.2.1", - "@types/signale": "^1.2.1", - "@types/uuid": "^3.4.5", - "@typescript-eslint/eslint-plugin": "^2.4.0", - "@typescript-eslint/parser": "^2.4.0", - "eslint": "^6.5.1", - "eslint-config-airbnb-base": "^14.0.0", - "eslint-plugin-import": "^2.18.2", - "typescript": "^3.6.4" - } -} +{ + "name": "cloudservices-rewrite", + "version": "1.2.0", + "description": "The official LOC Cloud Services system, this is a rewrite of the original version. ", + "main": "dist/Client.js", + "scripts": { + "lint": "eslint ./ --ext ts --fix", + "build": "make", + "lint-find": "eslint ./ --ext ts" + }, + "author": "Library of Code sp-us Engineering Team", + "license": "AGPL-3.0-only", + "private": false, + "dependencies": { + "@ghaiklor/x509": "^1.0.0", + "axios": "^0.19.0", + "body-parser": "^1.19.0", + "eris": "abalabahaha/eris#dev", + "eris-pagination": "bsian03/eris-pagination", + "express": "^4.17.1", + "fs-extra": "^8.1.0", + "helmet": "^3.21.2", + "ioredis": "^4.14.1", + "moment": "^2.24.0", + "moment-precise-range-plugin": "^1.3.0", + "mongoose": "^5.7.4", + "nodemailer": "^6.3.1", + "signale": "^1.4.0", + "uuid": "^3.3.3" + }, + "devDependencies": { + "@types/express": "^4.17.2", + "@types/fs-extra": "^8.0.0", + "@types/helmet": "^0.0.45", + "@types/ioredis": "^4.0.18", + "@types/moment-precise-range-plugin": "^0.2.0", + "@types/mongoose": "^5.5.20", + "@types/nodemailer": "^6.2.1", + "@types/signale": "^1.2.1", + "@types/uuid": "^3.4.5", + "@typescript-eslint/eslint-plugin": "^2.4.0", + "@typescript-eslint/parser": "^2.4.0", + "eslint": "^6.5.1", + "eslint-config-airbnb-base": "^14.0.0", + "eslint-plugin-import": "^2.18.2", + "typescript": "^3.6.4" + } +} diff --git a/src/class/Collection.ts b/src/class/Collection.ts index 71e8a07..12b5b02 100644 --- a/src/class/Collection.ts +++ b/src/class/Collection.ts @@ -1,155 +1,153 @@ -/** - * Hold a bunch of something - */ -export default class Collection extends Map { - baseObject: any - - /** - * Creates an instance of Collection - */ - constructor(iterable: any[]|object = null) { - if (iterable && iterable instanceof Array) { - // @ts-ignore - super(iterable); - } else if (iterable && iterable instanceof Object) { - // @ts-ignore - super(Object.entries(iterable)); - } else { - super(); - } - } - - /** - * Map to array - * ```js - * [value, value, value] - * ``` - */ - toArray(): V[] { - return [...this.values()]; - } - - /** - * Map to object - * ```js - * { key: value, key: value, key: value } - * ``` - */ - toObject(): object { - const obj: object = {}; - for (const [key, value] of this.entries()) { - obj[key] = value; - } - return obj; - } - - /** - * Add an object - * - * If baseObject, add only if instance of baseObject - * - * If no baseObject, add - * @param key The key of the object - * @param value The object data - * @param replace Whether to replace an existing object with the same key - * @return The existing or newly created object - */ - add(key: string, value: V, replace: boolean = false): V { - if (this.has(key) && !replace) { - return this.get(key); - } - if (this.baseObject && !(value instanceof this.baseObject)) return null; - - this.set(key, value); - return value; - } - - /** - * Return the first object to make the function evaluate true - * @param func A function that takes an object and returns something - * @return The first matching object, or `null` if no match - */ - find(func: Function): V { - for (const item of this.values()) { - if (func(item)) return item; - } - return null; - } - - /** - * Return an array with the results of applying the given function to each element - * @param callbackfn A function that takes an object and returns something - */ - map(callbackfn: (value?: V, index?: number, array?: V[]) => U): U[] { - const arr = []; - for (const item of this.values()) { - arr.push(callbackfn(item)); - } - return arr; - } - - /** - * Return all the objects that make the function evaluate true - * @param func A function that takes an object and returns true if it matches - */ - filter(func: Function): V[] { - const arr = []; - for (const item of this.values()) { - if (func(item)) { - arr.push(item); - } - } - return arr; - } - - /** - * Test if at least one element passes the test implemented by the provided function. Returns true if yes, or false if not. - * @param func A function that takes an object and returns true if it matches - */ - some(func: Function) { - for (const item of this.values()) { - if (func(item)) { - return true; - } - } - return false; - } - - /** - * Update an object - * @param key The key of the object - * @param value The updated object data - */ - update(key: string, value: V) { - return this.add(key, value, true); - } - - /** - * Remove an object - * @param key The key of the object - * @returns The removed object, or `null` if nothing was removed - */ - remove(key: string): V { - const item = this.get(key); - if (!item) { - return null; - } - this.delete(key); - return item; - } - - /** - * Get a random object from the Collection - * @returns The random object or `null` if empty - */ - random(): V { - if (!this.size) { - return null; - } - return Array.from(this.values())[Math.floor(Math.random() * this.size)]; - } - - toString() { - return `[Collection<${this.baseObject.name}>]`; - } -} +/** + * Hold a bunch of something + */ +export default class Collection extends Map { + baseObject: any + + /** + * Creates an instance of Collection + */ + constructor(iterable: any[]|object = null) { + if (iterable && iterable instanceof Array) { + super(iterable); + } else if (iterable && iterable instanceof Object) { + super(Object.entries(iterable)); + } else { + super(); + } + } + + /** + * Map to array + * ```js + * [value, value, value] + * ``` + */ + toArray(): V[] { + return [...this.values()]; + } + + /** + * Map to object + * ```js + * { key: value, key: value, key: value } + * ``` + */ + toObject(): object { + const obj: object = {}; + for (const [key, value] of this.entries()) { + obj[key] = value; + } + return obj; + } + + /** + * Add an object + * + * If baseObject, add only if instance of baseObject + * + * If no baseObject, add + * @param key The key of the object + * @param value The object data + * @param replace Whether to replace an existing object with the same key + * @return The existing or newly created object + */ + add(key: string, value: V, replace: boolean = false): V { + if (this.has(key) && !replace) { + return this.get(key); + } + if (this.baseObject && !(value instanceof this.baseObject)) return null; + + this.set(key, value); + return value; + } + + /** + * Return the first object to make the function evaluate true + * @param func A function that takes an object and returns something + * @return The first matching object, or `null` if no match + */ + find(func: Function): V { + for (const item of this.values()) { + if (func(item)) return item; + } + return null; + } + + /** + * Return an array with the results of applying the given function to each element + * @param callbackfn A function that takes an object and returns something + */ + map(callbackfn: (value?: V, index?: number, array?: V[]) => U): U[] { + const arr = []; + for (const item of this.values()) { + arr.push(callbackfn(item)); + } + return arr; + } + + /** + * Return all the objects that make the function evaluate true + * @param func A function that takes an object and returns true if it matches + */ + filter(func: Function): V[] { + const arr = []; + for (const item of this.values()) { + if (func(item)) { + arr.push(item); + } + } + return arr; + } + + /** + * Test if at least one element passes the test implemented by the provided function. Returns true if yes, or false if not. + * @param func A function that takes an object and returns true if it matches + */ + some(func: Function) { + for (const item of this.values()) { + if (func(item)) { + return true; + } + } + return false; + } + + /** + * Update an object + * @param key The key of the object + * @param value The updated object data + */ + update(key: string, value: V) { + return this.add(key, value, true); + } + + /** + * Remove an object + * @param key The key of the object + * @returns The removed object, or `null` if nothing was removed + */ + remove(key: string): V { + const item = this.get(key); + if (!item) { + return null; + } + this.delete(key); + return item; + } + + /** + * Get a random object from the Collection + * @returns The random object or `null` if empty + */ + random(): V { + if (!this.size) { + return null; + } + return Array.from(this.values())[Math.floor(Math.random() * this.size)]; + } + + toString() { + return `[Collection<${this.baseObject.name}>]`; + } +} diff --git a/src/class/Util.ts b/src/class/Util.ts index 22f7b5a..f37ba33 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -242,7 +242,6 @@ export default class Util { .setTimestamp(); 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'}`); - // @ts-ignore this.client.createMessage('580950455581147146', { embed }); this.client.getDMChannel(userID).then((channel) => channel.createMessage({ embed })).catch(); return Promise.resolve(log); diff --git a/src/commands/cwg_data.ts b/src/commands/cwg_data.ts index 60dad9a..354fc07 100644 --- a/src/commands/cwg_data.ts +++ b/src/commands/cwg_data.ts @@ -1,58 +1,56 @@ -import fs from 'fs'; -import moment from 'moment'; -import x509 from '@ghaiklor/x509'; -import { createPaginationEmbed } from 'eris-pagination'; -import { Message } from 'eris'; -import { Command, RichEmbed } from '../class'; -import { Client } from '..'; - -export default class CWG_Data extends Command { - constructor(client: Client) { - super(client); - this.name = 'data'; - this.description = 'Check CWG data'; - this.usage = `${this.client.config.prefix}cwg data [Domain | Port]`; - this.permissions = { roles: ['446104438969466890'] }; - this.enabled = true; - } - - public async run(message: Message, args: string[]) { - try { - if (!args[0]) return this.client.commands.get('help').run(message, ['cwg', this.name]); - const dom = await this.client.db.Domain.find({ $or: [{ domain: args[0] }, { port: Number(args[0]) || '' }] }); - if (!dom.length) { - if (!Number.isNaN(Number(args[0]))) { - try { - await this.client.util.exec(`fuser ${args[0]}/tcp`); - return message.channel.createMessage(`***${this.client.stores.emojis.error} The port you provided is being used by a system process.***`); - } catch (error) { - return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); - } - } - return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); - } - const embeds = dom.map((domain) => { - const cert = fs.readFileSync(domain.x509.cert, { encoding: 'utf8' }); - const embed = new RichEmbed(); - embed.setTitle('Domain Information'); - embed.addField('Account Username', domain.account.username, true); - embed.addField('Account ID', domain.account.userID, true); - embed.addField('Domain', domain.domain, true); - embed.addField('Port', String(domain.port), true); - embed.addField('Certificate Issuer', x509.getIssuer(cert).organizationName, true); - embed.addField('Certificate Subject', x509.getSubject(cert).commonName, true); - embed.addField('Certificate Expiration Date', moment(x509.parseCert(cert).notAfter).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - embed.setTimestamp(); - return embed; - }); - this.client.signale.log(embeds); - // @ts-ignore - if (embeds.length === 1) return message.channel.createMessage({ embed: embeds[0] }); - // @ts-ignore - return createPaginationEmbed(message, this.client, embeds, {}); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} +import fs from 'fs'; +import moment from 'moment'; +import x509 from '@ghaiklor/x509'; +import { createPaginationEmbed } from 'eris-pagination'; +import { Message } from 'eris'; +import { Command, RichEmbed } from '../class'; +import { Client } from '..'; + +export default class CWG_Data extends Command { + constructor(client: Client) { + super(client); + this.name = 'data'; + this.description = 'Check CWG data'; + this.usage = `${this.client.config.prefix}cwg data [Domain | Port]`; + this.permissions = { roles: ['446104438969466890'] }; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + if (!args[0]) return this.client.commands.get('help').run(message, ['cwg', this.name]); + const dom = await this.client.db.Domain.find({ $or: [{ domain: args[0] }, { port: Number(args[0]) || '' }] }); + if (!dom.length) { + if (!Number.isNaN(Number(args[0]))) { + try { + await this.client.util.exec(`fuser ${args[0]}/tcp`); + return message.channel.createMessage(`***${this.client.stores.emojis.error} The port you provided is being used by a system process.***`); + } catch (error) { + return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); + } + } + return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); + } + const embeds = dom.map((domain) => { + const cert = fs.readFileSync(domain.x509.cert, { encoding: 'utf8' }); + const embed = new RichEmbed(); + embed.setTitle('Domain Information'); + embed.addField('Account Username', domain.account.username, true); + embed.addField('Account ID', domain.account.userID, true); + embed.addField('Domain', domain.domain, true); + embed.addField('Port', String(domain.port), true); + embed.addField('Certificate Issuer', x509.getIssuer(cert).organizationName, true); + embed.addField('Certificate Subject', x509.getSubject(cert).commonName, true); + embed.addField('Certificate Expiration Date', moment(x509.parseCert(cert).notAfter).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + embed.setTimestamp(); + return embed; + }); + this.client.signale.log(embeds); + if (embeds.length === 1) return message.channel.createMessage({ embed: embeds[0] }); + return createPaginationEmbed(message, this.client, embeds, {}); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/cwg_delete.ts b/src/commands/cwg_delete.ts index cf58e16..f142d10 100644 --- a/src/commands/cwg_delete.ts +++ b/src/commands/cwg_delete.ts @@ -1,63 +1,61 @@ -import fs from 'fs-extra'; -import axios from 'axios'; -import { Message } from 'eris'; -import { Command, RichEmbed } from '../class'; -import { Client } from '..'; - -export default class CWG_Delete extends Command { - constructor(client: Client) { - super(client); - this.name = 'delete'; - this.description = 'Unbind a domain to the CWG'; - this.usage = `${this.client.config.prefix}cwg delete [Domain | Port]`; - this.permissions = { roles: ['525441307037007902'] }; - this.aliases = ['unbind']; - this.enabled = true; - } - - public async run(message: Message, args: string[]) { - try { - if (!args[0]) return this.client.commands.get('help').run(message, ['cwg', this.name]); - const domain = await this.client.db.Domain.findOne({ $or: [{ domain: args[0] }, { port: Number(args[0]) || '' }] }); - if (!domain) return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); - const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Deleting domain...***`); - const embed = new RichEmbed(); - embed.setTitle('Domain Deletion'); - embed.addField('Account Username', domain.account.username, true); - embed.addField('Account ID', domain.account.userID, true); - embed.addField('Domain', domain.domain, true); - embed.addField('Port', String(domain.port), true); - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - embed.setTimestamp(); - if (domain.domain.includes('cloud.libraryofcode.org')) { - const resultID = await axios({ - method: 'get', - url: `https://api.cloudflare.com/client/v4/zones/5e82fc3111ed4fbf9f58caa34f7553a7/dns_records?name=${domain.domain}`, - headers: { Authorization: `Bearer ${this.client.config.cloudflare}` }, - }); - this.client.signale.debug(resultID.data); - if (resultID.data.result[0]) { - const recordID = resultID.data.result[0].id; - await axios({ - method: 'delete', - url: `https://api.cloudflare.com/client/v4/zones/5e82fc3111ed4fbf9f58caa34f7553a7/dns_records/${recordID}`, - headers: { Authorization: `Bearer ${this.client.config.cloudflare}` }, - }); - } - } - try { - await fs.unlink(`/etc/nginx/sites-enabled/${domain.domain}`); - await fs.unlink(`/etc/nginx/sites-available/${domain.domain}`); - } catch (e) { this.client.signale.error(e); } - await this.client.db.Domain.deleteOne({ domain: domain.domain }); - 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.***`); - // @ts-ignore - this.client.createMessage('580950455581147146', { embed }); - // @ts-ignore - return this.client.getDMChannel(domain.account.userID).then((channel) => channel.createMessage({ embed })).catch(() => {}); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} +import fs from 'fs-extra'; +import axios from 'axios'; +import { Message } from 'eris'; +import { Command, RichEmbed } from '../class'; +import { Client } from '..'; + +export default class CWG_Delete extends Command { + constructor(client: Client) { + super(client); + this.name = 'delete'; + this.description = 'Unbind a domain to the CWG'; + this.usage = `${this.client.config.prefix}cwg delete [Domain | Port]`; + this.permissions = { roles: ['525441307037007902'] }; + this.aliases = ['unbind']; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + if (!args[0]) return this.client.commands.get('help').run(message, ['cwg', this.name]); + const domain = await this.client.db.Domain.findOne({ $or: [{ domain: args[0] }, { port: Number(args[0]) || '' }] }); + if (!domain) return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); + const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Deleting domain...***`); + const embed = new RichEmbed(); + embed.setTitle('Domain Deletion'); + embed.addField('Account Username', domain.account.username, true); + embed.addField('Account ID', domain.account.userID, true); + embed.addField('Domain', domain.domain, true); + embed.addField('Port', String(domain.port), true); + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + embed.setTimestamp(); + if (domain.domain.includes('cloud.libraryofcode.org')) { + const resultID = await axios({ + method: 'get', + url: `https://api.cloudflare.com/client/v4/zones/5e82fc3111ed4fbf9f58caa34f7553a7/dns_records?name=${domain.domain}`, + headers: { Authorization: `Bearer ${this.client.config.cloudflare}` }, + }); + this.client.signale.debug(resultID.data); + if (resultID.data.result[0]) { + const recordID = resultID.data.result[0].id; + await axios({ + method: 'delete', + url: `https://api.cloudflare.com/client/v4/zones/5e82fc3111ed4fbf9f58caa34f7553a7/dns_records/${recordID}`, + headers: { Authorization: `Bearer ${this.client.config.cloudflare}` }, + }); + } + } + try { + await fs.unlink(`/etc/nginx/sites-enabled/${domain.domain}`); + await fs.unlink(`/etc/nginx/sites-available/${domain.domain}`); + } catch (e) { this.client.signale.error(e); } + await this.client.db.Domain.deleteOne({ domain: domain.domain }); + 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.***`); + this.client.createMessage('580950455581147146', { embed }); + return this.client.getDMChannel(domain.account.userID).then((channel) => channel.createMessage({ embed })).catch(() => {}); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/disk.ts b/src/commands/disk.ts index b1ac0d6..b53b45c 100644 --- a/src/commands/disk.ts +++ b/src/commands/disk.ts @@ -1,45 +1,43 @@ -import { Message } from 'eris'; -import moment from 'moment'; -import { Client } from '..'; -import { RichEmbed, Command } from '../class'; -import { dataConversion } from '../functions'; -// eslint-disable-next-line import/no-unresolved -import 'moment-precise-range-plugin'; - -export default class Disk extends Command { - constructor(client: Client) { - super(client); - this.name = 'disk'; - this.description = 'Checks the used disk space by a user'; - this.usage = `${this.client.config.prefix}disk [Username/User ID/Email]`; - this.permissions = { roles: ['446104438969466890'] }; - this.enabled = false; - } - - async run(message: Message, args: string[]) { - try { - if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); - const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }, { emailAddress: args[0] }] }); - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); - if (account.root || args[0].includes('./')) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Permission denied***`); - const diskReply = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Fetching total disk size may up to 10 minutes. This message will edit when the disk size has been located.***`); - const start = Date.now(); - const result = await this.client.util.exec(`du -s ${account.homepath}`); - const end = Date.now(); - // @ts-ignore - const totalTime: string = moment.preciseDiff(start, end); - const embed = new RichEmbed(); - embed.setTitle('Disk Usage'); - embed.setColor('ff0000'); - embed.setDescription(result.split(/ +/g)[1]); - embed.addField('Result', dataConversion(Number(result.split(/ +/g)[0])), true); - embed.addField('Time taken', totalTime, true); - embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL); - embed.setTimestamp(); - // @ts-ignore - return diskReply.edit({ content: '', embed }); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} +import { Message } from 'eris'; +import moment from 'moment'; +import { Client } from '..'; +import { RichEmbed, Command } from '../class'; +import { dataConversion } from '../functions'; +// eslint-disable-next-line import/no-unresolved +import 'moment-precise-range-plugin'; + +export default class Disk extends Command { + constructor(client: Client) { + super(client); + this.name = 'disk'; + this.description = 'Checks the used disk space by a user'; + this.usage = `${this.client.config.prefix}disk [Username/User ID/Email]`; + this.permissions = { roles: ['446104438969466890'] }; + this.enabled = false; + } + + async run(message: Message, args: string[]) { + try { + if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); + const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }, { emailAddress: args[0] }] }); + if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); + if (account.root || args[0].includes('./')) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Permission denied***`); + const diskReply = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Fetching total disk size may up to 10 minutes. This message will edit when the disk size has been located.***`); + const start = Date.now(); + const result = await this.client.util.exec(`du -s ${account.homepath}`); + const end = Date.now(); + const totalTime: string = moment.preciseDiff(start, end); + const embed = new RichEmbed(); + embed.setTitle('Disk Usage'); + embed.setColor('ff0000'); + embed.setDescription(result.split(/ +/g)[1]); + embed.addField('Result', dataConversion(Number(result.split(/ +/g)[0])), true); + embed.addField('Time taken', totalTime, true); + embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL); + embed.setTimestamp(); + return diskReply.edit({ content: '', embed }); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/help.ts b/src/commands/help.ts index 6ad81aa..ac915e1 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -1,70 +1,67 @@ -import { Message } from 'eris'; -import { createPaginationEmbed } from 'eris-pagination'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; - -export default class Help extends Command { - constructor(client: Client) { - super(client); - this.name = 'help'; - this.description = 'Display a list of commands'; - this.usage = `${this.client.config.prefix}help | ${this.client.config.prefix}help ping`; - this.aliases = ['commands']; - this.enabled = true; - } - - // eslint-disable-next-line consistent-return - public async run(message: Message, args?: string[]) { - try { - if (!args[0]) { - const cmdList: Command[] = []; - this.client.commands.forEach((c) => cmdList.push(c)); - const commands = this.client.commands.map((c) => { - const aliases = c.aliases.map((alias) => `${this.client.config.prefix}${alias}`).join(', '); - const perms: string[] = []; - let allowedRoles = c.permissions && c.permissions.roles && c.permissions.roles.map((r) => `<@&${r}>`).join(', '); - if (allowedRoles) { allowedRoles = `**Roles:** ${allowedRoles}`; perms.push(allowedRoles); } - let allowedUsers = c.permissions && c.permissions.users && c.permissions.users.map((u) => `<@${u}>`).join(', '); - if (allowedUsers) { allowedUsers = `**Users:** ${allowedUsers}`; perms.push(allowedUsers); } - const displayedPerms = perms.length ? `**Permissions:**\n${perms.join('\n')}` : ''; - return { name: `${this.client.config.prefix}${c.name}`, value: `**Description:** ${c.description}\n**Aliases:** ${aliases}\n**Usage:** ${c.usage}\n${displayedPerms}`, inline: false }; - }); - - const splitCommands = this.client.util.splitFields(commands); - const cmdPages: RichEmbed[] = []; - splitCommands.forEach((splitCmd) => { - const embed = new RichEmbed(); - embed.setTimestamp(); 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}`); - splitCmd.forEach((c) => embed.addField(c.name, c.value, c.inline)); - return cmdPages.push(embed); - }); - // @ts-ignore - if (cmdPages.length === 1) return message.channel.createMessage({ embed: cmdPages[0] }); - // @ts-ignore - return createPaginationEmbed(message, this.client, cmdPages); - } - const resolved = await this.client.util.resolveCommand(args, message); - if (!resolved) return message.channel.createMessage(`${this.client.stores.emojis.error} **Command not found!**`); - const { cmd } = resolved; - const perms: string[] = []; - let allowedRoles = cmd.permissions && cmd.permissions.roles && cmd.permissions.roles.map((r) => `<@&${r}>`).join(', '); - if (allowedRoles) { allowedRoles = `**Roles:** ${allowedRoles}`; perms.push(allowedRoles); } - let allowedUsers = cmd.permissions && cmd.permissions.users && cmd.permissions.users.map((u) => `<@${u}>`).join(', '); - if (allowedUsers) { allowedUsers = `**Users:** ${allowedUsers}`; perms.push(allowedUsers); } - 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 subcommands = cmd.subcommands.size ? `\n**Subcommands:** ${cmd.subcommands.map((s) => `${cmd.name} ${s.name}`).join(', ')}` : ''; - const embed = new RichEmbed(); - 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); - const description = `**Description**: ${cmd.description}\n**Usage:** ${cmd.usage}${aliases}${displayedPerms}${subcommands}`; - embed.setDescription(description); - // @ts-ignore - message.channel.createMessage({ embed }); - } catch (error) { - this.client.util.handleError(error, message, this); - } - } -} +import { Message } from 'eris'; +import { createPaginationEmbed } from 'eris-pagination'; +import { Client } from '..'; +import { Command, RichEmbed } from '../class'; + +export default class Help extends Command { + constructor(client: Client) { + super(client); + this.name = 'help'; + this.description = 'Display a list of commands'; + this.usage = `${this.client.config.prefix}help | ${this.client.config.prefix}help ping`; + this.aliases = ['commands']; + this.enabled = true; + } + + // eslint-disable-next-line consistent-return + public async run(message: Message, args?: string[]) { + try { + if (!args[0]) { + const cmdList: Command[] = []; + this.client.commands.forEach((c) => cmdList.push(c)); + const commands = this.client.commands.map((c) => { + const aliases = c.aliases.map((alias) => `${this.client.config.prefix}${alias}`).join(', '); + const perms: string[] = []; + let allowedRoles = c.permissions && c.permissions.roles && c.permissions.roles.map((r) => `<@&${r}>`).join(', '); + if (allowedRoles) { allowedRoles = `**Roles:** ${allowedRoles}`; perms.push(allowedRoles); } + let allowedUsers = c.permissions && c.permissions.users && c.permissions.users.map((u) => `<@${u}>`).join(', '); + if (allowedUsers) { allowedUsers = `**Users:** ${allowedUsers}`; perms.push(allowedUsers); } + const displayedPerms = perms.length ? `**Permissions:**\n${perms.join('\n')}` : ''; + return { name: `${this.client.config.prefix}${c.name}`, value: `**Description:** ${c.description}\n**Aliases:** ${aliases}\n**Usage:** ${c.usage}\n${displayedPerms}`, inline: false }; + }); + + const splitCommands = this.client.util.splitFields(commands); + const cmdPages: RichEmbed[] = []; + splitCommands.forEach((splitCmd) => { + const embed = new RichEmbed(); + embed.setTimestamp(); 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}`); + splitCmd.forEach((c) => embed.addField(c.name, c.value, c.inline)); + return cmdPages.push(embed); + }); + if (cmdPages.length === 1) return message.channel.createMessage({ embed: cmdPages[0] }); + return createPaginationEmbed(message, this.client, cmdPages); + } + const resolved = await this.client.util.resolveCommand(args, message); + if (!resolved) return message.channel.createMessage(`${this.client.stores.emojis.error} **Command not found!**`); + const { cmd } = resolved; + const perms: string[] = []; + let allowedRoles = cmd.permissions && cmd.permissions.roles && cmd.permissions.roles.map((r) => `<@&${r}>`).join(', '); + if (allowedRoles) { allowedRoles = `**Roles:** ${allowedRoles}`; perms.push(allowedRoles); } + let allowedUsers = cmd.permissions && cmd.permissions.users && cmd.permissions.users.map((u) => `<@${u}>`).join(', '); + if (allowedUsers) { allowedUsers = `**Users:** ${allowedUsers}`; perms.push(allowedUsers); } + 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 subcommands = cmd.subcommands.size ? `\n**Subcommands:** ${cmd.subcommands.map((s) => `${cmd.name} ${s.name}`).join(', ')}` : ''; + const embed = new RichEmbed(); + 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); + const description = `**Description**: ${cmd.description}\n**Usage:** ${cmd.usage}${aliases}${displayedPerms}${subcommands}`; + embed.setDescription(description); + message.channel.createMessage({ embed }); + } catch (error) { + this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/lock.ts b/src/commands/lock.ts index b85ec33..245013a 100644 --- a/src/commands/lock.ts +++ b/src/commands/lock.ts @@ -1,54 +1,55 @@ -import moment from 'moment'; -import { Message } from 'eris'; -import { Client } from '..'; -import { Command } from '../class'; - -export default class Lock extends Command { - constructor(client: Client) { - super(client); - this.name = 'lock'; - this.description = 'Locks an account.'; - this.permissions = { roles: ['455972169449734144', '662163685439045632'] }; - this.enabled = true; - } - - public async run(message: Message, args: string[]) { // eslint-disable-line - try { - if (!args.length) return this.client.commands.get('help').run(message, [this.name]); - const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] }); - if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot find user.***`); - if (account.locked) return message.channel.createMessage(`***${this.client.stores.emojis.error} This account is already locked.***`); - const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Locking account...***`); - if (account.username === 'matthew' || account.root) return edit.edit(`***${this.client.stores.emojis.error} Permission denied.***`); - await this.client.util.exec(`lock ${account.username}`); - await account.updateOne({ locked: true }); - - const expiry = new Date(); - const lockLength = args[1].match(/[a-z]+|[^a-z]+/gi); - // @ts-ignore - const momentMilliseconds = moment.duration(Number(lockLength[0]), lockLength[1]).asMilliseconds(); - const reason = momentMilliseconds ? args.slice(2).join(' ') : args.slice(1).join(' '); - - await this.client.util.createModerationLog(account.userID, message.member, 2, reason, momentMilliseconds); - edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been locked by Moderator ${message.author.username}#${message.author.discriminator}.***`); - message.delete(); - - this.client.util.transport.sendMail({ - to: account.emailAddress, - from: 'Library of Code sp-us | Cloud Services ', - subject: 'Your account has been locked', - html: ` -

Library of Code | Cloud Services

-

Your Cloud Account has been locked until ${momentMilliseconds ? moment(expiry).calendar() : 'indefinitely'} under the EULA.

-

Reason: ${momentMilliseconds ? args.slice(2).join(' ') : args.slice(1).join(' ')}

-

Supervisor: ${message.author.username}

-

Expiration: ${momentMilliseconds ? moment(expiry).format('dddd, MMMM Do YYYY, h:mm:ss A') : 'N/A'}

- - Library of Code sp-us | Support Team - `, - }); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} +import moment, { unitOfTime } from 'moment'; +import { Message } from 'eris'; +import { Client } from '..'; +import { Command } from '../class'; + +export default class Lock extends Command { + constructor(client: Client) { + super(client); + this.name = 'lock'; + this.description = 'Locks an account.'; + this.permissions = { roles: ['455972169449734144', '662163685439045632'] }; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { // eslint-disable-line + try { + if (!args.length) return this.client.commands.get('help').run(message, [this.name]); + const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] }); + if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot find user.***`); + if (account.locked) return message.channel.createMessage(`***${this.client.stores.emojis.error} This account is already locked.***`); + const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Locking account...***`); + if (account.username === 'matthew' || account.root) return edit.edit(`***${this.client.stores.emojis.error} Permission denied.***`); + await this.client.util.exec(`lock ${account.username}`); + await account.updateOne({ locked: true }); + + const expiry = new Date(); + const lockLength = args[1].match(/[a-z]+|[^a-z]+/gi); + const length = Number(lockLength[0]); + const unit = lockLength[1] as unitOfTime.Base; + const momentMilliseconds = moment.duration(length, unit).asMilliseconds(); + const reason = momentMilliseconds ? args.slice(2).join(' ') : args.slice(1).join(' '); + + await this.client.util.createModerationLog(account.userID, message.member, 2, reason, momentMilliseconds); + edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been locked by Moderator ${message.author.username}#${message.author.discriminator}.***`); + message.delete(); + + this.client.util.transport.sendMail({ + to: account.emailAddress, + from: 'Library of Code sp-us | Cloud Services ', + subject: 'Your account has been locked', + html: ` +

Library of Code | Cloud Services

+

Your Cloud Account has been locked until ${momentMilliseconds ? moment(expiry).calendar() : 'indefinitely'} under the EULA.

+

Reason: ${momentMilliseconds ? args.slice(2).join(' ') : args.slice(1).join(' ')}

+

Supervisor: ${message.author.username}

+

Expiration: ${momentMilliseconds ? moment(expiry).format('dddd, MMMM Do YYYY, h:mm:ss A') : 'N/A'}

+ + Library of Code sp-us | Support Team + `, + }); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/modlogs.ts b/src/commands/modlogs.ts index dc23c45..fd974ed 100644 --- a/src/commands/modlogs.ts +++ b/src/commands/modlogs.ts @@ -1,68 +1,65 @@ -import { Message } from 'eris'; -// eslint-disable-next-line import/no-unresolved -import { createPaginationEmbed } from 'eris-pagination'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; - -export default class Modlogs extends Command { - constructor(client: Client) { - super(client); - this.name = 'modlogs'; - this.description = 'Check a user\'s Cloud Modlogs'; - this.aliases = ['infractions', 'modlog']; - this.enabled = true; - this.permissions = { roles: ['446104438969466890'] }; - } - - public async run(message: Message, args: string[]) { - try { - if (!args.length) return this.client.commands.get('help').run(message, [this.name]); - const msg: Message = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Locating modlogs...***`); - const query = await this.client.db.Moderation.find({ $or: [{ username: args.join(' ') }, { userID: args.filter((a) => a)[0].replace(/[<@!>]/g, '') }] }); - if (!query.length) return msg.edit(`***${this.client.stores.emojis.error} Cannot locate modlogs for ${args.join(' ')}***`); - - // @ts-ignore - const formatted = query.sort((a, b) => a.date - b.date).map((log) => { - const { username, moderatorID, reason, type, date, logID } = log; - let name: string; - switch (type) { - default: name = 'Generic'; break; - case 0: name = 'Create'; break; - case 1: name = 'Warn'; break; - case 2: name = 'Lock'; break; - case 3: name = 'Unlock'; break; - case 4: name = 'Delete'; break; - } - const value = `**ID:** ${logID}\n**Account name:** ${username}\n**Moderator:** <@${moderatorID}>\n**Reason:** ${reason || 'Not supplied'}\n**Date:** ${date.toLocaleString('en-us')} EST`; - const inline = true; - return { name, value, inline }; - }); - const users = [...new Set(query.map((log) => log.userID))].map((u) => `<@${u}>`); - - const logs = this.client.util.splitFields(formatted); - - const embeds = logs.map((l) => { - const embed = new RichEmbed(); - embed.setDescription(`List of Cloud moderation logs for ${users.join(', ')}`); - embed.setAuthor('Library of Code | Cloud Services', this.client.user.avatarURL, 'https://libraryofcode.org/'); - embed.setTitle('Cloud Modlogs/Infractions'); - embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL); - l.forEach((f) => embed.addField(f.name, f.value, f.inline)); - embed.setTimestamp(); - embed.setColor(3447003); - return embed; - }); - - if (embeds.length === 1) { - // @ts-ignore - msg.edit({ content: '', embed: embeds[0] }); - } else { - // @ts-ignore - createPaginationEmbed(message, this.client, embeds, {}, msg); - } - return msg; - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} +import { Message } from 'eris'; +// eslint-disable-next-line import/no-unresolved +import { createPaginationEmbed } from 'eris-pagination'; +import { Client } from '..'; +import { Command, RichEmbed } from '../class'; + +export default class Modlogs extends Command { + constructor(client: Client) { + super(client); + this.name = 'modlogs'; + this.description = 'Check a user\'s Cloud Modlogs'; + this.aliases = ['infractions', 'modlog']; + this.enabled = true; + this.permissions = { roles: ['446104438969466890'] }; + } + + public async run(message: Message, args: string[]) { + try { + if (!args.length) return this.client.commands.get('help').run(message, [this.name]); + const msg: Message = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Locating modlogs...***`); + const query = await this.client.db.Moderation.find({ $or: [{ username: args.join(' ') }, { userID: args.filter((a) => a)[0].replace(/[<@!>]/g, '') }] }); + if (!query.length) return msg.edit(`***${this.client.stores.emojis.error} Cannot locate modlogs for ${args.join(' ')}***`); + + const formatted = query.sort((a, b) => a.date.getTime() - b.date.getTime()).map((log) => { + const { username, moderatorID, reason, type, date, logID } = log; + let name: string; + switch (type) { + default: name = 'Generic'; break; + case 0: name = 'Create'; break; + case 1: name = 'Warn'; break; + case 2: name = 'Lock'; break; + case 3: name = 'Unlock'; break; + case 4: name = 'Delete'; break; + } + const value = `**ID:** ${logID}\n**Account name:** ${username}\n**Moderator:** <@${moderatorID}>\n**Reason:** ${reason || 'Not supplied'}\n**Date:** ${date.toLocaleString('en-us')} EST`; + const inline = true; + return { name, value, inline }; + }); + const users = [...new Set(query.map((log) => log.userID))].map((u) => `<@${u}>`); + + const logs = this.client.util.splitFields(formatted); + + const embeds = logs.map((l) => { + const embed = new RichEmbed(); + embed.setDescription(`List of Cloud moderation logs for ${users.join(', ')}`); + embed.setAuthor('Library of Code | Cloud Services', this.client.user.avatarURL, 'https://libraryofcode.org/'); + embed.setTitle('Cloud Modlogs/Infractions'); + embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL); + l.forEach((f) => embed.addField(f.name, f.value, f.inline)); + embed.setTimestamp(); + embed.setColor(3447003); + return embed; + }); + + if (embeds.length === 1) { + msg.edit({ content: '', embed: embeds[0] }); + } else { + createPaginationEmbed(message, this.client, embeds, {}, msg); + } + return msg; + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/notify.ts b/src/commands/notify.ts index ff3ff1e..c7b4cfd 100644 --- a/src/commands/notify.ts +++ b/src/commands/notify.ts @@ -1,53 +1,51 @@ -/* eslint-disable consistent-return */ -import { Message } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; - -export default class Notify extends Command { - constructor(client: Client) { - super(client); - this.name = 'notify'; - this.description = 'Sends a notification to a user.'; - this.usage = `${this.client.config.prefix}notify [username | user ID]`; - this.permissions = { roles: ['446104438969466890'] }; - this.enabled = true; - } - - public async run(message: Message, args: string[]) { - try { - if (!args.length) return this.client.commands.get('help').run(message, [this.name]); - const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Sending notification...***`); - 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.***`); - const embed = new RichEmbed() - .setTitle('Cloud Account | Notification') - .setDescription(args.slice(1).join(' ')) - .addField('Moderator', `<@${message.author.id}>`, true) - .setFooter(this.client.user.username, this.client.user.avatarURL) - .setTimestamp(); - this.client.getDMChannel(account.userID).then((channel) => { - // @ts-ignore - channel.createMessage({ embed }); - }); - embed.addField('User', `${account.username} | <@${account.userID}>`, true); - // @ts-ignore - this.client.createMessage('580950455581147146', { embed }); - this.client.util.transport.sendMail({ - to: account.emailAddress, - from: 'Library of Code sp-us | Cloud Services ', - subject: 'Notification', - html: ` -

Library of Code sp-us | Cloud Services

-

${args.slice(1).join(' ')}

-

Moderator: ${message.author.username}

- - Library of Code sp-us | Support Team - `, - }); - message.delete(); - edit.edit(`***${this.client.stores.emojis.success} Send notification to ${account.username}.***`); - } catch (error) { - await this.client.util.handleError(error, message, this); - } - } -} +/* eslint-disable consistent-return */ +import { Message } from 'eris'; +import { Client } from '..'; +import { Command, RichEmbed } from '../class'; + +export default class Notify extends Command { + constructor(client: Client) { + super(client); + this.name = 'notify'; + this.description = 'Sends a notification to a user.'; + this.usage = `${this.client.config.prefix}notify [username | user ID]`; + this.permissions = { roles: ['446104438969466890'] }; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + if (!args.length) return this.client.commands.get('help').run(message, [this.name]); + const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Sending notification...***`); + 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.***`); + const embed = new RichEmbed() + .setTitle('Cloud Account | Notification') + .setDescription(args.slice(1).join(' ')) + .addField('Moderator', `<@${message.author.id}>`, true) + .setFooter(this.client.user.username, this.client.user.avatarURL) + .setTimestamp(); + this.client.getDMChannel(account.userID).then((channel) => { + channel.createMessage({ embed }); + }); + embed.addField('User', `${account.username} | <@${account.userID}>`, true); + this.client.createMessage('580950455581147146', { embed }); + this.client.util.transport.sendMail({ + to: account.emailAddress, + from: 'Library of Code sp-us | Cloud Services ', + subject: 'Notification', + html: ` +

Library of Code sp-us | Cloud Services

+

${args.slice(1).join(' ')}

+

Moderator: ${message.author.username}

+ + Library of Code sp-us | Support Team + `, + }); + message.delete(); + edit.edit(`***${this.client.stores.emojis.success} Send notification to ${account.username}.***`); + } catch (error) { + await this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/parse.ts b/src/commands/parse.ts index 2bd957b..f23f682 100644 --- a/src/commands/parse.ts +++ b/src/commands/parse.ts @@ -1,70 +1,69 @@ -import fs from 'fs-extra'; -import { parseCert } from '@ghaiklor/x509'; -import { Message } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; -import { parseCertificate, Certificate } from '../functions'; - -export default class Parse extends Command { - constructor(client: Client) { - super(client); - this.name = 'parse'; - this.description = 'Gets information on a user\'s x509 certificate.'; - this.usage = `${this.client.config.prefix}parse [username || user ID]`; - this.permissions = { roles: ['446104438969466890'] }; - } - - public async run(message: Message, args: string[]) { // eslint-disable-line - try { - if (!args.length) return this.client.commands.get('help').run(message, [this.name]); - const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] }); - if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot find user.***`); - let dir: string[]; - try { - dir = await fs.readdir(`${account.homepath}/Validation`); - } catch (err) { - return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate Validation directory.***`); - } - if (!dir.length) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate certificate.***`); - let cert: Certificate; - try { - cert = await parseCertificate(this.client, `${account.homepath}/Validation/${dir[0]}`); - } catch (error) { - if (error.message.includes('panic: Certificate PEM Encode == nil')) return message.channel.createMessage(`***${this.client.stores.emojis.error} Invalid certificate.***`); - } - // const cert = parseCert(`${account.homepath}/Validation/${dir[0]}`); - const subjectCommonName = cert.subject.commonName || 'Not Specified'; - const subjectEmailAddress = cert.subject.emailAddress || 'Not Specified'; - const subjectOrganization = cert.subject.organizationName || 'Not Specified'; - const subjectOrganizationalUnit = cert.subject.organizationalUnitName || 'Not Specified'; - const subjectCountry = cert.subject.countryName || 'Not Specified'; - const issuerCommonName = cert.issuer.commonName || 'Not Specified'; - const issuerEmailAddress = cert.issuer.emailAddress || 'Not Specified'; - const issuerOrganization = cert.issuer.organizationName || 'Not Specified'; - const issuerOrganizationalUnit = cert.issuer.organizationalUnitName || 'Not Specified'; - const issuerCountry = cert.issuer.countryName || 'Not Specified'; - const user = this.client.users.get(account.userID) || await this.client.getRESTUser(account.userID); - const embed = new RichEmbed(); - embed.setTitle('Parse x509 Certificate'); - embed.setDescription(`${account.homepath}/Validation/${dir[0]} | ${account.username} <@${user.id}>`); - embed.setColor(3447003); - embed.addField('Subject', `**Common Name:** ${subjectCommonName}\n**Email Address:** ${subjectEmailAddress}\n**Organization:** ${subjectOrganization}\n**Organizational Unit:** ${subjectOrganizationalUnit}\n**Country:** ${subjectCountry}`, true); - embed.addField('Issuer', `**Common Name:** ${issuerCommonName}\n**Email Address:** ${issuerEmailAddress}\n**Organization:** ${issuerOrganization}\n**Organizational Unit:** ${issuerOrganizationalUnit}\n**Country:** ${issuerCountry}`, true); - embed.addField('Serial Number', cert.serial, true); - embed.addField('Fingerprint', cert.fingerPrint, true); - embed.addField('Signature Algorithm', cert.signatureAlgorithm, true); - embed.addField('Public Key Algorithm', cert.publicKeyAlgorithm, true); - embed.addField('Key Usage', cert.extensions.keyUsage, true); - embed.addField('Extended Key Usage', cert.extensions.extendedKeyUsage.join(', '), true); - embed.addField('Policies', cert.extensions.certificatePolicies.join(', '), true); - embed.addField('Issued On', new Date(cert.notBefore).toLocaleString('en-us'), true); - embed.addField('Expires On', new Date(cert.notAfter).toLocaleString('en-us'), true); - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - embed.setTimestamp(); - // @ts-ignore - message.channel.createMessage({ embed }); - } catch (error) { - await this.client.util.handleError(error, message, this); - } - } -} +import fs from 'fs-extra'; +import { parseCert } from '@ghaiklor/x509'; +import { Message } from 'eris'; +import { Client } from '..'; +import { Command, RichEmbed } from '../class'; +import { parseCertificate, Certificate } from '../functions'; + +export default class Parse extends Command { + constructor(client: Client) { + super(client); + this.name = 'parse'; + this.description = 'Gets information on a user\'s x509 certificate.'; + this.usage = `${this.client.config.prefix}parse [username || user ID]`; + this.permissions = { roles: ['446104438969466890'] }; + } + + public async run(message: Message, args: string[]) { // eslint-disable-line + try { + if (!args.length) return this.client.commands.get('help').run(message, [this.name]); + const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] }); + if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot find user.***`); + let dir: string[]; + try { + dir = await fs.readdir(`${account.homepath}/Validation`); + } catch (err) { + return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate Validation directory.***`); + } + if (!dir.length) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate certificate.***`); + let cert: Certificate; + try { + cert = await parseCertificate(this.client, `${account.homepath}/Validation/${dir[0]}`); + } catch (error) { + if (error.message.includes('panic: Certificate PEM Encode == nil')) return message.channel.createMessage(`***${this.client.stores.emojis.error} Invalid certificate.***`); + } + // const cert = parseCert(`${account.homepath}/Validation/${dir[0]}`); + const subjectCommonName = cert.subject.commonName || 'Not Specified'; + const subjectEmailAddress = cert.subject.emailAddress || 'Not Specified'; + const subjectOrganization = cert.subject.organizationName || 'Not Specified'; + const subjectOrganizationalUnit = cert.subject.organizationalUnitName || 'Not Specified'; + const subjectCountry = cert.subject.countryName || 'Not Specified'; + const issuerCommonName = cert.issuer.commonName || 'Not Specified'; + const issuerEmailAddress = cert.issuer.emailAddress || 'Not Specified'; + const issuerOrganization = cert.issuer.organizationName || 'Not Specified'; + const issuerOrganizationalUnit = cert.issuer.organizationalUnitName || 'Not Specified'; + const issuerCountry = cert.issuer.countryName || 'Not Specified'; + const user = this.client.users.get(account.userID) || await this.client.getRESTUser(account.userID); + const embed = new RichEmbed(); + embed.setTitle('Parse x509 Certificate'); + embed.setDescription(`${account.homepath}/Validation/${dir[0]} | ${account.username} <@${user.id}>`); + embed.setColor(3447003); + embed.addField('Subject', `**Common Name:** ${subjectCommonName}\n**Email Address:** ${subjectEmailAddress}\n**Organization:** ${subjectOrganization}\n**Organizational Unit:** ${subjectOrganizationalUnit}\n**Country:** ${subjectCountry}`, true); + embed.addField('Issuer', `**Common Name:** ${issuerCommonName}\n**Email Address:** ${issuerEmailAddress}\n**Organization:** ${issuerOrganization}\n**Organizational Unit:** ${issuerOrganizationalUnit}\n**Country:** ${issuerCountry}`, true); + embed.addField('Serial Number', cert.serial, true); + embed.addField('Fingerprint', cert.fingerPrint, true); + embed.addField('Signature Algorithm', cert.signatureAlgorithm, true); + embed.addField('Public Key Algorithm', cert.publicKeyAlgorithm, true); + embed.addField('Key Usage', cert.extensions.keyUsage, true); + embed.addField('Extended Key Usage', cert.extensions.extendedKeyUsage.join(', '), true); + embed.addField('Policies', cert.extensions.certificatePolicies.join(', '), true); + embed.addField('Issued On', new Date(cert.notBefore).toLocaleString('en-us'), true); + embed.addField('Expires On', new Date(cert.notAfter).toLocaleString('en-us'), true); + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + embed.setTimestamp(); + message.channel.createMessage({ embed }); + } catch (error) { + await this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 65e1531..7e1164a 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -1,75 +1,72 @@ -import { parseCert } from '@ghaiklor/x509'; -import { Message } from 'eris'; -import { readdirSync } from 'fs'; -import moment from 'moment'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; -import { parseCertificate, Certificate } from '../functions'; - -export default class Parseall extends Command { - constructor(client: Client) { - super(client); - - this.name = 'parseall'; - this.description = 'Displays certificate validation for all accounts'; - this.usage = `${this.client.config.prefix}parseall`; - this.permissions = { roles: ['446104438969466890'] }; - this.aliases = ['checkcerts', 'verifyall', 'verifycerts']; - } - - public async run(message: Message, args: string[]) { - try { - const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Loading...***`); - const embed = new RichEmbed(); - embed.setTitle('Certificate Validation'); - embed.setAuthor(this.client.user.username, this.client.user.avatarURL); - embed.setFooter(`Requested by ${message.member.username}#${message.member.discriminator}`, message.member.avatarURL); - embed.setTimestamp(); - const search = await this.client.db.Account.find(); - - const files = search.map((acc) => { - let certfile: string; - try { certfile = readdirSync(`${acc.homepath}/Validation`)[0] } catch (error) { if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) certfile = 'not_found.crt' } // eslint-disable-line - return `${acc.homepath}/Validation/${certfile}`; - }); - - // @ts-ignore - const parsed: ({ status: 'fulfilled', value: Certificate } | { status: 'rejected', reason: Error })[] = await Promise.allSettled(files.map((c) => parseCertificate(this.client, c))); - - const final: string[] = await Promise.all(search.map(async (a) => { - const result = parsed[search.findIndex((acc) => acc === a)]; - if (result.status === 'rejected') { - if (result.reason.message.includes('no such file or directory') || result.reason.message.includes('File doesn\'t exist.')) return `${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`; - if (result.reason.message.includes('panic: Certificate PEM Encode == nil')) return `${this.client.stores.emojis.error} **${a.username}** Invalid certificate`; - throw result.reason; - } - const { notAfter } = result.value; - // @ts-ignore - const timeObject: {years: number, months: number, days: number, hours: number, minutes: number, seconds: number, firstDateWasLater: boolean} = moment.preciseDiff(new Date(), notAfter, true); - const precise: [number, string][] = []; - // @ts-ignore - const timeArray: number[] = Object.values(timeObject).filter((v) => typeof v === 'number'); - timeArray.forEach((t) => { // eslint-disable-line - const index = timeArray.indexOf(t); - const measurements = ['yr', 'mo', 'd', 'h', 'm', 's']; - precise.push([t, measurements[index]]); - }); - const time = precise.filter((n) => n[0]).map(((v) => v.join(''))).join(', '); - - if (notAfter < new Date()) return `${this.client.stores.emojis.error} **${a.username}** Expired ${time} ago`; - return `${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`; - })); - - if (final.join('\n').length < 2048) embed.setDescription(final.join('\n')); - else { - const split = this.client.util.splitString(final.join('\n'), 1024); - split.forEach((s) => embed.addField('\u200B', s)); - } - - // @ts-ignore - return await msg.edit({ content: '', embed }); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} +import { parseCert } from '@ghaiklor/x509'; +import { Message } from 'eris'; +import { readdirSync } from 'fs'; +import moment from 'moment'; +import 'moment-precise-range-plugin'; +import { Client } from '..'; +import { Command, RichEmbed } from '../class'; +import { parseCertificate, Certificate } from '../functions'; + +export default class Parseall extends Command { + constructor(client: Client) { + super(client); + + this.name = 'parseall'; + this.description = 'Displays certificate validation for all accounts'; + this.usage = `${this.client.config.prefix}parseall`; + this.permissions = { roles: ['446104438969466890'] }; + this.aliases = ['checkcerts', 'verifyall', 'verifycerts']; + } + + public async run(message: Message, args: string[]) { + try { + const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Loading...***`); + const embed = new RichEmbed(); + embed.setTitle('Certificate Validation'); + embed.setAuthor(this.client.user.username, this.client.user.avatarURL); + embed.setFooter(`Requested by ${message.member.username}#${message.member.discriminator}`, message.member.avatarURL); + embed.setTimestamp(); + const search = await this.client.db.Account.find(); + + const files = search.map((acc) => { + let certfile: string; + try { certfile = readdirSync(`${acc.homepath}/Validation`)[0] } catch (error) { if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) certfile = 'not_found.crt' } // eslint-disable-line + return `${acc.homepath}/Validation/${certfile}`; + }); + + const parsed = await Promise.allSettled(files.map((c) => parseCertificate(this.client, c))); + + const final: string[] = await Promise.all(search.map(async (a) => { + const result = parsed[search.findIndex((acc) => acc === a)]; + if (result.status === 'rejected') { + if (result.reason.message.includes('no such file or directory') || result.reason.message.includes('File doesn\'t exist.')) return `${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`; + if (result.reason.message.includes('panic: Certificate PEM Encode == nil')) return `${this.client.stores.emojis.error} **${a.username}** Invalid certificate`; + throw result.reason; + } + const { notAfter } = result.value; + const timeObject = moment.preciseDiff(new Date(), notAfter, true); + const precise: [number, string][] = []; + const timeArray: number[] = Object.values(timeObject).filter((v) => typeof v === 'number'); + timeArray.forEach((t) => { // eslint-disable-line + const index = timeArray.indexOf(t); + const measurements = ['yr', 'mo', 'd', 'h', 'm', 's']; + precise.push([t, measurements[index]]); + }); + const time = precise.filter((n) => n[0]).map(((v) => v.join(''))).join(', '); + + if (notAfter < new Date()) return `${this.client.stores.emojis.error} **${a.username}** Expired ${time} ago`; + return `${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`; + })); + + if (final.join('\n').length < 2048) embed.setDescription(final.join('\n')); + else { + const split = this.client.util.splitString(final.join('\n'), 1024); + split.forEach((s) => embed.addField('\u200B', s)); + } + + return await msg.edit({ content: '', embed }); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/securesign_account.ts b/src/commands/securesign_account.ts index 64b4ed6..0ec1efc 100644 --- a/src/commands/securesign_account.ts +++ b/src/commands/securesign_account.ts @@ -1,47 +1,46 @@ -import { Message, PrivateChannel } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; -import { AccountInterface } from '../models'; - -export default class SecureSign_Account extends Command { - constructor(client: Client) { - super(client); - this.name = 'account'; - this.description = 'Provides SecureSign account details for currently logged in user'; - this.usage = `${this.client.config.prefix}securesign account`; - this.enabled = true; - this.guildOnly = false; - } - - public async run(message: Message, args: string[]) { - try { - const user = await this.client.db.Account.findOne({ userID: message.author.id }); - if (!user || (!user.permissions.staff && !(message.channel instanceof PrivateChannel))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Run this command in your DMs!***`); - - let account: AccountInterface; - if (!args[0] || !user.permissions.staff) account = user; - else account = await this.client.db.Account.findOne({ $or: [{ userID: args[0] }, { username: args[0] }, { emailAddress: args[0] }] }); - - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); - if (!account.hash) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not initialized***`); - const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Loading account details...***`); - - const details = await this.client.util.exec(`sudo -H -u ${account.username} bash -c 'securesign-canary account'`); - const info = details.replace(/^\s+|\s+$/g, '').replace(/\n/g, '\n**').replace(/: /g, ':** ').split('\n'); - const title = info.shift(); - const description = info.join('\n'); - const content = ''; - - const embed = new RichEmbed(); - embed.setTitle(title); - embed.setDescription(description); - embed.setAuthor(this.client.user.username, this.client.user.avatarURL); - embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL); - - // @ts-ignore - return msg.edit({ content, embed }); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} +import { Message, PrivateChannel } from 'eris'; +import { Client } from '..'; +import { Command, RichEmbed } from '../class'; +import { AccountInterface } from '../models'; + +export default class SecureSign_Account extends Command { + constructor(client: Client) { + super(client); + this.name = 'account'; + this.description = 'Provides SecureSign account details for currently logged in user'; + this.usage = `${this.client.config.prefix}securesign account`; + this.enabled = true; + this.guildOnly = false; + } + + public async run(message: Message, args: string[]) { + try { + const user = await this.client.db.Account.findOne({ userID: message.author.id }); + if (!user || (!user.permissions.staff && !(message.channel instanceof PrivateChannel))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Run this command in your DMs!***`); + + let account: AccountInterface; + if (!args[0] || !user.permissions.staff) account = user; + else account = await this.client.db.Account.findOne({ $or: [{ userID: args[0] }, { username: args[0] }, { emailAddress: args[0] }] }); + + if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); + if (!account.hash) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not initialized***`); + const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Loading account details...***`); + + const details = await this.client.util.exec(`sudo -H -u ${account.username} bash -c 'securesign-canary account'`); + const info = details.replace(/^\s+|\s+$/g, '').replace(/\n/g, '\n**').replace(/: /g, ':** ').split('\n'); + const title = info.shift(); + const description = info.join('\n'); + const content = ''; + + const embed = new RichEmbed(); + embed.setTitle(title); + embed.setDescription(description); + embed.setAuthor(this.client.user.username, this.client.user.avatarURL); + embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL); + + return msg.edit({ content, embed }); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/securesign_build.ts b/src/commands/securesign_build.ts index fb28b3e..48f5d2a 100644 --- a/src/commands/securesign_build.ts +++ b/src/commands/securesign_build.ts @@ -1,36 +1,35 @@ -import { Message } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; - -export default class SecureSign_Build extends Command { - constructor(client: Client) { - super(client); - this.name = 'build'; - this.description = 'Shows information about the current build of the CLI'; - this.usage = `${this.client.config.prefix}securesign build`; - this.enabled = true; - } - - public async run(message: Message, args: string[]) { - try { - const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Loading build information...***`); - - const build = await this.client.util.exec("sudo -H -u root bash -c 'securesign-canary build'"); - const info = build.replace(/^\s+|\s+$/g, '').replace(/\n/g, '\n**').replace(/: /g, ':** ').split('\n'); - const title = info.shift(); - const description = info.join('\n'); - const content = ''; - - const embed = new RichEmbed(); - embed.setTitle(title); - embed.setDescription(description); - embed.setAuthor(this.client.user.username, this.client.user.avatarURL); - embed.setFooter(`Requested by ${message.member.username}#${message.member.discriminator}`, message.member.avatarURL); - - // @ts-ignore - msg.edit({ content, embed }); - } catch (error) { - this.client.util.handleError(error, message, this); - } - } -} +import { Message } from 'eris'; +import { Client } from '..'; +import { Command, RichEmbed } from '../class'; + +export default class SecureSign_Build extends Command { + constructor(client: Client) { + super(client); + this.name = 'build'; + this.description = 'Shows information about the current build of the CLI'; + this.usage = `${this.client.config.prefix}securesign build`; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Loading build information...***`); + + const build = await this.client.util.exec("sudo -H -u root bash -c 'securesign-canary build'"); + const info = build.replace(/^\s+|\s+$/g, '').replace(/\n/g, '\n**').replace(/: /g, ':** ').split('\n'); + const title = info.shift(); + const description = info.join('\n'); + const content = ''; + + const embed = new RichEmbed(); + embed.setTitle(title); + embed.setDescription(description); + embed.setAuthor(this.client.user.username, this.client.user.avatarURL); + embed.setFooter(`Requested by ${message.member.username}#${message.member.discriminator}`, message.member.avatarURL); + + msg.edit({ content, embed }); + } catch (error) { + this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/securesign_createcrt.ts b/src/commands/securesign_createcrt.ts index 80e5d8a..85052db 100644 --- a/src/commands/securesign_createcrt.ts +++ b/src/commands/securesign_createcrt.ts @@ -1,65 +1,64 @@ -import { Message, PrivateChannel, TextChannel } from 'eris'; -import axios from 'axios'; -import { Client } from '..'; -import { Command } from '../class'; - -export default class SecureSign_Init extends Command { - constructor(client: Client) { - super(client); - this.name = 'createcrt'; - this.description = 'Creates a new certificate'; - this.usage = `${this.client.config.prefix}securesign createcrt [-s sign] [-c class] [-m digest]\n\`sign\`: Sign type (ecc/rsa)\n\`class\`: Certificate Class (1/2/3)\n\`digest\`: SHA Digest (256/384/512)`; - this.enabled = true; - this.guildOnly = false; - } - - public async run(message: Message, args: string[]) { - try { - const account = await this.client.db.Account.findOne({ userID: message.author.id }); - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); - if (!account.hash) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not initialized***`); - - // @ts-ignore - const options: { s?: string, c?: string, m?: string } = args.length ? Object.fromEntries(` ${args.join(' ')}`.split(' -').filter((a) => a).map((a) => a.split(/ (.+)/)).filter((a) => a.length > 1)) : {}; - if (options.s && options.s.toLowerCase() !== 'ecc' && options.s.toLowerCase() !== 'rsa') return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid signing type, choose between \`ecc\` or \`rsa\``); - if (options.c && (!Number(options.c) || Number(options.c) < 1 || Number(options.c) > 3)) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid class selected, choose between Class \`1\`, \`2\` or \`3\``); - if (options.m && (!Number(options.m) || (options.m !== '256' && options.m !== '384' && options.m !== '512'))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid SHA Digest selected, choose between \`256\`, \`384\` or \`512\``); - if (Number(options.c) === 3 && (!options.s || options.s.toLowerCase() === 'ecc')) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Class 3 ECC certificates are not supported, please use the \`-s rsa\` option instead***`); - - const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Creating certificate...***`); - if (options.s) options.s = options.s.toLowerCase(); - const hash = this.client.util.getAcctHash(account.homepath); - - // Check if they can generate certificate - try { - const { data } = await axios({ - method: 'GET', - url: 'https://api.securesign.org/account/details', - headers: { Authorization: hash, 'Content-Type': 'application/json' }, - }); - - const { total, allowed } = data.message; - if (total >= allowed) return msg.edit(`${this.client.stores.emojis.error} ***Not enough certificate allowances - please ask a member of staff to increase this limit from ${total}***`); - if (Number(options.c) > data.message.class) return msg.edit(`${this.client.stores.emojis.error} ***Class too low, you are on a class ${data.message.class} account***`); - } catch (error) { - const { code } = error.response.data; - if (code === 1001) { - await this.client.db.Account.updateOne({ userID: account.userID }, { $set: { hash: false } }); - this.client.getDMChannel(account.userID).then((channel) => channel.createMessage('Your SecureSign password has been reset - please reinitialize your SecureSign account')).catch(); - return msg.edit(`${this.client.stores.emojis.error} ***Authentication failed***`); - } - throw error; - } - - const execoptions = `${options.s ? ` -s ${options.s}` : ''}${options.c ? ` -c ${options.c}` : ''}${options.m ? ` -m ${options.m}` : ''}`; - const cmd = `sudo -H -u ${account.username} bash -c 'securesign-canary createcrt${execoptions}'`; - - const exec = await this.client.util.exec(cmd); - if (!exec.replace(/^\s+|\s+$/g, '').endsWith('Successfully wrote certificate.')) throw new Error(`Certificate generation did not complete successfully:\n${cmd}`); - - return msg.edit(`${this.client.stores.emojis.success} ***Successfully created certificate***`); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} +import { Message, PrivateChannel, TextChannel } from 'eris'; +import axios from 'axios'; +import { Client } from '..'; +import { Command } from '../class'; + +export default class SecureSign_Init extends Command { + constructor(client: Client) { + super(client); + this.name = 'createcrt'; + this.description = 'Creates a new certificate'; + this.usage = `${this.client.config.prefix}securesign createcrt [-s sign] [-c class] [-m digest]\n\`sign\`: Sign type (ecc/rsa)\n\`class\`: Certificate Class (1/2/3)\n\`digest\`: SHA Digest (256/384/512)`; + this.enabled = true; + this.guildOnly = false; + } + + public async run(message: Message, args: string[]) { + try { + const account = await this.client.db.Account.findOne({ userID: message.author.id }); + if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); + if (!account.hash) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not initialized***`); + + const options: { s?: string, c?: string, m?: string } = args.length ? Object.fromEntries(` ${args.join(' ')}`.split(' -').filter((a) => a).map((a) => a.split(/ (.+)/)).filter((a) => a.length > 1)) : {}; + if (options.s && options.s.toLowerCase() !== 'ecc' && options.s.toLowerCase() !== 'rsa') return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid signing type, choose between \`ecc\` or \`rsa\``); + if (options.c && (!Number(options.c) || Number(options.c) < 1 || Number(options.c) > 3)) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid class selected, choose between Class \`1\`, \`2\` or \`3\``); + if (options.m && (!Number(options.m) || (options.m !== '256' && options.m !== '384' && options.m !== '512'))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid SHA Digest selected, choose between \`256\`, \`384\` or \`512\``); + if (Number(options.c) === 3 && (!options.s || options.s.toLowerCase() === 'ecc')) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Class 3 ECC certificates are not supported, please use the \`-s rsa\` option instead***`); + + const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Creating certificate...***`); + if (options.s) options.s = options.s.toLowerCase(); + const hash = this.client.util.getAcctHash(account.homepath); + + // Check if they can generate certificate + try { + const { data } = await axios({ + method: 'GET', + url: 'https://api.securesign.org/account/details', + headers: { Authorization: hash, 'Content-Type': 'application/json' }, + }); + + const { total, allowed } = data.message; + if (total >= allowed) return msg.edit(`${this.client.stores.emojis.error} ***Not enough certificate allowances - please ask a member of staff to increase this limit from ${total}***`); + if (Number(options.c) > data.message.class) return msg.edit(`${this.client.stores.emojis.error} ***Class too low, you are on a class ${data.message.class} account***`); + } catch (error) { + const { code } = error.response.data; + if (code === 1001) { + await this.client.db.Account.updateOne({ userID: account.userID }, { $set: { hash: false } }); + this.client.getDMChannel(account.userID).then((channel) => channel.createMessage('Your SecureSign password has been reset - please reinitialize your SecureSign account')).catch(); + return msg.edit(`${this.client.stores.emojis.error} ***Authentication failed***`); + } + throw error; + } + + const execoptions = `${options.s ? ` -s ${options.s}` : ''}${options.c ? ` -c ${options.c}` : ''}${options.m ? ` -m ${options.m}` : ''}`; + const cmd = `sudo -H -u ${account.username} bash -c 'securesign-canary createcrt${execoptions}'`; + + const exec = await this.client.util.exec(cmd); + if (!exec.replace(/^\s+|\s+$/g, '').endsWith('Successfully wrote certificate.')) throw new Error(`Certificate generation did not complete successfully:\n${cmd}`); + + return msg.edit(`${this.client.stores.emojis.success} ***Successfully created certificate***`); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/securesign_init.ts b/src/commands/securesign_init.ts index 1ccccfa..ecaacb3 100644 --- a/src/commands/securesign_init.ts +++ b/src/commands/securesign_init.ts @@ -1,56 +1,55 @@ -import { Message, PrivateChannel, TextChannel } from 'eris'; -import axios, { AxiosResponse } from 'axios'; -import { Client } from '..'; -import { Command } from '../class'; - -export default class SecureSign_Init extends Command { - constructor(client: Client) { - super(client); - this.name = 'init'; - this.description = 'Inits configuration files and environment variables (DM only)'; - this.usage = `${this.client.config.prefix}securesign init [hash]`; - this.enabled = true; - this.guildOnly = false; - } - - public async run(message: Message, args: string[]) { - try { - if (!args[0]) return this.client.commands.get('help').run(message, ['securesign', this.name]); - if (!(message.channel instanceof PrivateChannel)) { - message.delete(); - return message.channel.createMessage(`${this.client.stores.emojis.error} ***Run this command in your DMs!***`); - } - const account = await this.client.db.Account.findOne({ userID: message.author.id }); - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not registered***`); - if (account.locked) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Your account is locked***`); - const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Initializing account...***`); - let verify: AxiosResponse; - try { - verify = await axios({ - method: 'get', - url: 'https://api.securesign.org/account/details', - headers: { Authorization: args[0] }, - }); - } catch (error) { - const { status } = error.response; - if (status === 400 || status === 401 || status === 403 || status === 404) return msg.edit(`${this.client.stores.emojis.error} ***Credentials incorrect***`); - throw error; - } - const { id } = verify.data.message; - if (id !== message.author.id && !account.root) { - // @ts-ignore - const channel: TextChannel = this.client.guilds.get('446067825673633794').channels.get('501089664040697858'); - channel.createMessage(`**__UNAUTHORIZED ACCESS ALERT__**\n${message.author.mention} tried to initialize their account using <@${id}>'s SecureSign credentials.\nTheir account has been locked under Section 5.2 of the EULA.`); - const tasks = [this.client.util.exec(`lock ${account.username}`), account.updateOne({ locked: true }), this.client.util.createModerationLog(account.userID, this.client.user, 2, 'Violation of Section 5.2 of the EULA')]; - await Promise.all(tasks); - return msg.edit(`${this.client.stores.emojis.error} ***Credentials incorrect***`); - } - const init = await this.client.util.exec(`sudo -H -u ${account.username} bash -c 'securesign-canary init -a ${args[0]}'`); - if (!init.replace(/^\s+|\s+$/g, '').endsWith('Initialization sequence completed.')) throw new Error(`Account initialization did not complete successfully:\n${init}`); - await this.client.db.Account.updateOne({ userID: message.author.id }, { $set: { hash: true } }); - return msg.edit(`${this.client.stores.emojis.success} ***Account initialized***`); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} +import { Message, PrivateChannel, TextChannel } from 'eris'; +import axios, { AxiosResponse } from 'axios'; +import { Client } from '..'; +import { Command } from '../class'; + +export default class SecureSign_Init extends Command { + constructor(client: Client) { + super(client); + this.name = 'init'; + this.description = 'Inits configuration files and environment variables (DM only)'; + this.usage = `${this.client.config.prefix}securesign init [hash]`; + this.enabled = true; + this.guildOnly = false; + } + + public async run(message: Message, args: string[]) { + try { + if (!args[0]) return this.client.commands.get('help').run(message, ['securesign', this.name]); + if (!(message.channel instanceof PrivateChannel)) { + message.delete(); + return message.channel.createMessage(`${this.client.stores.emojis.error} ***Run this command in your DMs!***`); + } + const account = await this.client.db.Account.findOne({ userID: message.author.id }); + if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not registered***`); + if (account.locked) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Your account is locked***`); + const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Initializing account...***`); + let verify: AxiosResponse; + try { + verify = await axios({ + method: 'get', + url: 'https://api.securesign.org/account/details', + headers: { Authorization: args[0] }, + }); + } catch (error) { + const { status } = error.response; + if (status === 400 || status === 401 || status === 403 || status === 404) return msg.edit(`${this.client.stores.emojis.error} ***Credentials incorrect***`); + throw error; + } + const { id } = verify.data.message; + if (id !== message.author.id && !account.root) { + const channel = this.client.guilds.get('446067825673633794').channels.get('501089664040697858') as TextChannel; + channel.createMessage(`**__UNAUTHORIZED ACCESS ALERT__**\n${message.author.mention} tried to initialize their account using <@${id}>'s SecureSign credentials.\nTheir account has been locked under Section 5.2 of the EULA.`); + const tasks = [this.client.util.exec(`lock ${account.username}`), account.updateOne({ locked: true }), this.client.util.createModerationLog(account.userID, this.client.user, 2, 'Violation of Section 5.2 of the EULA')]; + await Promise.all(tasks); + return msg.edit(`${this.client.stores.emojis.error} ***Credentials incorrect***`); + } + const init = await this.client.util.exec(`sudo -H -u ${account.username} bash -c 'securesign-canary init -a ${args[0]}'`); + if (!init.replace(/^\s+|\s+$/g, '').endsWith('Initialization sequence completed.')) throw new Error(`Account initialization did not complete successfully:\n${init}`); + await this.client.db.Account.updateOne({ userID: message.author.id }, { $set: { hash: true } }); + return msg.edit(`${this.client.stores.emojis.success} ***Account initialized***`); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/sysinfo.ts b/src/commands/sysinfo.ts index 3f880a2..8925cae 100644 --- a/src/commands/sysinfo.ts +++ b/src/commands/sysinfo.ts @@ -1,36 +1,35 @@ -import moment from 'moment'; -import { Message } from 'eris'; -import os, { totalmem } from 'os'; -import { Command, RichEmbed } from '../class'; -import { dataConversion } from '../functions'; -import { Client } from '..'; - -export default class SysInfo extends Command { - constructor(client: Client) { - super(client); - this.name = 'sysinfo'; - this.description = 'Provides system information.'; - this.enabled = true; - } - - public async run(message: Message) { - const availableMemory: string = await this.client.util.exec('free -b'); - const usedMemory = dataConversion(totalmem() - Number(availableMemory.split('\n')[1].split(' ').slice(-1)[0])); - const date = new Date(); - date.setMilliseconds(-(moment.duration(os.uptime(), 's').asMilliseconds())); - - const embed = new RichEmbed(); - embed.setTitle('System Information & Statistics'); - embed.addField('Hostname', os.hostname(), true); - embed.addField('Uptime', `${moment.duration(os.uptime(), 's').humanize()} | Last restart was on ${moment(date).format('dddd, MMMM Do YYYY, h:mm:ss A')} EST`, true); - embed.addField('CPU', `${os.cpus()[0].model} ${os.cpus()[0].speed / 1000}GHz | ${os.cpus().length} Cores | ${os.arch()}`, true); - embed.addField('Load Average (last 15 minutes)', os.loadavg()[2].toFixed(3), true); - embed.addField('Memory/RAM', `${usedMemory} / ${dataConversion(totalmem())}`, true); - embed.addField('Network Interfaces (IPv4)', os.networkInterfaces().eth0.filter((r) => r.family === 'IPv4')[0].address, true); - embed.addField('Network Interfaces (IPv6)', os.networkInterfaces().eth0.filter((r) => r.family === 'IPv6')[0].address.replace(/:/gi, '\:'), true); // eslint-disable-line - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - embed.setTimestamp(); - // @ts-ignore - message.channel.createMessage({ embed }); - } -} +import moment from 'moment'; +import { Message } from 'eris'; +import os, { totalmem } from 'os'; +import { Command, RichEmbed } from '../class'; +import { dataConversion } from '../functions'; +import { Client } from '..'; + +export default class SysInfo extends Command { + constructor(client: Client) { + super(client); + this.name = 'sysinfo'; + this.description = 'Provides system information.'; + this.enabled = true; + } + + public async run(message: Message) { + const availableMemory: string = await this.client.util.exec('free -b'); + const usedMemory = dataConversion(totalmem() - Number(availableMemory.split('\n')[1].split(' ').slice(-1)[0])); + const date = new Date(); + date.setMilliseconds(-(moment.duration(os.uptime(), 's').asMilliseconds())); + + const embed = new RichEmbed(); + embed.setTitle('System Information & Statistics'); + embed.addField('Hostname', os.hostname(), true); + embed.addField('Uptime', `${moment.duration(os.uptime(), 's').humanize()} | Last restart was on ${moment(date).format('dddd, MMMM Do YYYY, h:mm:ss A')} EST`, true); + embed.addField('CPU', `${os.cpus()[0].model} ${os.cpus()[0].speed / 1000}GHz | ${os.cpus().length} Cores | ${os.arch()}`, true); + embed.addField('Load Average (last 15 minutes)', os.loadavg()[2].toFixed(3), true); + embed.addField('Memory/RAM', `${usedMemory} / ${dataConversion(totalmem())}`, true); + embed.addField('Network Interfaces (IPv4)', os.networkInterfaces().eth0.filter((r) => r.family === 'IPv4')[0].address, true); + embed.addField('Network Interfaces (IPv6)', os.networkInterfaces().eth0.filter((r) => r.family === 'IPv6')[0].address.replace(/:/gi, '\:'), true); // eslint-disable-line + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + embed.setTimestamp(); + message.channel.createMessage({ embed }); + } +} diff --git a/src/commands/whois.ts b/src/commands/whois.ts index 58082cb..07f3004 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -1,64 +1,63 @@ -/* eslint-disable consistent-return */ -import moment from 'moment'; -import { Message } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; -import { dataConversion } from '../functions'; -import User from './whois_user'; - -export default class Whois extends Command { - constructor(client: Client) { - super(client); - this.name = 'whois'; - this.description = 'Views information for a cloud account.'; - this.aliases = ['account', 'user']; - this.usage = `${this.client.config.prefix}account [User Name | User ID | Email Address]`; - this.permissions = { roles: ['446104438969466890'] }; - this.subcmds = [User]; - this.enabled = true; - } - - public async run(message: Message, args: string[]) { - try { - if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); - const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }, { emailAddress: args[0] }] }); - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found.***`); - const embed = new RichEmbed(); - embed.setTitle('Account Information'); - if (this.client.users.get(account.userID)) embed.setThumbnail(this.client.users.get(account.userID).avatarURL); - embed.setColor(0x36393f); - let fingerInformation: string; - const result = await this.client.util.exec(`finger ${account.username}`); - if (message.member && !message.member.roles.includes('143414786913206272')) { - fingerInformation = result.replace(/((^\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, '[MASKED IP ADDRESS]'); - } else { - fingerInformation = result; - } - embed.setDescription(`${fingerInformation}\n${await this.client.util.exec(`chage -l ${account.username}`)}`); - embed.addField('Username', `${account.username} | <@${account.userID}>`, true); - embed.addField('ID', account.userID, true); - embed.addField('Email Address', account.emailAddress, true); - embed.addField('Created By', `<@${this.client.users.get(account.createdBy).id}>`, true); - embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); - const cpuUsage = await this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`); - embed.addField('CPU Usage', cpuUsage.split('\n')[0] ? `${cpuUsage.split('\n')[0]}%` : '0%', true); - embed.addField('Memory', dataConversion(Number(await this.client.util.exec(`memory ${account.username}`)) * 1000), true); - const data = await this.client.redis.get(`storage-${account.username}`) ? dataConversion(Number(await this.client.redis.get(`storage-${account.username}`))) : 'N/A'; - embed.addField('Storage', data, true); - let details = ''; - if (account.locked) details += 'This account is currently locked.\n'; - if (account.permissions.engineer) details += 'This account belongs to an Engineer.\n'; - else if (account.permissions.communityManager) details += 'This account belongs to a Community Manager.\n'; - else if (account.permissions.supervisor) details += 'This account belongs to a Supervisor.\n'; - else if (account.permissions.staff) details += 'This account belongs to a Staff member.\n'; - if (account.root) details += 'This account has root/administrative privileges.\n'; - if (details) embed.addField('Additional Details', details, true); - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - embed.setTimestamp(); - // @ts-ignore - message.channel.createMessage({ embed }); - } catch (error) { - await this.client.util.handleError(error, message, this); - } - } -} +/* eslint-disable consistent-return */ +import moment from 'moment'; +import { Message } from 'eris'; +import { Client } from '..'; +import { Command, RichEmbed } from '../class'; +import { dataConversion } from '../functions'; +import User from './whois_user'; + +export default class Whois extends Command { + constructor(client: Client) { + super(client); + this.name = 'whois'; + this.description = 'Views information for a cloud account.'; + this.aliases = ['account', 'user']; + this.usage = `${this.client.config.prefix}account [User Name | User ID | Email Address]`; + this.permissions = { roles: ['446104438969466890'] }; + this.subcmds = [User]; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); + const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }, { emailAddress: args[0] }] }); + if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found.***`); + const embed = new RichEmbed(); + embed.setTitle('Account Information'); + if (this.client.users.get(account.userID)) embed.setThumbnail(this.client.users.get(account.userID).avatarURL); + embed.setColor(0x36393f); + let fingerInformation: string; + const result = await this.client.util.exec(`finger ${account.username}`); + if (message.member && !message.member.roles.includes('143414786913206272')) { + fingerInformation = result.replace(/((^\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, '[MASKED IP ADDRESS]'); + } else { + fingerInformation = result; + } + embed.setDescription(`${fingerInformation}\n${await this.client.util.exec(`chage -l ${account.username}`)}`); + embed.addField('Username', `${account.username} | <@${account.userID}>`, true); + embed.addField('ID', account.userID, true); + embed.addField('Email Address', account.emailAddress, true); + embed.addField('Created By', `<@${this.client.users.get(account.createdBy).id}>`, true); + embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); + const cpuUsage = await this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`); + embed.addField('CPU Usage', cpuUsage.split('\n')[0] ? `${cpuUsage.split('\n')[0]}%` : '0%', true); + embed.addField('Memory', dataConversion(Number(await this.client.util.exec(`memory ${account.username}`)) * 1000), true); + const data = await this.client.redis.get(`storage-${account.username}`) ? dataConversion(Number(await this.client.redis.get(`storage-${account.username}`))) : 'N/A'; + embed.addField('Storage', data, true); + let details = ''; + if (account.locked) details += 'This account is currently locked.\n'; + if (account.permissions.engineer) details += 'This account belongs to an Engineer.\n'; + else if (account.permissions.communityManager) details += 'This account belongs to a Community Manager.\n'; + else if (account.permissions.supervisor) details += 'This account belongs to a Supervisor.\n'; + else if (account.permissions.staff) details += 'This account belongs to a Staff member.\n'; + if (account.root) details += 'This account has root/administrative privileges.\n'; + if (details) embed.addField('Additional Details', details, true); + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + embed.setTimestamp(); + message.channel.createMessage({ embed }); + } catch (error) { + await this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/whois_user.ts b/src/commands/whois_user.ts index a635a8c..cd152de 100644 --- a/src/commands/whois_user.ts +++ b/src/commands/whois_user.ts @@ -1,53 +1,52 @@ -/* eslint-disable consistent-return */ -import moment from 'moment'; -import { Message } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; -import { dataConversion } from '../functions'; -import { AccountInterface } from '../models'; - -export default class Whois_User extends Command { - constructor(client: Client) { - super(client); - this.name = 'user'; - this.description = 'Gets information about your account.'; - this.usage = `${this.client.config.prefix}whois user `; - this.enabled = true; - } - - public async run(message: Message, args: string[]) { - try { - let account: AccountInterface; - if (!args[0]) account = await this.client.db.Account.findOne({ userID: message.author.id }); - else account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }] }); - if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} You don't have an account.***`); - const embed = new RichEmbed(); - embed.setTitle('Account Information'); - if (this.client.users.get(account.userID)) embed.setThumbnail(this.client.users.get(account.userID).avatarURL); - embed.setColor(0x36393f); - embed.addField('Username', `${account.username} | <@${account.userID}>`, true); - embed.addField('ID', account.userID, true); - embed.addField('Created By', `<@${this.client.users.get(account.createdBy).id}>`, true); - embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); - const cpuUsage = await this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`); - embed.addField('CPU Usage', cpuUsage.split('\n')[0] ? `${cpuUsage.split('\n')[0]}%` : '0%', true); - embed.addField('Memory', dataConversion(Number(await this.client.util.exec(`memory ${account.username}`)) * 1000), true); - const data = await this.client.redis.get(`storage-${account.username}`) ? dataConversion(Number(await this.client.redis.get(`storage-${account.username}`))) : 'N/A'; - embed.addField('Storage', data, true); - let details = ''; - if (account.locked) details += 'This account is currently locked.\n'; - if (account.permissions.engineer) details += 'This account belongs to an Engineer.\n'; - else if (account.permissions.communityManager) details += 'This account belongs to a Community Manager.\n'; - else if (account.permissions.supervisor) details += 'This account belongs to a Supervisor.\n'; - else if (account.permissions.staff) details += 'This account belongs to a Staff member.\n'; - if (account.root) details += 'This account has root/administrative privileges.\n'; - if (details) embed.addField('Additional Details', details, true); - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - embed.setTimestamp(); - // @ts-ignore - message.channel.createMessage({ embed }); - } catch (error) { - this.client.util.handleError(error, message, this); - } - } -} +/* eslint-disable consistent-return */ +import moment from 'moment'; +import { Message } from 'eris'; +import { Client } from '..'; +import { Command, RichEmbed } from '../class'; +import { dataConversion } from '../functions'; +import { AccountInterface } from '../models'; + +export default class Whois_User extends Command { + constructor(client: Client) { + super(client); + this.name = 'user'; + this.description = 'Gets information about your account.'; + this.usage = `${this.client.config.prefix}whois user `; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + let account: AccountInterface; + if (!args[0]) account = await this.client.db.Account.findOne({ userID: message.author.id }); + else account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }] }); + if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} You don't have an account.***`); + const embed = new RichEmbed(); + embed.setTitle('Account Information'); + if (this.client.users.get(account.userID)) embed.setThumbnail(this.client.users.get(account.userID).avatarURL); + embed.setColor(0x36393f); + embed.addField('Username', `${account.username} | <@${account.userID}>`, true); + embed.addField('ID', account.userID, true); + embed.addField('Created By', `<@${this.client.users.get(account.createdBy).id}>`, true); + embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); + const cpuUsage = await this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`); + embed.addField('CPU Usage', cpuUsage.split('\n')[0] ? `${cpuUsage.split('\n')[0]}%` : '0%', true); + embed.addField('Memory', dataConversion(Number(await this.client.util.exec(`memory ${account.username}`)) * 1000), true); + const data = await this.client.redis.get(`storage-${account.username}`) ? dataConversion(Number(await this.client.redis.get(`storage-${account.username}`))) : 'N/A'; + embed.addField('Storage', data, true); + let details = ''; + if (account.locked) details += 'This account is currently locked.\n'; + if (account.permissions.engineer) details += 'This account belongs to an Engineer.\n'; + else if (account.permissions.communityManager) details += 'This account belongs to a Community Manager.\n'; + else if (account.permissions.supervisor) details += 'This account belongs to a Supervisor.\n'; + else if (account.permissions.staff) details += 'This account belongs to a Staff member.\n'; + if (account.root) details += 'This account has root/administrative privileges.\n'; + if (details) embed.addField('Additional Details', details, true); + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + embed.setTimestamp(); + message.channel.createMessage({ embed }); + } catch (error) { + this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/index.ts b/src/index.ts index 4d8c716..3f299c9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ -export { default as Client } from './Client'; -export { default as config } from './config.json'; -export { default as Classes } from './class'; -export { default as Commands } from './commands'; -export { default as Events } from './events'; -export { default as Models } from './models'; -export { default as Stores } from './stores'; +export { default as Client } from './Client'; +export { default as config } from './config.json'; +export * from './class'; +export * from './commands'; +export * from './events'; +export * from './models'; +export * from './stores'; diff --git a/tsconfig.json b/tsconfig.json index d97cc52..04f4976 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,64 +1,64 @@ -{ - "compilerOptions": { - /* Basic Options */ - // "incremental": true, /* Enable incremental compilation */ - "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'. */ - // "lib": [], /* Specify library files to be included in the compilation. */ - // "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - "declaration": false, /* Generates corresponding '.d.ts' file. */ - // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - // "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "./dist", /* Redirect output structure to the directory. */ - "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - // "composite": true, /* Enable project compilation */ - // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ - // "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'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - - /* Strict Type-Checking Options */ - "strict": false, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ - // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "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 */ - "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - "resolveJsonModule": true, - // "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'. */ - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* List of folders to include type definitions from. */ - // "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. */ - "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - - /* Source Map Options */ - // "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. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - - /* Experimental Options */ - // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - } -} +{ + "compilerOptions": { + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "ES2020", /* 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'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "declaration": false, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./dist", /* Redirect output structure to the directory. */ + "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "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'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": false, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "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 */ + "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + "resolveJsonModule": true, + // "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'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "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. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "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. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + } +} diff --git a/types/moment.d.ts b/types/moment.d.ts new file mode 100644 index 0000000..a90caea --- /dev/null +++ b/types/moment.d.ts @@ -0,0 +1,15 @@ +import moment from 'moment'; + +declare module 'moment' { + interface PreciseRangeValueObject extends moment.MomentObjectOutput { + firstDateWasLater: boolean; + } + + interface Moment { + preciseDiff(d2: moment.MomentInput, returnValueObject?: false): string; + preciseDiff(d2: moment.MomentInput, returnValueObject: true): PreciseRangeValueObject; + } + + function preciseDiff(d1: moment.MomentInput, d2: moment.MomentInput, returnValueObject?: false): string; + function preciseDiff(d1: moment.MomentInput, d2: moment.MomentInput, returnValueObject: true): PreciseRangeValueObject; +} -- 2.20.1 From d91d44e95d4c3e996ef2da7508a2edbfcd508674 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 14 Mar 2020 00:12:23 +0000 Subject: [PATCH 103/516] Remove verbose flags --- Makefile | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/Makefile b/Makefile index 6be4d86..5553d82 100644 --- a/Makefile +++ b/Makefile @@ -1,25 +1,25 @@ -# Builds TypeScript & Go - -check_certificate_files := $(wildcard src/go/checkCertificate/*.go) -check_certificate_signatures_files := $(wildcard src/go/checkCertSignatures/*.go) -storage_files := $(wildcard src/go/storage/*.go) - -all: check_certificate check_cert_signatures storage typescript - -check_certificate: - HOME=/root go build -v -ldflags="-s -w" -o dist/bin/checkCertificate ${check_certificate_files} - @chmod 740 dist/bin/checkCertificate - file dist/bin/checkCertificate - -check_cert_signatures: - HOME=/root go build -v -ldflags="-s -w" -o dist/bin/checkCertSignatures ${check_certificate_signatures_files} - @chmod 740 dist/bin/checkCertSignatures - file dist/bin/checkCertSignatures - -storage: - HOME=/root go build -v -ldflags="-s -w" -o dist/bin/storage ${storage_files} - @chmod 740 dist/bin/storage - file dist/bin/storage - -typescript: - tsc -p ./tsconfig.json +# Builds TypeScript & Go + +check_certificate_files := $(wildcard src/go/checkCertificate/*.go) +check_certificate_signatures_files := $(wildcard src/go/checkCertSignatures/*.go) +storage_files := $(wildcard src/go/storage/*.go) + +all: check_certificate check_cert_signatures storage typescript + +check_certificate: + HOME=/root go build -ldflags="-s -w" -o dist/bin/checkCertificate ${check_certificate_files} + @chmod 740 dist/bin/checkCertificate + file dist/bin/checkCertificate + +check_cert_signatures: + HOME=/root go build -ldflags="-s -w" -o dist/bin/checkCertSignatures ${check_certificate_signatures_files} + @chmod 740 dist/bin/checkCertSignatures + file dist/bin/checkCertSignatures + +storage: + HOME=/root go build -ldflags="-s -w" -o dist/bin/storage ${storage_files} + @chmod 740 dist/bin/storage + file dist/bin/storage + +typescript: + tsc -p ./tsconfig.json -- 2.20.1 From 755a176d13d20ce10983d471a9926351d58cb606 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sat, 14 Mar 2020 01:02:32 +0000 Subject: [PATCH 104/516] Fix building? --- package.json | 1 + types/global.d.ts | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 types/global.d.ts diff --git a/package.json b/package.json index c503294..57ed666 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "@types/ioredis": "^4.0.18", "@types/moment-precise-range-plugin": "^0.2.0", "@types/mongoose": "^5.5.20", + "@types/node": "^13.9.1", "@types/nodemailer": "^6.2.1", "@types/signale": "^1.2.1", "@types/uuid": "^3.4.5", diff --git a/types/global.d.ts b/types/global.d.ts new file mode 100644 index 0000000..04a9dd5 --- /dev/null +++ b/types/global.d.ts @@ -0,0 +1,31 @@ + +interface PromiseFulfilledResult { + status: 'fulfilled'; + value: T; +} + +interface PromiseRejectedResult { + status: 'rejected'; + reason: any; +} + +type PromiseSettledResult = PromiseFulfilledResult | PromiseRejectedResult; + +interface PromiseConstructor { + /** + * Creates a Promise that is resolved with an array of results when all + * of the provided Promises resolve or reject. + * @param values An array of Promises. + * @returns A new Promise. + */ + allSettled(values: T): + Promise<{ -readonly [P in keyof T]: PromiseSettledResult ? U : T[P]> }>; + + /** + * Creates a Promise that is resolved with an array of results when all + * of the provided Promises resolve or reject. + * @param values An array of Promises. + * @returns A new Promise. + */ + allSettled(values: Iterable): Promise ? U : T>[]>; +} -- 2.20.1 From 07d7ca79580b547abc047cbfbc3ec667b555fa4c Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 17 Mar 2020 01:17:46 -0400 Subject: [PATCH 105/516] package fixes --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 8a7d054..11d0f84 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,11 @@ "@ghaiklor/x509": "^1.0.0", "axios": "^0.19.0", "body-parser": "^1.19.0", - "eris": "abalabahaha/eris#dev", + "eris": "^0.11.2", "eris-pagination": "bsian03/eris-pagination", "express": "^4.17.1", "fs-extra": "^8.1.0", + "gocrypt": "^1.8.0", "helmet": "^3.21.2", "ioredis": "^4.14.1", "moment": "^2.24.0", -- 2.20.1 From 4c0d5cad32a75f218dac2d5eb697dac07ef42318 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 17 Mar 2020 01:35:43 -0400 Subject: [PATCH 106/516] boot fixes --- src/Client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Client.ts b/src/Client.ts index 97cfbb9..d3d0393 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -64,7 +64,7 @@ export default class Client extends Eris.Client { private async loadFunctions() { const functions = await fs.readdir('./functions'); functions.forEach(async (func) => { - if (func === 'index.ts' || func === 'index.js') return; + if (func === 'index.ts' || func === 'index.js' || func === 'dataConversion.js') return; try { (require(`./functions/${func}`).default)(this); } catch (error) { -- 2.20.1 From 8e7a641c7bbb40f892b6946a52e026c11a5d2068 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 17 Mar 2020 01:39:18 -0400 Subject: [PATCH 107/516] Changes to path location --- src/Client.ts | 4 ++-- src/commands/cwg_create.ts | 4 ++-- src/commands/cwg_updatecert.ts | 2 +- src/commands/exec.ts | 2 +- src/commands/load.ts | 2 +- src/commands/pull.ts | 6 +++--- src/intervals/storage.ts | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index d3d0393..9e1a074 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -119,8 +119,8 @@ export default class Client extends Eris.Client { }); this.server = new Server(this, { port: this.config.port }); - const corepath = '/var/CloudServices/dist'; - const cmdFiles = await fs.readdir('/var/CloudServices/dist/commands'); + const corepath = '/opt/CloudServices/dist'; + const cmdFiles = await fs.readdir('/opt/CloudServices/dist/commands'); cmdFiles.forEach((f) => delete require.cache[`${corepath}/${f}`]); delete require.cache[`${corepath}/config.json`]; delete require.cache[`${corepath}/class/Util`]; diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index fa738af..6966cd0 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -150,7 +150,7 @@ export default class CWG_Create extends Command { if (x509Certificate) { x509 = await this.createCertAndPrivateKey(domain, x509Certificate.cert, x509Certificate.key); } - let cfg = await fs.readFile('/var/CloudServices/dist/static/nginx.conf', { encoding: 'utf8' }); + let cfg = await fs.readFile('/opt/CloudServices/dist/static/nginx.conf', { encoding: 'utf8' }); cfg = cfg.replace(/\[DOMAIN]/g, domain); cfg = cfg.replace(/\[PORT]/g, String(port)); cfg = cfg.replace(/\[CERTIFICATE]/g, x509.cert); @@ -185,7 +185,7 @@ export default class CWG_Create extends Command { public async createCertAndPrivateKey(domain: string, certChain: string, privateKey: string) { if (!this.isValidCertificateChain(certChain)) throw new Error('Invalid Certificate Chain'); if (!this.isValidPrivateKey(privateKey)) throw new Error('Invalid Private Key'); - const path = `/var/CloudServices/temp/${domain}`; + const path = `/opt/CloudServices/temp/${domain}`; const temp = [writeFile(`${path}.chain.crt`, certChain), writeFile(`${path}.key.pem`, privateKey)]; const removeFiles = [unlink(`${path}.chain.crt`), unlink(`${path}.key.pem`)]; await Promise.all(temp); diff --git a/src/commands/cwg_updatecert.ts b/src/commands/cwg_updatecert.ts index aa11590..fa108e9 100644 --- a/src/commands/cwg_updatecert.ts +++ b/src/commands/cwg_updatecert.ts @@ -32,7 +32,7 @@ export default class CWG_UpdateCert extends Command { if (!this.isValidCertificateChain(certAndPrivateKey[0])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid Certificate Chain***`); if (!this.isValidPrivateKey(certAndPrivateKey[1])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid Private Key***`); - const path = `/var/CloudServices/temp/${account.id}`; + const path = `/opt/CloudServices/temp/${account.id}`; const temp = [writeFile(`${path}.chain.crt`, certAndPrivateKey[0]), writeFile(`${path}.key.pem`, certAndPrivateKey[1])]; const removeFiles = [unlink(`${path}.chain.crt`), unlink(`${path}.key.pem`)]; await Promise.all(temp); diff --git a/src/commands/exec.ts b/src/commands/exec.ts index 0a9cc2f..f286635 100644 --- a/src/commands/exec.ts +++ b/src/commands/exec.ts @@ -21,7 +21,7 @@ export default class Exec extends Command { const response = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Executing \`${args.join(' ')}\`***`); let result: string; try { - result = await this.client.util.exec(args.join(' '), { cwd: '/var/CloudServices' }); + result = await this.client.util.exec(args.join(' '), { cwd: '/opt/CloudServices' }); } catch (error) { result = error.message; } diff --git a/src/commands/load.ts b/src/commands/load.ts index 1c94df7..92ce2bd 100644 --- a/src/commands/load.ts +++ b/src/commands/load.ts @@ -19,7 +19,7 @@ export default class Load extends Command { const type = args[0].toLowerCase(); if (!allowed.includes(type)) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid type to (re)load***`); - const corepath = '/var/CloudServices/dist'; + const corepath = '/opt/CloudServices/dist'; if (type === 'config') { this.client.config = require(`${corepath}/config.json`); delete require.cache[`${corepath}/config.json`]; diff --git a/src/commands/pull.ts b/src/commands/pull.ts index 39d7920..cdd0fe7 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -20,7 +20,7 @@ export default class Pull extends Command { let pull: string; try { - pull = await this.client.util.exec('git pull', { cwd: '/var/CloudServices' }); + pull = await this.client.util.exec('git pull', { cwd: '/opt/CloudServices' }); } catch (error) { const updatedMessage = updateMessage.content.replace(`${this.client.stores.emojis.loading} ***Fetching latest commit...***`, `${this.client.stores.emojis.error} ***Could not fetch latest commit***`) .replace(/```$/, `${error.message}\n\`\`\``); @@ -46,7 +46,7 @@ export default class Pull extends Command { let install: string; try { - install = await this.client.util.exec('yarn install', { cwd: '/var/CloudServices' }); + install = await this.client.util.exec('yarn install', { cwd: '/opt/CloudServices' }); } catch (error) { this.client.updating = false; const updatedMessage = passedPull.content.replace(`${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`, `${this.client.stores.emojis.error} ***Failed to reinstall dependencies***`) @@ -71,7 +71,7 @@ export default class Pull extends Command { let build: string; try { - build = await this.client.util.exec('yarn run build', { cwd: '/var/CloudServices' }); + build = await this.client.util.exec('yarn run build', { cwd: '/opt/CloudServices' }); } catch (error) { const updatedMessage = updatedPackages.content.replace(`${this.client.stores.emojis.loading} ***Rebuilding files...***`, `${this.client.stores.emojis.error} ***Failed to rebuild files***`) .replace(/```$/, `${error.message}\n\`\`\``); diff --git a/src/intervals/storage.ts b/src/intervals/storage.ts index 2c1c503..ec81b7d 100644 --- a/src/intervals/storage.ts +++ b/src/intervals/storage.ts @@ -11,8 +11,8 @@ export default async function storage(client: Client) { const res = await client.util.exec(`du -bs /home/${account.username}`); let bytes = Number(res.split('/')[0].replace('\t', '')); try { - await fs.access(`/var/mail/${account.username}`, fs.constants.F_OK); - const res2 = await client.util.exec(`du -bs /var/mail/${account.username}`); + await fs.access(`/opt/mail/${account.username}`, fs.constants.F_OK); + const res2 = await client.util.exec(`du -bs /opt/mail/${account.username}`); bytes += Number(res2.split('/')[0].replace('\t', '')); } catch { bytes += 0; -- 2.20.1 From ff97b32d5d9f881cccbbca9876a759924bd8a1e3 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 23 Mar 2020 22:25:08 -0400 Subject: [PATCH 108/516] add tier to user upon account creation --- src/class/Util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index f37ba33..3dc58f6 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -150,7 +150,7 @@ export default class Util { await this.exec(`chage -d0 ${username}`); const account = new this.client.db.Account({ - username, userID, emailAddress, createdBy: moderatorID, createdAt: new Date(), locked: false, ssInit: false, homepath: `/home/${username}`, + username, userID, emailAddress, createdBy: moderatorID, createdAt: new Date(), locked: false, tier: 1, ssInit: false, homepath: `/home/${username}`, }); return account.save(); } -- 2.20.1 From 7d4ac0b479784d10557936794f25796dd8fb817d Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 23 Mar 2020 22:25:33 -0400 Subject: [PATCH 109/516] remove securesign link from account create command --- src/commands/createaccount.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/commands/createaccount.ts b/src/commands/createaccount.ts index 13598c4..8d7e6f6 100644 --- a/src/commands/createaccount.ts +++ b/src/commands/createaccount.ts @@ -85,7 +85,6 @@ export default class CreateAccount extends Command {
  • #cloud-info - Important information you will need to, or should, know to a certain extent. These include our infractions system and Tier limits
  • #cloud-support - A support channel specifically for the cloud machine, you can use this to ask how to renew your certificates, for example
  • Library of Code Support Desk - Our Support desk, you can contact Staff here.
  • -
  • SecureSign - our certificates manager
  • Want to support us?

    You can support us on Patreon! Head to our Patreon page and feel free to donate as much or as little as you want!
    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!

    -- 2.20.1 From 1371b0efdf7d1c4b025994c35902b3f692226c6b Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 23 Mar 2020 22:26:06 -0400 Subject: [PATCH 110/516] automatic hard enforcement for memory limits --- src/intervals/memory.ts | 73 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/intervals/memory.ts diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts new file mode 100644 index 0000000..56013ed --- /dev/null +++ b/src/intervals/memory.ts @@ -0,0 +1,73 @@ +/* eslint-disable no-await-in-loop */ +import { Client } from '..'; +import { RichEmbed } from '../class'; + +const channelID = '691824484230889546'; + +export const memoryLimits = { + TIER_1_SOFT: 250, + TIER_1_HARD: 300, + TIER_2_SOFT: 300, + TIER_2_HARD: 350, + TIER_3_SOFT: 450, + TIER_3_HARD: 500, +}; + +export default async function memory(client: Client) { + const accounts = await client.db.Account.find(); + for (const acc of accounts) { + if (acc.root) return; + // memory in bytes + const mem = Number(await client.util.exec(`memory ${acc.username}`)) * 1000; + // memory in megabytes + const memoryConversion = mem / 1024 / 1024; + let userLimits: { soft: number, hard: number }; + if (acc.tier === 1) { + userLimits = { soft: memoryLimits.TIER_1_SOFT, hard: memoryLimits.TIER_1_HARD }; + } else if (acc.tier === 2) { + userLimits = { soft: memoryLimits.TIER_2_SOFT, hard: memoryLimits.TIER_2_HARD }; + } else if (acc.tier === 3) { + userLimits = { soft: memoryLimits.TIER_3_SOFT, hard: memoryLimits.TIER_3_HARD }; + } + + /* if the user has exceeded their soft memory limit, which is the one described in the + resource limit guidelines, we'll inform staff. + */ + if (acc.tier === 1 && memoryConversion >= userLimits.soft) { + const embed = new RichEmbed(); + if (client.users.get(acc.userID)) embed.setThumbnail(client.users.get(acc.userID).avatarURL); + embed.addField('User', `${acc.username} | <@${acc.userID}> | ${acc.userID}`, true); + embed.addField('Tier', String(acc.tier), true); + embed.addField('Memory Usage', `${String(memoryConversion)} MB`, true); + embed.addField('Memory Limit', `${String(userLimits.soft)} MB`, true); + embed.setFooter(client.user.username, client.user.avatarURL); + embed.setTimestamp(); + + // if they exceed the hard limit, we'll kill all of their processes. + if (memoryConversion >= userLimits.hard) { + client.util.exec(`killall -9 -u ${acc.username}`); + 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.'); + client.util.createModerationLog(acc.userID, client.guilds.get('446067825673633794').members.get(client.user.id), 1, '[AUTO] Exceeded resource limit for RAM.'); + client.util.transport.sendMail({ + to: acc.emailAddress, + from: 'Library of Code sp-us | Cloud Services ', + subject: 'Your account has been warned', + html: ` +

    Library of Code sp-us | Cloud Services

    +

    Your account has received an official warning from a Moderator. Please get the underlying issue resolved to avoid possible moderative action.

    +

    Reason: [AUTO] Exceeded resource limit for RAM.

    +

    Moderator: ${client.user.username}

    + + Library of Code sp-us | Support Team + `, + }); + } else { + embed.setTitle('Resource Limit Notification'); + embed.setDescription('Someone has reached the (soft) resource limit for their tier on RAM.'); + } + // @ts-ignore + client.createMessage(channelID, { embed }); + } + } +} -- 2.20.1 From 2955aec793345eff668151a2017fd14f0382e353 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 23 Mar 2020 22:26:29 -0400 Subject: [PATCH 111/516] storage interval code cleanup --- src/intervals/storage.ts | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/intervals/storage.ts b/src/intervals/storage.ts index ec81b7d..488a578 100644 --- a/src/intervals/storage.ts +++ b/src/intervals/storage.ts @@ -4,27 +4,6 @@ import { spawn } from 'child_process'; import { Client } from '..'; export default async function storage(client: Client) { - /* const main = async () => { - const accounts = await client.db.Account.find(); - for (const account of accounts) { - setTimeout(async () => { - const res = await client.util.exec(`du -bs /home/${account.username}`); - let bytes = Number(res.split('/')[0].replace('\t', '')); - try { - await fs.access(`/opt/mail/${account.username}`, fs.constants.F_OK); - const res2 = await client.util.exec(`du -bs /opt/mail/${account.username}`); - bytes += Number(res2.split('/')[0].replace('\t', '')); - } catch { - bytes += 0; - } - await client.redis.set(`storage-${account.username}`, bytes); - }, 600000); - } - }; - await main(); - setInterval(async () => { - await main(); - }, 900000); */ let storageGo = spawn(`${__dirname}/../bin/storage`, [], { cwd: __dirname }); storageGo.stdout.on('data', (data) => client.signale.log(data.toString())); storageGo.stderr.on('data', (data) => client.signale.log(data.toString())); -- 2.20.1 From fbe50376309d43926c6c08a43a39bc3b190ea6a7 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 23 Mar 2020 22:26:42 -0400 Subject: [PATCH 112/516] add tier to Account model and interface --- src/models/Account.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/models/Account.ts b/src/models/Account.ts index 651d451..ab38d31 100644 --- a/src/models/Account.ts +++ b/src/models/Account.ts @@ -8,12 +8,11 @@ export interface AccountInterface extends Document { createdBy: string, createdAt: Date, locked: boolean, + tier: number; permissions: { - support: boolean, - staff: boolean, - supervisor: boolean, - communityManager: boolean, - engineer: boolean + associate: boolean, + sheriff: boolean, + facultyMarshal: boolean, }, root: boolean, hash: boolean, @@ -29,12 +28,11 @@ const Account: Schema = new Schema({ createdBy: String, createdAt: Date, locked: Boolean, + tier: Number, permissions: { - support: Boolean, - staff: Boolean, - supervisor: Boolean, - communityManager: Boolean, - engineer: Boolean, + associate: Boolean, + sheriff: Boolean, + facultyMarshal: Boolean, }, root: Boolean, hash: Boolean, -- 2.20.1 From 0a2ad6cddec76b6d66b1760e32b49305da9d19d0 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 23 Mar 2020 22:27:00 -0400 Subject: [PATCH 113/516] add tier information and perm cleanup for whois commands --- src/commands/whois.ts | 8 ++++---- src/commands/whois_user.ts | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/commands/whois.ts b/src/commands/whois.ts index 07f3004..7ea26a3 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -38,6 +38,7 @@ export default class Whois extends Command { embed.addField('Username', `${account.username} | <@${account.userID}>`, true); embed.addField('ID', account.userID, true); embed.addField('Email Address', account.emailAddress, true); + embed.addField('Tier', String(account.tier), true); embed.addField('Created By', `<@${this.client.users.get(account.createdBy).id}>`, true); embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); const cpuUsage = await this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`); @@ -47,10 +48,9 @@ export default class Whois extends Command { embed.addField('Storage', data, true); let details = ''; if (account.locked) details += 'This account is currently locked.\n'; - if (account.permissions.engineer) details += 'This account belongs to an Engineer.\n'; - else if (account.permissions.communityManager) details += 'This account belongs to a Community Manager.\n'; - else if (account.permissions.supervisor) details += 'This account belongs to a Supervisor.\n'; - else if (account.permissions.staff) details += 'This account belongs to a Staff member.\n'; + if (account.permissions.facultyMarshal) details += 'This account belongs to a Faculty Marshal.\n'; + else if (account.permissions.sheriff) details += 'This account belongs to a Sheriff.\n'; + else if (account.permissions.associate) details += 'This account belongs to a Staff member.\n'; if (account.root) details += 'This account has root/administrative privileges.\n'; if (details) embed.addField('Additional Details', details, true); embed.setFooter(this.client.user.username, this.client.user.avatarURL); diff --git a/src/commands/whois_user.ts b/src/commands/whois_user.ts index cd152de..2ed0ff9 100644 --- a/src/commands/whois_user.ts +++ b/src/commands/whois_user.ts @@ -27,6 +27,7 @@ export default class Whois_User extends Command { embed.setColor(0x36393f); embed.addField('Username', `${account.username} | <@${account.userID}>`, true); embed.addField('ID', account.userID, true); + embed.addField('Tier', String(account.tier), true); embed.addField('Created By', `<@${this.client.users.get(account.createdBy).id}>`, true); embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); const cpuUsage = await this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`); @@ -36,10 +37,9 @@ export default class Whois_User extends Command { embed.addField('Storage', data, true); let details = ''; if (account.locked) details += 'This account is currently locked.\n'; - if (account.permissions.engineer) details += 'This account belongs to an Engineer.\n'; - else if (account.permissions.communityManager) details += 'This account belongs to a Community Manager.\n'; - else if (account.permissions.supervisor) details += 'This account belongs to a Supervisor.\n'; - else if (account.permissions.staff) details += 'This account belongs to a Staff member.\n'; + if (account.permissions.facultyMarshal) details += 'This account belongs to a Faculty Marshal.\n'; + else if (account.permissions.sheriff) details += 'This account belongs to a Sheriff.\n'; + else if (account.permissions.associate) details += 'This account belongs to a Staff member.\n'; if (account.root) details += 'This account has root/administrative privileges.\n'; if (details) embed.addField('Additional Details', details, true); embed.setFooter(this.client.user.username, this.client.user.avatarURL); -- 2.20.1 From cae4c9c2cdd8948ff66dac8d0919eff65a178d50 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 04:56:38 -0400 Subject: [PATCH 114/516] disable all api routes temporarily --- src/api/routes/Account.ts | 2 +- src/api/routes/Root.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/routes/Account.ts b/src/api/routes/Account.ts index 8a10596..6f7920c 100644 --- a/src/api/routes/Account.ts +++ b/src/api/routes/Account.ts @@ -5,7 +5,7 @@ import { Req } from '../interfaces'; export default class Account extends Route { constructor(server: Server) { - super(server, { path: '/account', deprecated: false }); + super(server, { path: '/account', deprecated: false, maintenance: true }); } public bind() { diff --git a/src/api/routes/Root.ts b/src/api/routes/Root.ts index a1e5766..41f8466 100644 --- a/src/api/routes/Root.ts +++ b/src/api/routes/Root.ts @@ -4,7 +4,7 @@ import { Route } from '../../class'; export default class Root extends Route { constructor(server: Server) { - super(server, { path: '/', deprecated: false }); + super(server, { path: '/', deprecated: false, maintenance: true }); } public bind() { -- 2.20.1 From cf465b01c8f440cecf256c976b5fa14ea0914836 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 04:57:08 -0400 Subject: [PATCH 115/516] add account utilities class and rework of util class --- src/class/AccountUtil.ts | 73 ++++++++++++++++++++++++++++++++++++++++ src/class/Util.ts | 8 +++-- src/class/index.ts | 1 + 3 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 src/class/AccountUtil.ts diff --git a/src/class/AccountUtil.ts b/src/class/AccountUtil.ts new file mode 100644 index 0000000..cac764a --- /dev/null +++ b/src/class/AccountUtil.ts @@ -0,0 +1,73 @@ +import { AccountInterface } from '../models'; +import { Client } from '..'; + +export default class AccountUtil { + public client: Client; + + constructor(client: Client) { + this.client = client; + } + + /** + * This function creates a new user account. + * @param data Data/information on the new user account to create. + * @param data.userID The Discord ID for the user. + * @param data.username The username for the new user, this will also be their username on the machine. + * @param data.emailAddress The user's email address. + * @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 }> { + const moderatorMember = this.client.guilds.get('446067825673633794').members.get(moderator); + const tempPass = this.client.util.randomPassword(); + let passHash = await this.client.util.createHash(tempPass); passHash = passHash.replace(/[$]/g, '\\$').replace('\n', ''); + const acctName = this.client.users.get(data.userID).username.replace(/[!@#$%^&*(),.?":{}|<>]/g, '-').replace(/\s/g, '-'); + const etcPasswd = `${acctName},${data.userID},,`; + + const accountInterface = await this.client.util.createAccount(passHash, etcPasswd, data.username, data.userID, data.emailAddress, moderator); + await this.client.util.createModerationLog(data.userID, moderatorMember, 0); + + this.client.util.transport.sendMail({ + to: data.emailAddress, + from: 'Library of Code sp-us | Cloud Services ', + subject: 'Your account has been created', + html: ` + + +

    Library of Code | Cloud Services

    +

    Your Cloud Account has been created, welcome! Please see below for some details regarding your account and our services

    +

    Username: ${data.username}

    +

    SSH Login:

    ssh ${data.username}@cloud.libraryofcode.org
    +

    Useful information

    +

    How to log in:

    +
      +
    1. Open your desired terminal application - we recommend using Bash, but you can use your computer's default
    2. +
    3. Type in your SSH Login as above
    4. +
    5. When prompted, enter your password Please note that inputs will be blank, so be careful not to type in your password incorrectly
    6. +
    +

    If you fail to authenticate yourself too many times, you will be IP banned and will fail to connect. If this is the case, feel free to DM Ramirez with your public IPv4 address. + +

    Channels and Links

    +
      +
    • #status - You can find the status of all our services, including the cloud machine, here
    • +
    • #cloud-announcements - Announcements regarding the cloud machine will be here. These include planned maintenance, updates to preinstalled services etc.
    • +
    • #cloud-info - Important information you will need to, or should, know to a certain extent. These include our infractions system and Tier limits
    • +
    • #cloud-support - A support channel specifically for the cloud machine, you can use this to ask how to renew your certificates, for example
    • +
    • Library of Code Support Desk - Our Support desk, you can contact Staff here.
    • +
    +

    Want to support us?

    +

    You can support us on Patreon! Head to our Patreon page and feel free to donate as much or as little as you want!
    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!

    + Library of Code sp-us | Support Team + + `, + }); + + const dmChannel = await this.client.getDMChannel(data.userID).catch(); + dmChannel.createMessage('<: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` + + `You will be asked to change your password, \`(current) UNIX password\` is \`${tempPass}\`, then create a password that is at least 12 characters long, with at least one number, special character, and an uppercase letter\n` + + 'Bear in mind that when you enter your password, it will be blank, so be careful not to type in your password incorrectly.\n' + + 'You may now return to Modmail, and continue setting up your account from there.\n\n' + + 'An email containing some useful information has also been sent').catch(); + return { account: accountInterface, tempPass }; + } +} diff --git a/src/class/Util.ts b/src/class/Util.ts index 3dc58f6..19ed57f 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -6,14 +6,15 @@ import { Message, PrivateChannel, GroupChannel, Member, User } from 'eris'; import uuid from 'uuid/v4'; import moment from 'moment'; import fs from 'fs'; -import os from 'os'; import { Client } from '..'; -import { Command, RichEmbed } from '.'; -import { ModerationInterface, AccountInterface } from '../models'; +import { AccountUtil, Command, RichEmbed } from '.'; +import { ModerationInterface, AccountInterface, Account } from '../models'; export default class Util { public client: Client; + public accounts: AccountUtil; + public transport: nodemailer.Transporter; constructor(client: Client) { @@ -22,6 +23,7 @@ export default class Util { host: 'staff.libraryofcode.org', auth: { user: 'support', pass: this.client.config.emailPass }, }); + this.accounts = new AccountUtil(client); } /** diff --git a/src/class/index.ts b/src/class/index.ts index a85412e..a2744c7 100644 --- a/src/class/index.ts +++ b/src/class/index.ts @@ -1,3 +1,4 @@ +export { default as AccountUtil } from './AccountUtil'; export { default as Command } from './Command'; export { default as RichEmbed } from './RichEmbed'; export { default as Util } from './Util'; -- 2.20.1 From c77c2f57023cdd9c6ca5f1028a86ade8b1be8693 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 04:57:24 -0400 Subject: [PATCH 116/516] have createaccount cmd use account utils instance --- src/commands/createaccount.ts | 66 ++--------------------------------- 1 file changed, 2 insertions(+), 64 deletions(-) diff --git a/src/commands/createaccount.ts b/src/commands/createaccount.ts index 8d7e6f6..9e6997f 100644 --- a/src/commands/createaccount.ts +++ b/src/commands/createaccount.ts @@ -37,71 +37,9 @@ export default class CreateAccount extends Command { if (!/^[a-z][-a-z0-9]*$/.test(args[2])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid username supplied***`); const confirmation = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Creating account...***`); + const data = await this.client.util.accounts.createAccount({ userID: args[0], username: args[2], emailAddress: args[1] }, message.author.id); - const tempPass = this.client.util.randomPassword(); - let passHash = await this.client.util.createHash(tempPass); passHash = passHash.replace(/[$]/g, '\\$').replace('\n', ''); - const acctName = this.client.users.get(args[0]).username.replace(/[!@#$%^&*(),.?":{}|<>]/g, '-').replace(/\s/g, '-'); - const etcPasswd = `${acctName},${args[0]},,`; - - await this.client.util.createAccount(passHash, etcPasswd, args[2], args[0], args[1], message.author.id); - await this.client.util.createModerationLog(args[0], message.member, 0); - - this.client.util.transport.sendMail({ - to: args[1], - from: 'Library of Code sp-us | Cloud Services ', - subject: 'Your account has been created', - html: ` - - -

    Library of Code | Cloud Services

    -

    Your Cloud Account has been created, welcome! Please see below for some details regarding your account and our services

    -

    Username: ${args[2]}

    -

    SSH Login:

    ssh ${args[2]}@cloud.libraryofcode.org
    -

    Email address (see below for further information): ${args[2]}@cloud.libraryofcode.org

    -

    Useful information

    -

    How to log in:

    -
      -
    1. Open your desired terminal application - we recommend using Bash, but you can use your computer's default
    2. -
    3. Type in your SSH Login as above
    4. -
    5. When prompted, enter your password Please note that inputs will be blank, so be careful not to type in your password incorrectly
    6. -
    -

    If you fail to authenticate yourself too many times, you will be IP banned and will fail to connect. If this is the case, feel free to DM Ramirez with your public IPv4 address. - -

    Setting up your cloud email

    -

    All email applications are different, so here are some information you can use to connect your email

    -
      -
    • Server: cloud.libraryofcode.org
    • -
    • Account username/password: Normal login
    • -
    • Account type (incoming): IMAP
    • -
    • Incoming port: 143 (993 if you're using TLS security type)
    • -
    • Incoming Security Type: STARTTLS (TLS if you're using port 993)
    • -
    • Outgoing port: 587 (If that doesn't work, try 25)
    • -
    • Outgoing Security Type: STARTTLS
    • -
    -

    Channels and Links

    -
      -
    • #status - You can find the status of all our services, including the cloud machine, here
    • -
    • #cloud-announcements - Announcements regarding the cloud machine will be here. These include planned maintenance, updates to preinstalled services etc.
    • -
    • #cloud-info - Important information you will need to, or should, know to a certain extent. These include our infractions system and Tier limits
    • -
    • #cloud-support - A support channel specifically for the cloud machine, you can use this to ask how to renew your certificates, for example
    • -
    • Library of Code Support Desk - Our Support desk, you can contact Staff here.
    • -
    -

    Want to support us?

    -

    You can support us on Patreon! Head to our Patreon page and feel free to donate as much or as little as you want!
    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!

    - Library of Code sp-us | Support Team - - `, - }); - - const dmChannel = await this.client.getDMChannel(args[0]).catch(); - dmChannel.createMessage('<:loc:607695848612167700> **Thank you for creating an account with us!** <:loc:607695848612167700>\n' - + `Please log into your account by running \`ssh ${args[2]}@cloud.libraryofcode.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` - + 'Bear in mind that when you enter your password, it will be blank, so be careful not to type in your password incorrectly.\n' - + 'You may now return to Modmail, and continue setting up your account from there.\n\n' - + 'An email containing some useful information has also been sent').catch(); - - return confirmation.edit(`${this.client.stores.emojis.success} ***Account successfully created***\n**Username:** \`${args[2]}\`\n**Temporary Password:** \`${tempPass}\``); + return confirmation.edit(`${this.client.stores.emojis.success} ***Account successfully created***\n**Username:** \`${args[2]}\`\n**Temporary Password:** \`${data.tempPass}\``); } catch (error) { return this.client.util.handleError(error, message, this); } -- 2.20.1 From 2af97851e114d9d612a1fb90a5d8a4a8a9a4d71f Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 04:57:40 -0400 Subject: [PATCH 117/516] no idea whats happening but i object --- src/commands/cwg_create.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index 6966cd0..8a5a8a1 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -34,7 +34,7 @@ export default class CWG_Create extends Command { let certs: { cert: string, key: string }; if (!this.urlRegex.test(args[1])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid URL***`); - if (Number(args[2]) < 1024 || Number(args[2]) > 65535) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Port must be greater than 1024 and less than 65535***`); + if (Number(args[2]) <= 1024 || Number(args[2]) >= 65535) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Port must be greater than 1024 and less than 65535***`); if (!args[1].endsWith('.cloud.libraryofcode.org') && !args[4]) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Certificate Chain and Private Key are required for custom domains***`); const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }] }); @@ -74,7 +74,7 @@ export default class CWG_Create extends Command { const domain = await this.createDomain(account, args[1], Number(args[2]), certs); - const tasks = [message.delete(), this.client.util.exec('systemctl reload')]; + const tasks = [message.delete(), this.client.util.exec('systemctl reload nginx')]; // @ts-ignore await Promise.all(tasks); @@ -149,6 +149,11 @@ export default class CWG_Create extends Command { let x509: { cert: string, key: string }; if (x509Certificate) { x509 = await this.createCertAndPrivateKey(domain, x509Certificate.cert, x509Certificate.key); + } else { + x509 = { + cert: '/etc/ssl/private/cloud-libraryofcode-org.chain.crt', + key: '/etc/ssl/private/cloud-libraryofcode-org.key', + }; } let cfg = await fs.readFile('/opt/CloudServices/dist/static/nginx.conf', { encoding: 'utf8' }); cfg = cfg.replace(/\[DOMAIN]/g, domain); -- 2.20.1 From 2f2d6d823c3f01bdd4cca3f2f0769ba44ddc4d66 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 04:57:59 -0400 Subject: [PATCH 118/516] disable parse commands --- src/commands/parse.ts | 1 + src/commands/parseall.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/commands/parse.ts b/src/commands/parse.ts index f23f682..b7df469 100644 --- a/src/commands/parse.ts +++ b/src/commands/parse.ts @@ -12,6 +12,7 @@ export default class Parse extends Command { this.description = 'Gets information on a user\'s x509 certificate.'; this.usage = `${this.client.config.prefix}parse [username || user ID]`; this.permissions = { roles: ['446104438969466890'] }; + this.enabled = false; } public async run(message: Message, args: string[]) { // eslint-disable-line diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts index 7e1164a..d4ecc18 100644 --- a/src/commands/parseall.ts +++ b/src/commands/parseall.ts @@ -16,6 +16,7 @@ export default class Parseall extends Command { this.usage = `${this.client.config.prefix}parseall`; this.permissions = { roles: ['446104438969466890'] }; this.aliases = ['checkcerts', 'verifyall', 'verifycerts']; + this.enabled = false; } public async run(message: Message, args: string[]) { -- 2.20.1 From 3f7ead1db458288a03a7342191538fc70ef1ef15 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 04:58:14 -0400 Subject: [PATCH 119/516] disable all securesign commands --- src/commands/securesign.ts | 2 +- src/commands/securesign_activatekey.ts | 2 +- src/commands/securesign_alliance.ts | 2 +- src/commands/securesign_build.ts | 2 +- src/commands/securesign_createcrt.ts | 2 +- src/commands/securesign_init.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/commands/securesign.ts b/src/commands/securesign.ts index 6b7dfbe..a0bbfc7 100644 --- a/src/commands/securesign.ts +++ b/src/commands/securesign.ts @@ -16,7 +16,7 @@ export default class SecureSign extends Command { this.usage = `Run ${this.client.config.prefix}${this.name} [subcommand] for usage information`; this.aliases = ['ss']; this.subcmds = [Build, Init, Account, ActivateKey, CreateCrt, Alliace]; - this.enabled = true; + this.enabled = false; } public async run(message: Message) { diff --git a/src/commands/securesign_activatekey.ts b/src/commands/securesign_activatekey.ts index fc99504..2d1bcd0 100644 --- a/src/commands/securesign_activatekey.ts +++ b/src/commands/securesign_activatekey.ts @@ -9,7 +9,7 @@ export default class SecureSign_ActivateKey extends Command { this.name = 'activatekey'; this.description = 'Claims an Activation Key'; this.usage = `${this.client.config.prefix}securesign activatekey [key]`; - this.enabled = true; + this.enabled = false; } public async run(message: Message, args: string[]) { diff --git a/src/commands/securesign_alliance.ts b/src/commands/securesign_alliance.ts index cc54c10..ca509c5 100644 --- a/src/commands/securesign_alliance.ts +++ b/src/commands/securesign_alliance.ts @@ -10,7 +10,7 @@ export default class SecureSign_Alliance extends Command { this.name = 'alliance'; this.description = 'Claims an alliance/promo key'; this.usage = `${this.client.config.prefix}securesign alliance [key]`; - this.enabled = true; + this.enabled = false; this.guildOnly = false; } diff --git a/src/commands/securesign_build.ts b/src/commands/securesign_build.ts index 48f5d2a..fd8665b 100644 --- a/src/commands/securesign_build.ts +++ b/src/commands/securesign_build.ts @@ -8,7 +8,7 @@ export default class SecureSign_Build extends Command { this.name = 'build'; this.description = 'Shows information about the current build of the CLI'; this.usage = `${this.client.config.prefix}securesign build`; - this.enabled = true; + this.enabled = false; } public async run(message: Message, args: string[]) { diff --git a/src/commands/securesign_createcrt.ts b/src/commands/securesign_createcrt.ts index 85052db..655921b 100644 --- a/src/commands/securesign_createcrt.ts +++ b/src/commands/securesign_createcrt.ts @@ -9,7 +9,7 @@ export default class SecureSign_Init extends Command { this.name = 'createcrt'; this.description = 'Creates a new certificate'; this.usage = `${this.client.config.prefix}securesign createcrt [-s sign] [-c class] [-m digest]\n\`sign\`: Sign type (ecc/rsa)\n\`class\`: Certificate Class (1/2/3)\n\`digest\`: SHA Digest (256/384/512)`; - this.enabled = true; + this.enabled = false; this.guildOnly = false; } diff --git a/src/commands/securesign_init.ts b/src/commands/securesign_init.ts index ecaacb3..199acf3 100644 --- a/src/commands/securesign_init.ts +++ b/src/commands/securesign_init.ts @@ -9,7 +9,7 @@ export default class SecureSign_Init extends Command { this.name = 'init'; this.description = 'Inits configuration files and environment variables (DM only)'; this.usage = `${this.client.config.prefix}securesign init [hash]`; - this.enabled = true; + this.enabled = false; this.guildOnly = false; } -- 2.20.1 From ffa3d24f8992c2f85dc9bf9d992ab82cb8bd5294 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 04:59:23 -0400 Subject: [PATCH 120/516] disable checkSS interval function --- src/functions/checkSS.ts | 3 +++ src/functions/index.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/functions/checkSS.ts b/src/functions/checkSS.ts index e6ed824..39cee9d 100644 --- a/src/functions/checkSS.ts +++ b/src/functions/checkSS.ts @@ -1,3 +1,5 @@ +/* eslint-disable consistent-return */ +/* eslint-disable no-unreachable */ /* eslint-disable no-await-in-loop */ import axios from 'axios'; import { inspect } from 'util'; @@ -5,6 +7,7 @@ import { Client } from '..'; let interval: NodeJS.Timeout; export default function checkSS(client: Client) { + return; interval = setInterval(async () => { try { const accounts = await client.db.Account.find(); diff --git a/src/functions/index.ts b/src/functions/index.ts index a349b65..6afeb0e 100644 --- a/src/functions/index.ts +++ b/src/functions/index.ts @@ -1,4 +1,4 @@ export { default as checkLock, clear as clearLock } from './checkLock'; export { default as dataConversion } from './dataConversion'; -export { default as checkSS, clear as clearSS } from './checkSS'; +// export { default as checkSS, clear as clearSS } from './checkSS'; export { default as parseCertificate, Certificate } from './parseCertificate'; -- 2.20.1 From 00e76a6b6922f59c1567b6cada16e641033ec7f2 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 05:08:11 -0400 Subject: [PATCH 121/516] roll back to ES2017 --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 04f4976..131a1cb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "ES2020", /* 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'. */ // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ -- 2.20.1 From 449d61fd5529ed3d6c84caf7b65030261a40c800 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 05:08:37 -0400 Subject: [PATCH 122/516] fixes --- src/commands/securesign_account.ts | 4 ++-- src/commands/securesign_createcrt.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/commands/securesign_account.ts b/src/commands/securesign_account.ts index 0ec1efc..26ea3f5 100644 --- a/src/commands/securesign_account.ts +++ b/src/commands/securesign_account.ts @@ -16,10 +16,10 @@ export default class SecureSign_Account extends Command { public async run(message: Message, args: string[]) { try { const user = await this.client.db.Account.findOne({ userID: message.author.id }); - if (!user || (!user.permissions.staff && !(message.channel instanceof PrivateChannel))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Run this command in your DMs!***`); + if (!user || (!user.permissions.associate && !(message.channel instanceof PrivateChannel))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Run this command in your DMs!***`); let account: AccountInterface; - if (!args[0] || !user.permissions.staff) account = user; + if (!args[0] || !user.permissions.associate) account = user; else account = await this.client.db.Account.findOne({ $or: [{ userID: args[0] }, { username: args[0] }, { emailAddress: args[0] }] }); if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); diff --git a/src/commands/securesign_createcrt.ts b/src/commands/securesign_createcrt.ts index 655921b..9b34e0b 100644 --- a/src/commands/securesign_createcrt.ts +++ b/src/commands/securesign_createcrt.ts @@ -15,6 +15,7 @@ export default class SecureSign_Init extends Command { public async run(message: Message, args: string[]) { try { + return; const account = await this.client.db.Account.findOne({ userID: message.author.id }); if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); if (!account.hash) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not initialized***`); -- 2.20.1 From c3656ae4e8af34e1371d3ebf06669da5bb953fd2 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 11:22:36 -0400 Subject: [PATCH 123/516] rm gocrypt dep --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 11d0f84..2efef48 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,6 @@ "eris-pagination": "bsian03/eris-pagination", "express": "^4.17.1", "fs-extra": "^8.1.0", - "gocrypt": "^1.8.0", "helmet": "^3.21.2", "ioredis": "^4.14.1", "moment": "^2.24.0", -- 2.20.1 From da61fade27a004650bedde31cd509904bfccb8fc Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 11:28:07 -0400 Subject: [PATCH 124/516] change default shell to bash --- src/class/Util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index 19ed57f..28cb962 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -148,7 +148,7 @@ export default class Util { } public async createAccount(hash: string, etcPasswd: string, username: string, userID: string, emailAddress: string, moderatorID: string): Promise { - await this.exec(`useradd -m -p ${hash} -c ${etcPasswd} -s /bin/zsh ${username}`); + await this.exec(`useradd -m -p ${hash} -c ${etcPasswd} -s /bin/bash ${username}`); await this.exec(`chage -d0 ${username}`); const account = new this.client.db.Account({ -- 2.20.1 From b615178da685e48f252a391304a55db833f5f80a Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 11:32:51 -0400 Subject: [PATCH 125/516] fix issue on CI --- src/commands/cwg_delete.ts | 2 +- src/commands/cwg_updatecert.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/cwg_delete.ts b/src/commands/cwg_delete.ts index f142d10..53424c5 100644 --- a/src/commands/cwg_delete.ts +++ b/src/commands/cwg_delete.ts @@ -18,7 +18,7 @@ export default class CWG_Delete extends Command { public async run(message: Message, args: string[]) { try { if (!args[0]) return this.client.commands.get('help').run(message, ['cwg', this.name]); - const domain = await this.client.db.Domain.findOne({ $or: [{ domain: args[0] }, { port: Number(args[0]) || '' }] }); + const domain = await this.client.db.Domain.findOne({ $or: [{ domain: args[0] }, { port: Number(args[0]) || 0 }] }); if (!domain) return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Deleting domain...***`); const embed = new RichEmbed(); diff --git a/src/commands/cwg_updatecert.ts b/src/commands/cwg_updatecert.ts index fa108e9..6c58ed2 100644 --- a/src/commands/cwg_updatecert.ts +++ b/src/commands/cwg_updatecert.ts @@ -18,7 +18,7 @@ export default class CWG_UpdateCert extends Command { public async run(message: Message, args: string[]) { try { if (!args[2]) return this.client.commands.get('help').run(message, ['cwg', this.name]); - const dom = await this.client.db.Domain.findOne({ $or: [{ domain: args[0] }, { port: Number(args[0]) || '' }] }); + const dom = await this.client.db.Domain.findOne({ $or: [{ domain: args[0] }, { port: Number(args[0]) || 0 }] }); if (!dom) return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); const { domain, port, x509, account } = dom; const { cert, key } = x509; -- 2.20.1 From 11cf7db6c92c7110ee3c9a9bf75b0aafabd64702 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 11:37:01 -0400 Subject: [PATCH 126/516] tier memory updates --- src/intervals/memory.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 56013ed..1f96d20 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -5,12 +5,12 @@ import { RichEmbed } from '../class'; const channelID = '691824484230889546'; export const memoryLimits = { - TIER_1_SOFT: 250, - TIER_1_HARD: 300, - TIER_2_SOFT: 300, - TIER_2_HARD: 350, - TIER_3_SOFT: 450, - TIER_3_HARD: 500, + TIER_1_SOFT: 200, + TIER_1_HARD: 350, + TIER_2_SOFT: 350, + TIER_2_HARD: 400, + TIER_3_SOFT: 500, + TIER_3_HARD: 550, }; export default async function memory(client: Client) { -- 2.20.1 From 23afdcdf90f0f73593ed4e117e78ffca66bfb2db Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 12:10:09 -0400 Subject: [PATCH 127/516] sheriff perms to create accs --- src/commands/createaccount.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/createaccount.ts b/src/commands/createaccount.ts index 9e6997f..c345066 100644 --- a/src/commands/createaccount.ts +++ b/src/commands/createaccount.ts @@ -10,7 +10,7 @@ export default class CreateAccount extends Command { this.description = 'Create an account on the Cloud VM'; this.usage = `${this.client.config.prefix}createaccount [User ID] [Email] [Account name]`; this.aliases = ['createacc', 'cacc', 'caccount', 'create']; - this.permissions = { roles: ['662163685439045632'] }; + this.permissions = { roles: ['662163685439045632', '455972169449734144'] }; this.enabled = true; } -- 2.20.1 From febb9ee92444aa20bcc8cbcdb22e661e77104347 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 12:10:58 -0400 Subject: [PATCH 128/516] various fixes to account model and intervals --- src/commands/securesign_account.ts | 4 +- src/intervals/memory.ts | 112 +++++++++++++++-------------- src/models/Account.ts | 4 +- 3 files changed, 61 insertions(+), 59 deletions(-) diff --git a/src/commands/securesign_account.ts b/src/commands/securesign_account.ts index 26ea3f5..0ec1efc 100644 --- a/src/commands/securesign_account.ts +++ b/src/commands/securesign_account.ts @@ -16,10 +16,10 @@ export default class SecureSign_Account extends Command { public async run(message: Message, args: string[]) { try { const user = await this.client.db.Account.findOne({ userID: message.author.id }); - if (!user || (!user.permissions.associate && !(message.channel instanceof PrivateChannel))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Run this command in your DMs!***`); + if (!user || (!user.permissions.staff && !(message.channel instanceof PrivateChannel))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Run this command in your DMs!***`); let account: AccountInterface; - if (!args[0] || !user.permissions.associate) account = user; + if (!args[0] || !user.permissions.staff) account = user; else account = await this.client.db.Account.findOne({ $or: [{ userID: args[0] }, { username: args[0] }, { emailAddress: args[0] }] }); if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 1f96d20..87c5d60 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -13,61 +13,63 @@ export const memoryLimits = { TIER_3_HARD: 550, }; -export default async function memory(client: Client) { - const accounts = await client.db.Account.find(); - for (const acc of accounts) { - if (acc.root) return; - // memory in bytes - const mem = Number(await client.util.exec(`memory ${acc.username}`)) * 1000; - // memory in megabytes - const memoryConversion = mem / 1024 / 1024; - let userLimits: { soft: number, hard: number }; - if (acc.tier === 1) { - userLimits = { soft: memoryLimits.TIER_1_SOFT, hard: memoryLimits.TIER_1_HARD }; - } else if (acc.tier === 2) { - userLimits = { soft: memoryLimits.TIER_2_SOFT, hard: memoryLimits.TIER_2_HARD }; - } else if (acc.tier === 3) { - userLimits = { soft: memoryLimits.TIER_3_SOFT, hard: memoryLimits.TIER_3_HARD }; - } - - /* if the user has exceeded their soft memory limit, which is the one described in the - resource limit guidelines, we'll inform staff. - */ - if (acc.tier === 1 && memoryConversion >= userLimits.soft) { - const embed = new RichEmbed(); - if (client.users.get(acc.userID)) embed.setThumbnail(client.users.get(acc.userID).avatarURL); - embed.addField('User', `${acc.username} | <@${acc.userID}> | ${acc.userID}`, true); - embed.addField('Tier', String(acc.tier), true); - embed.addField('Memory Usage', `${String(memoryConversion)} MB`, true); - embed.addField('Memory Limit', `${String(userLimits.soft)} MB`, true); - embed.setFooter(client.user.username, client.user.avatarURL); - embed.setTimestamp(); - - // if they exceed the hard limit, we'll kill all of their processes. - if (memoryConversion >= userLimits.hard) { - client.util.exec(`killall -9 -u ${acc.username}`); - 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.'); - client.util.createModerationLog(acc.userID, client.guilds.get('446067825673633794').members.get(client.user.id), 1, '[AUTO] Exceeded resource limit for RAM.'); - client.util.transport.sendMail({ - to: acc.emailAddress, - from: 'Library of Code sp-us | Cloud Services ', - subject: 'Your account has been warned', - html: ` -

    Library of Code sp-us | Cloud Services

    -

    Your account has received an official warning from a Moderator. Please get the underlying issue resolved to avoid possible moderative action.

    -

    Reason: [AUTO] Exceeded resource limit for RAM.

    -

    Moderator: ${client.user.username}

    - - Library of Code sp-us | Support Team - `, - }); - } else { - embed.setTitle('Resource Limit Notification'); - embed.setDescription('Someone has reached the (soft) resource limit for their tier on RAM.'); +export default function memory(client: Client) { + setInterval(async () => { + const accounts = await client.db.Account.find(); + for (const acc of accounts) { + if (acc.root) return; + // memory in bytes + const mem = Number(await client.util.exec(`memory ${acc.username}`)) * 1000; + // memory in megabytes + const memoryConversion = mem / 1024 / 1024; + let userLimits: { soft: number, hard: number }; + if (acc.tier === 1) { + userLimits = { soft: memoryLimits.TIER_1_SOFT, hard: memoryLimits.TIER_1_HARD }; + } else if (acc.tier === 2) { + userLimits = { soft: memoryLimits.TIER_2_SOFT, hard: memoryLimits.TIER_2_HARD }; + } else if (acc.tier === 3) { + userLimits = { soft: memoryLimits.TIER_3_SOFT, hard: memoryLimits.TIER_3_HARD }; + } + + /* if the user has exceeded their soft memory limit, which is the one described in the + resource limit guidelines, we'll inform staff. + */ + if (acc.tier === 1 && memoryConversion >= userLimits.soft) { + const embed = new RichEmbed(); + if (client.users.get(acc.userID)) embed.setThumbnail(client.users.get(acc.userID).avatarURL); + embed.addField('User', `${acc.username} | <@${acc.userID}> | ${acc.userID}`, true); + embed.addField('Tier', String(acc.tier), true); + embed.addField('Memory Usage', `${String(memoryConversion)} MB`, true); + embed.addField('Memory Limit', `${String(userLimits.soft)} MB`, true); + embed.setFooter(client.user.username, client.user.avatarURL); + embed.setTimestamp(); + + // if they exceed the hard limit, we'll kill all of their processes. + if (memoryConversion >= userLimits.hard) { + client.util.exec(`killall -9 -u ${acc.username}`); + 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.'); + client.util.createModerationLog(acc.userID, client.guilds.get('446067825673633794').members.get(client.user.id), 1, '[AUTO] Exceeded resource limit for RAM.'); + client.util.transport.sendMail({ + to: acc.emailAddress, + from: 'Library of Code sp-us | Cloud Services ', + subject: 'Your account has been warned', + html: ` +

    Library of Code sp-us | Cloud Services

    +

    Your account has received an official warning from a Moderator. Please get the underlying issue resolved to avoid possible moderative action.

    +

    Reason: [AUTO] Exceeded resource limit for RAM.

    +

    Moderator: ${client.user.username}

    + + Library of Code sp-us | Support Team + `, + }); + } else { + embed.setTitle('Resource Limit Notification'); + embed.setDescription('Someone has reached the (soft) resource limit for their tier on RAM.'); + } + // @ts-ignore + client.createMessage(channelID, { embed }); } - // @ts-ignore - client.createMessage(channelID, { embed }); } - } + }, 300000); } diff --git a/src/models/Account.ts b/src/models/Account.ts index ab38d31..3f10dc2 100644 --- a/src/models/Account.ts +++ b/src/models/Account.ts @@ -10,7 +10,7 @@ export interface AccountInterface extends Document { locked: boolean, tier: number; permissions: { - associate: boolean, + staff: boolean, sheriff: boolean, facultyMarshal: boolean, }, @@ -30,7 +30,7 @@ const Account: Schema = new Schema({ locked: Boolean, tier: Number, permissions: { - associate: Boolean, + staff: Boolean, sheriff: Boolean, facultyMarshal: Boolean, }, -- 2.20.1 From 56a2b3eabf666970203bcbc5ac949b38f1930fae Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 12:11:16 -0400 Subject: [PATCH 129/516] add new interval which automatically updates permissions based on roles --- src/intervals/checkStaffStatus.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/intervals/checkStaffStatus.ts diff --git a/src/intervals/checkStaffStatus.ts b/src/intervals/checkStaffStatus.ts new file mode 100644 index 0000000..b34586c --- /dev/null +++ b/src/intervals/checkStaffStatus.ts @@ -0,0 +1,30 @@ +/* eslint-disable no-await-in-loop */ +import { Client } from '..'; + +export default function checkStaffStatus(client: Client) { + setInterval(async () => { + const accounts = await client.db.Account.find(); + for (const acc of accounts) { + const user = client.guilds.get('446067825673633794').members.get(acc.userID) ?? await client.guilds.get('446067825673633794').getRESTMember(acc.userID); + if (!acc.permissions.facultyMarshal && user.roles.includes('662163685439045632')) { + await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.facultyMarshal': true } }); + } + if (!acc.permissions.sheriff && user.roles.includes('455972169449734144')) { + await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.sheriff': true } }); + } + if (!acc.permissions.staff && user.roles.includes('446104438969466890')) { + await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.staff': true } }); + } + + if (acc.permissions.facultyMarshal && !user.roles.includes('662163685439045632')) { + await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.facultyMarshal': false } }); + } + if (acc.permissions.sheriff && !user.roles.includes('455972169449734144')) { + await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.sheriff': false } }); + } + if (acc.permissions.staff && !user.roles.includes('446104438969466890')) { + await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.staff': false } }); + } + } + }, 300000); +} -- 2.20.1 From 2f015b4e49cbfece0c02c4f9bca63672568593f4 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 12:14:39 -0400 Subject: [PATCH 130/516] add new interval which automatically updates permissions based on roles --- src/intervals/checkStaffStatus.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/intervals/checkStaffStatus.ts b/src/intervals/checkStaffStatus.ts index b34586c..bfff788 100644 --- a/src/intervals/checkStaffStatus.ts +++ b/src/intervals/checkStaffStatus.ts @@ -25,6 +25,13 @@ export default function checkStaffStatus(client: Client) { if (acc.permissions.staff && !user.roles.includes('446104438969466890')) { await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.staff': false } }); } + + if (acc.permissions.staff && acc.tier > 3) { + await client.db.Account.updateOne({ username: acc.username }, { $set: { tier: 3 } }); + client.getDMChannel(acc.userID).then((chan) => { + chan.createMessage('***Your account has automatically been upgraded to Tier 3 since you are a Staff member.***'); + }); + } } }, 300000); } -- 2.20.1 From c88d4cd9adf7c83ef1bc880e2003ec0597fe6135 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 12:15:00 -0400 Subject: [PATCH 131/516] various fixes to whois commands --- src/commands/whois.ts | 2 +- src/commands/whois_user.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/whois.ts b/src/commands/whois.ts index 7ea26a3..38109bf 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -50,7 +50,7 @@ export default class Whois extends Command { if (account.locked) details += 'This account is currently locked.\n'; if (account.permissions.facultyMarshal) details += 'This account belongs to a Faculty Marshal.\n'; else if (account.permissions.sheriff) details += 'This account belongs to a Sheriff.\n'; - else if (account.permissions.associate) details += 'This account belongs to a Staff member.\n'; + else if (account.permissions.staff) details += 'This account belongs to a Staff member.\n'; if (account.root) details += 'This account has root/administrative privileges.\n'; if (details) embed.addField('Additional Details', details, true); embed.setFooter(this.client.user.username, this.client.user.avatarURL); diff --git a/src/commands/whois_user.ts b/src/commands/whois_user.ts index 2ed0ff9..e4076f8 100644 --- a/src/commands/whois_user.ts +++ b/src/commands/whois_user.ts @@ -39,7 +39,7 @@ export default class Whois_User extends Command { if (account.locked) details += 'This account is currently locked.\n'; if (account.permissions.facultyMarshal) details += 'This account belongs to a Faculty Marshal.\n'; else if (account.permissions.sheriff) details += 'This account belongs to a Sheriff.\n'; - else if (account.permissions.associate) details += 'This account belongs to a Staff member.\n'; + else if (account.permissions.staff) details += 'This account belongs to a Staff member.\n'; if (account.root) details += 'This account has root/administrative privileges.\n'; if (details) embed.addField('Additional Details', details, true); embed.setFooter(this.client.user.username, this.client.user.avatarURL); -- 2.20.1 From eafcdf1cf66efcd9c67717f8615c408ca2913b61 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 12:16:39 -0400 Subject: [PATCH 132/516] build CI fixes --- src/commands/cwg_data.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/cwg_data.ts b/src/commands/cwg_data.ts index 354fc07..79e5b6c 100644 --- a/src/commands/cwg_data.ts +++ b/src/commands/cwg_data.ts @@ -19,7 +19,7 @@ export default class CWG_Data extends Command { public async run(message: Message, args: string[]) { try { if (!args[0]) return this.client.commands.get('help').run(message, ['cwg', this.name]); - const dom = await this.client.db.Domain.find({ $or: [{ domain: args[0] }, { port: Number(args[0]) || '' }] }); + const dom = await this.client.db.Domain.find({ $or: [{ domain: args[0] }, { port: Number(args[0]) || 0 }] }); if (!dom.length) { if (!Number.isNaN(Number(args[0]))) { try { -- 2.20.1 From 9433ad997fe20327f85610d123971d1fd8b2860d Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 18:16:27 -0400 Subject: [PATCH 133/516] small changes to nginx default config file --- src/static/nginx.conf | 46 +++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/static/nginx.conf b/src/static/nginx.conf index 8e85df4..327a416 100644 --- a/src/static/nginx.conf +++ b/src/static/nginx.conf @@ -3,40 +3,40 @@ server { listen [::]:443 ssl http2; server_name [DOMAIN]; -ssl_certificate [CERTIFICATE]; -ssl_certificate_key [KEY]; + ssl_certificate [CERTIFICATE]; + ssl_certificate_key [KEY]; -ssl_session_cache builtin:1000 shared:SSL:10m; -include /etc/nginx/error/502; -include /etc/nginx/error/504; -include /etc/nginx/error/500; -include /etc/nginx/error/404; -include /etc/nginx/error/429; -ssl_protocols TLSv1.2 TLSv1.3; + ssl_session_cache builtin:1000 shared:SSL:10m; + include /etc/nginx/error/502; + include /etc/nginx/error/504; + include /etc/nginx/error/500; + include /etc/nginx/error/404; + include /etc/nginx/error/429; + ssl_protocols TLSv1.2 TLSv1.3; -ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; -ssl_prefer_server_ciphers on; + ssl_prefer_server_ciphers on; -ssl_stapling on; -ssl_stapling_verify on; + ssl_stapling on; + ssl_stapling_verify on; -limit_req zone=one burst=5; - location / { + limit_req zone=one burst=15; + location / { -proxy_set_header Host $host; + proxy_set_header Host $host; -proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Real-IP $remote_addr; -proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; -proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Proto $scheme; -proxy_pass http://localhost:[PORT]; + proxy_pass http://localhost:[PORT]; -proxy_read_timeout 90; + proxy_read_timeout 90; -proxy_redirect http://localhost:[PORT] https://[DOMAIN]; + proxy_redirect http://localhost:[PORT] https://[DOMAIN]; } -} \ No newline at end of file +} -- 2.20.1 From 98a036c46c9a61cc9dc2c6ead274ca1a2e3bf68c Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 28 Mar 2020 20:52:00 -0400 Subject: [PATCH 134/516] attempt to fix fromEntries issue --- tsconfig.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 131a1cb..32e6546 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,9 +2,9 @@ "compilerOptions": { /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "ES2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ + "target": "ES2020", /* 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'. */ - // "lib": [], /* Specify library files to be included in the compilation. */ + "lib": ["ESNext", "ES2020", "ES2019.Object"], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ -- 2.20.1 From fbd5c478cca8cfa08b586d7dd64e3c55259cac6e Mon Sep 17 00:00:00 2001 From: Bsian Date: Sun, 29 Mar 2020 00:55:40 +0000 Subject: [PATCH 135/516] Fix certain typings stuff --- package.json | 2 +- src/commands/cwg_data.ts | 2 +- src/commands/help.ts | 2 +- src/commands/modlogs.ts | 2 +- src/commands/securesign_createcrt.ts | 1 - tsconfig.json | 2 +- types/global.d.ts | 31 ---------------------------- 7 files changed, 5 insertions(+), 37 deletions(-) delete mode 100644 types/global.d.ts diff --git a/package.json b/package.json index 2efef48..9cd9007 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "axios": "^0.19.0", "body-parser": "^1.19.0", "eris": "^0.11.2", - "eris-pagination": "bsian03/eris-pagination", + "eris-pagination": "bsian03/eris-pagination#dev", "express": "^4.17.1", "fs-extra": "^8.1.0", "helmet": "^3.21.2", diff --git a/src/commands/cwg_data.ts b/src/commands/cwg_data.ts index 79e5b6c..58c947f 100644 --- a/src/commands/cwg_data.ts +++ b/src/commands/cwg_data.ts @@ -48,7 +48,7 @@ export default class CWG_Data extends Command { }); this.client.signale.log(embeds); if (embeds.length === 1) return message.channel.createMessage({ embed: embeds[0] }); - return createPaginationEmbed(message, this.client, embeds, {}); + return createPaginationEmbed(message, embeds); } catch (error) { return this.client.util.handleError(error, message, this); } diff --git a/src/commands/help.ts b/src/commands/help.ts index ac915e1..e28b118 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -41,7 +41,7 @@ export default class Help extends Command { return cmdPages.push(embed); }); if (cmdPages.length === 1) return message.channel.createMessage({ embed: cmdPages[0] }); - return createPaginationEmbed(message, this.client, cmdPages); + return createPaginationEmbed(message, cmdPages); } const resolved = await this.client.util.resolveCommand(args, message); if (!resolved) return message.channel.createMessage(`${this.client.stores.emojis.error} **Command not found!**`); diff --git a/src/commands/modlogs.ts b/src/commands/modlogs.ts index fd974ed..da620c2 100644 --- a/src/commands/modlogs.ts +++ b/src/commands/modlogs.ts @@ -55,7 +55,7 @@ export default class Modlogs extends Command { if (embeds.length === 1) { msg.edit({ content: '', embed: embeds[0] }); } else { - createPaginationEmbed(message, this.client, embeds, {}, msg); + createPaginationEmbed(message, embeds, {}); } return msg; } catch (error) { diff --git a/src/commands/securesign_createcrt.ts b/src/commands/securesign_createcrt.ts index 9b34e0b..655921b 100644 --- a/src/commands/securesign_createcrt.ts +++ b/src/commands/securesign_createcrt.ts @@ -15,7 +15,6 @@ export default class SecureSign_Init extends Command { public async run(message: Message, args: string[]) { try { - return; const account = await this.client.db.Account.findOne({ userID: message.author.id }); if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); if (!account.hash) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not initialized***`); diff --git a/tsconfig.json b/tsconfig.json index 131a1cb..04f4976 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "ES2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ + "target": "ES2020", /* 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'. */ // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ diff --git a/types/global.d.ts b/types/global.d.ts deleted file mode 100644 index 04a9dd5..0000000 --- a/types/global.d.ts +++ /dev/null @@ -1,31 +0,0 @@ - -interface PromiseFulfilledResult { - status: 'fulfilled'; - value: T; -} - -interface PromiseRejectedResult { - status: 'rejected'; - reason: any; -} - -type PromiseSettledResult = PromiseFulfilledResult | PromiseRejectedResult; - -interface PromiseConstructor { - /** - * Creates a Promise that is resolved with an array of results when all - * of the provided Promises resolve or reject. - * @param values An array of Promises. - * @returns A new Promise. - */ - allSettled(values: T): - Promise<{ -readonly [P in keyof T]: PromiseSettledResult ? U : T[P]> }>; - - /** - * Creates a Promise that is resolved with an array of results when all - * of the provided Promises resolve or reject. - * @param values An array of Promises. - * @returns A new Promise. - */ - allSettled(values: Iterable): Promise ? U : T>[]>; -} -- 2.20.1 From 8d343b766dd496bc72586315110781b62380af45 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sun, 29 Mar 2020 00:55:58 +0000 Subject: [PATCH 136/516] No --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 32e6546..4932b96 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ // "incremental": true, /* Enable incremental compilation */ "target": "ES2020", /* 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'. */ - "lib": ["ESNext", "ES2020", "ES2019.Object"], /* Specify library files to be included in the compilation. */ + "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ -- 2.20.1 From 370f0f2fbf31525b20e9acb3489a2454e0e501b1 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sun, 29 Mar 2020 00:59:31 +0000 Subject: [PATCH 137/516] TS is gay --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 4932b96..f0b886f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ // "incremental": true, /* Enable incremental compilation */ "target": "ES2020", /* 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'. */ - "lib": [], /* Specify library files to be included in the compilation. */ + "lib": ["ES2019.Object"], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ -- 2.20.1 From 944cfc8c1e63e8a314f0c6a143e5bb0efca806fc Mon Sep 17 00:00:00 2001 From: Bsian Date: Sun, 29 Mar 2020 02:00:42 +0100 Subject: [PATCH 138/516] Disable command --- src/commands/securesign_account.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/securesign_account.ts b/src/commands/securesign_account.ts index 0ec1efc..e520df2 100644 --- a/src/commands/securesign_account.ts +++ b/src/commands/securesign_account.ts @@ -9,7 +9,7 @@ export default class SecureSign_Account extends Command { this.name = 'account'; this.description = 'Provides SecureSign account details for currently logged in user'; this.usage = `${this.client.config.prefix}securesign account`; - this.enabled = true; + this.enabled = false; this.guildOnly = false; } -- 2.20.1 From 677e09df9e994e41efd5f7c6cecdf3625eb4b060 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sun, 29 Mar 2020 02:07:52 +0100 Subject: [PATCH 139/516] ES2020 Promise --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index f0b886f..10493bf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ // "incremental": true, /* Enable incremental compilation */ "target": "ES2020", /* 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'. */ - "lib": ["ES2019.Object"], /* Specify library files to be included in the compilation. */ + "lib": ["ES2019.Object", "ES2020.Promise"], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ -- 2.20.1 From 077efbbd4554076afd5619fdfc8162c5b40716fb Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 01:55:31 -0400 Subject: [PATCH 140/516] syntax fixes --- src/static/nginx.conf | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/static/nginx.conf b/src/static/nginx.conf index 327a416..4312ac5 100644 --- a/src/static/nginx.conf +++ b/src/static/nginx.conf @@ -24,19 +24,19 @@ server { limit_req zone=one burst=15; location / { - proxy_set_header Host $host; + proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Proto $scheme; - proxy_pass http://localhost:[PORT]; + proxy_pass http://localhost:[PORT]; - proxy_read_timeout 90; + proxy_read_timeout 90; - proxy_redirect http://localhost:[PORT] https://[DOMAIN]; + proxy_redirect http://localhost:[PORT] https://[DOMAIN]; } } -- 2.20.1 From efc8dc8f02b25beab6ac284c8b8483f6fa477e3b Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 04:32:17 -0400 Subject: [PATCH 141/516] create a support key on account creation --- src/class/AccountUtil.ts | 10 +++++++--- src/class/Util.ts | 4 ++-- src/commands/createaccount.ts | 14 +++++++------- src/commands/whois.ts | 1 + src/models/Account.ts | 4 +++- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/class/AccountUtil.ts b/src/class/AccountUtil.ts index cac764a..87cba9a 100644 --- a/src/class/AccountUtil.ts +++ b/src/class/AccountUtil.ts @@ -1,3 +1,4 @@ +import { randomBytes } from 'crypto'; import { AccountInterface } from '../models'; import { Client } from '..'; @@ -22,20 +23,22 @@ export default class AccountUtil { let passHash = await this.client.util.createHash(tempPass); passHash = passHash.replace(/[$]/g, '\\$').replace('\n', ''); const acctName = this.client.users.get(data.userID).username.replace(/[!@#$%^&*(),.?":{}|<>]/g, '-').replace(/\s/g, '-'); const etcPasswd = `${acctName},${data.userID},,`; + const code = randomBytes(3).toString('hex').toUpperCase(); - const accountInterface = await this.client.util.createAccount(passHash, etcPasswd, data.username, data.userID, data.emailAddress, moderator); + 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); this.client.util.transport.sendMail({ to: data.emailAddress, from: 'Library of Code sp-us | Cloud Services ', - subject: 'Your account has been created', + subject: 'Your account has been created!', html: `

    Library of Code | Cloud Services

    Your Cloud Account has been created, welcome! Please see below for some details regarding your account and our services

    Username: ${data.username}

    +

    Support Key: ${code} || You may be asked for this support key when contacting Library of Code, please keep the code in a safe area.

    SSH Login:

    ssh ${data.username}@cloud.libraryofcode.org

    Useful information

    How to log in:

    @@ -67,7 +70,8 @@ export default class AccountUtil { + `You will be asked to change your password, \`(current) UNIX password\` is \`${tempPass}\`, then create a password that is at least 12 characters long, with at least one number, special character, and an uppercase letter\n` + 'Bear in mind that when you enter your password, it will be blank, so be careful not to type in your password incorrectly.\n' + 'You may now return to Modmail, and continue setting up your account from there.\n\n' - + 'An email containing some useful information has also been sent').catch(); + + 'An email containing some useful information has also been sent.\n' + + `Your support key is \`${code}\`. Pin this message, you may need this key to contact Library of Code in the future.`).catch(); return { account: accountInterface, tempPass }; } } diff --git a/src/class/Util.ts b/src/class/Util.ts index 28cb962..fb093d2 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -147,12 +147,12 @@ export default class Util { return tempPass; } - public async createAccount(hash: string, etcPasswd: string, username: string, userID: string, emailAddress: string, moderatorID: string): Promise { + public async createAccount(hash: string, etcPasswd: string, username: string, userID: string, emailAddress: string, moderatorID: string, code: string): Promise { await this.exec(`useradd -m -p ${hash} -c ${etcPasswd} -s /bin/bash ${username}`); await this.exec(`chage -d0 ${username}`); const account = new this.client.db.Account({ - username, userID, emailAddress, createdBy: moderatorID, createdAt: new Date(), locked: false, tier: 1, ssInit: false, homepath: `/home/${username}`, + username, userID, emailAddress, createdBy: moderatorID, createdAt: new Date(), locked: false, tier: 1, supportKey: code, ssInit: false, homepath: `/home/${username}`, }); return account.save(); } diff --git a/src/commands/createaccount.ts b/src/commands/createaccount.ts index c345066..15c04b5 100644 --- a/src/commands/createaccount.ts +++ b/src/commands/createaccount.ts @@ -24,17 +24,17 @@ export default class CreateAccount extends Command { 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 (!message.channel.guild.members.has(args[0])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***User not found***`); - if (message.channel.guild.members.get(args[0]).bot) return message.channel.createMessage(`${this.client.stores.emojis.error} ***I cannot create accounts for bots***`); + if (!message.channel.guild.members.has(args[0])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***User not found.***`); + if (message.channel.guild.members.get(args[0]).bot) return message.channel.createMessage(`${this.client.stores.emojis.error} ***I cannot create accounts for bots.***`); const checkUser = await this.client.db.Account.findOne({ userID: args[0] }); - if (checkUser) return message.channel.createMessage(`${this.client.stores.emojis.error} ***<@${args[0]}> already has an account***`); + if (checkUser) return message.channel.createMessage(`${this.client.stores.emojis.error} ***<@${args[0]}> already has an account.***`); const checkEmail = await this.client.db.Account.findOne({ emailAddress: args[1] }); - if (checkEmail) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account already exists with this email address***`); + if (checkEmail) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account already exists with this email address.***`); const checkAccount = await this.client.db.Account.findOne({ username: args[2] }); - if (checkAccount) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account already exists with this username***`); + if (checkAccount) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account already exists with this username.***`); - if (!this.client.util.isValidEmail(args[1])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid email address supplied***`); - if (!/^[a-z][-a-z0-9]*$/.test(args[2])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid username supplied***`); + if (!this.client.util.isValidEmail(args[1])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid email address supplied.***`); + if (!/^[a-z][-a-z0-9]*$/.test(args[2])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid username supplied.***`); const confirmation = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Creating account...***`); const data = await this.client.util.accounts.createAccount({ userID: args[0], username: args[2], emailAddress: args[1] }, message.author.id); diff --git a/src/commands/whois.ts b/src/commands/whois.ts index 38109bf..48465a7 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -39,6 +39,7 @@ export default class Whois extends Command { embed.addField('ID', account.userID, true); embed.addField('Email Address', account.emailAddress, true); embed.addField('Tier', String(account.tier), true); + embed.addField('Support Key', account.supportKey, true); embed.addField('Created By', `<@${this.client.users.get(account.createdBy).id}>`, true); embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); const cpuUsage = await this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`); diff --git a/src/models/Account.ts b/src/models/Account.ts index 3f10dc2..7ba490b 100644 --- a/src/models/Account.ts +++ b/src/models/Account.ts @@ -8,7 +8,8 @@ export interface AccountInterface extends Document { createdBy: string, createdAt: Date, locked: boolean, - tier: number; + tier: number, + supportKey: string, permissions: { staff: boolean, sheriff: boolean, @@ -29,6 +30,7 @@ const Account: Schema = new Schema({ createdAt: Date, locked: Boolean, tier: Number, + supportKey: String, permissions: { staff: Boolean, sheriff: Boolean, -- 2.20.1 From 2159845d467bc56be64065328332f59cf5fafc1f Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 04:32:27 -0400 Subject: [PATCH 142/516] command to change tier --- src/commands/tier.ts | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/commands/tier.ts diff --git a/src/commands/tier.ts b/src/commands/tier.ts new file mode 100644 index 0000000..a86d2e6 --- /dev/null +++ b/src/commands/tier.ts @@ -0,0 +1,41 @@ +/* eslint-disable consistent-return */ +import { Message } from 'eris'; +import { Client } from '..'; +import { Command, RichEmbed } from '../class'; + +export default class Tier extends Command { + constructor(client: Client) { + super(client); + this.name = 'tier'; + this.description = 'Changes the tier level for an account.'; + this.usage = `${this.client.config.prefix}tier <1 | 2 | 3>`; + this.permissions = { roles: ['446104438969466890'] }; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + if (!args.length) return this.client.commands.get('help').run(message, [this.name]); + const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Editing tier...***`); + 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.root) return edit.edit(`***${this.client.stores.emojis.error} Permission denied.***`); + if (Number.isNaN(Number(args[1]))) return edit.edit(`***${this.client.stores.emojis.error} The tier you provided is not a valid number. It should be between 1 and 3.***`); + if (Number(args[1]) > 3 || Number(args[1]) < 1) return edit.edit(`***${this.client.stores.emojis.error} You can only choose a Tier between 1 and 3.***`); + message.delete(); + await account.updateOne({ $set: { tier: Number(args[1]) } }); + message.channel.createMessage(`***${this.client.stores.emojis.success} Tier for ${account.username} has been changed to ${args[1]}.***`); + const embed = new RichEmbed(); + embed.setTitle('Cloud Account | Tier Change'); + embed.setColor('#0099ff'); + embed.addField('User', `${account.username} | <@${account.userID}>`, true); + embed.addField('Moderator', `<@${message.author.id}>`, true); + embed.addField('Old Tier -> New Tier', `${account.tier} -> ${args[1]}`, true); + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + embed.setTimestamp(); + this.client.createMessage('580950455581147146', { embed }); this.client.getDMChannel(account.userID).then((channel) => channel.createMessage({ embed })).catch(); + } catch (error) { + await this.client.util.handleError(error, message, this); + } + } +} -- 2.20.1 From 09de117cbd0632833b96441604a59c644aa4792b Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 04:32:38 -0400 Subject: [PATCH 143/516] command for email verification --- src/commands/emailcode.ts | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/commands/emailcode.ts diff --git a/src/commands/emailcode.ts b/src/commands/emailcode.ts new file mode 100644 index 0000000..ad203c1 --- /dev/null +++ b/src/commands/emailcode.ts @@ -0,0 +1,43 @@ +/* eslint-disable consistent-return */ +import { randomBytes } from 'crypto'; +import { Message } from 'eris'; +import { Client } from '..'; +import { Command, RichEmbed } from '../class'; + +export default class EmailCode extends Command { + constructor(client: Client) { + super(client); + this.name = 'emailcode'; + this.description = 'Sends a code to an email address to use for address verification.'; + this.usage = `${this.client.config.prefix}emailcode `; + this.permissions = { roles: ['446104438969466890'] }; + this.aliases = ['code']; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + const code = randomBytes(5).toString('hex'); + if (!this.client.util.isValidEmail(args[0])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid email address supplied.***`); + this.client.util.transport.sendMail({ + to: args[0], + from: 'Library of Code sp-us | Cloud Services ', + subject: 'Email Verification Code', + html: ` + + +

    Library of Code | Cloud Services

    +

    Please provide the code provided below to the Staff member working with you on account creation.

    +

    ${code}

    +

    Want to support us?

    +

    You can support us on Patreon! Head to our Patreon page and feel free to donate as much or as little as you want!
    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!

    + Library of Code sp-us | Support Team + + `, + }); + message.channel.createMessage(`***${this.client.stores.emojis.success} Code: \`${code}\` | Email Address: ${args[0]}***`); + } catch (error) { + await this.client.util.handleError(error, message, this); + } + } +} -- 2.20.1 From a9c1e79d296d19f82468e87276d0a67992c21e2e Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 04:37:12 -0400 Subject: [PATCH 144/516] tsconfig changes --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 10493bf..febdc18 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "ES2020", /* 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'. */ "lib": ["ES2019.Object", "ES2020.Promise"], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ -- 2.20.1 From 53774752dda3313eb199573ee3f182a42f97db12 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 04:45:59 -0400 Subject: [PATCH 145/516] fix issue in automatic perm checks --- src/intervals/checkStaffStatus.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intervals/checkStaffStatus.ts b/src/intervals/checkStaffStatus.ts index bfff788..48f7c0e 100644 --- a/src/intervals/checkStaffStatus.ts +++ b/src/intervals/checkStaffStatus.ts @@ -26,7 +26,7 @@ export default function checkStaffStatus(client: Client) { 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 } }); client.getDMChannel(acc.userID).then((chan) => { chan.createMessage('***Your account has automatically been upgraded to Tier 3 since you are a Staff member.***'); -- 2.20.1 From f38bf2587272b9f63a110fe7e8a6d2b0f25baa1a Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 04:58:29 -0400 Subject: [PATCH 146/516] add new commands --- src/commands/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/commands/index.ts b/src/commands/index.ts index f9d20aa..0abb76d 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -4,6 +4,7 @@ export { default as createaccount } from './createaccount'; export { default as cwg } from './cwg'; export { default as deleteaccount } from './deleteaccount'; export { default as disk } from './disk'; +export { default as emailcode } from './emailcode'; export { default as eval } from './eval'; export { default as exec } from './exec'; export { default as help } from './help'; @@ -19,6 +20,7 @@ export { default as resetpassword } from './resetpassword'; export { default as restart } from './restart'; export { default as securesign } from './securesign'; export { default as sysinfo } from './sysinfo'; +export { default as tier } from './tier'; export { default as unban } from './unban'; export { default as unlock } from './unlock'; export { default as warn } from './warn'; -- 2.20.1 From 2b8772dbfbf49079508c48f0f1fad4bbf4a90331 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 05:22:22 -0400 Subject: [PATCH 147/516] fix memory checking issue --- src/intervals/memory.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 87c5d60..d285e3b 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -34,7 +34,8 @@ export default function memory(client: Client) { /* if the user has exceeded their soft memory limit, which is the one described in the resource limit guidelines, we'll inform staff. */ - if (acc.tier === 1 && memoryConversion >= userLimits.soft) { + if (memoryConversion >= userLimits.soft) { + client.signale.info(`RAM Soft Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.soft} MB`); const embed = new RichEmbed(); if (client.users.get(acc.userID)) embed.setThumbnail(client.users.get(acc.userID).avatarURL); embed.addField('User', `${acc.username} | <@${acc.userID}> | ${acc.userID}`, true); @@ -46,6 +47,7 @@ export default function memory(client: Client) { // if they exceed the hard limit, we'll kill all of their processes. if (memoryConversion >= userLimits.hard) { + client.signale.info(`RAM Hard Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.hard} MB`); client.util.exec(`killall -9 -u ${acc.username}`); 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.'); -- 2.20.1 From 344926c74246a7863361c72b799a2a613359548d Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 05:23:11 -0400 Subject: [PATCH 148/516] fix memory checking issue --- src/intervals/memory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index d285e3b..f0806f8 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -73,5 +73,5 @@ export default function memory(client: Client) { client.createMessage(channelID, { embed }); } } - }, 300000); + }, 60000); } -- 2.20.1 From 4ca2e9b1886571b7e666a0ec8f84b13e715a5cb0 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 05:28:40 -0400 Subject: [PATCH 149/516] fix memory checking issue --- src/intervals/memory.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index f0806f8..04fabe5 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -16,7 +16,9 @@ export const memoryLimits = { export default function memory(client: Client) { setInterval(async () => { const accounts = await client.db.Account.find(); + console.log(accounts); for (const acc of accounts) { + console.log(acc); if (acc.root) return; // memory in bytes const mem = Number(await client.util.exec(`memory ${acc.username}`)) * 1000; @@ -34,6 +36,7 @@ export default function memory(client: Client) { /* if the user has exceeded their soft memory limit, which is the one described in the resource limit guidelines, we'll inform staff. */ + console.log(memoryConversion, userLimits.soft, userLimits.hard); if (memoryConversion >= userLimits.soft) { client.signale.info(`RAM Soft Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.soft} MB`); const embed = new RichEmbed(); -- 2.20.1 From 271cfe1959e47706beb3ca9befead850a4e4eddd Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 05:33:43 -0400 Subject: [PATCH 150/516] fix memory checking issue --- src/intervals/memory.ts | 122 +++++++++++++++++++++------------------- 1 file changed, 64 insertions(+), 58 deletions(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 04fabe5..334d9b6 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -15,66 +15,72 @@ export const memoryLimits = { export default function memory(client: Client) { setInterval(async () => { - const accounts = await client.db.Account.find(); - console.log(accounts); - for (const acc of accounts) { - console.log(acc); - if (acc.root) return; - // memory in bytes - const mem = Number(await client.util.exec(`memory ${acc.username}`)) * 1000; - // memory in megabytes - const memoryConversion = mem / 1024 / 1024; - let userLimits: { soft: number, hard: number }; - if (acc.tier === 1) { - userLimits = { soft: memoryLimits.TIER_1_SOFT, hard: memoryLimits.TIER_1_HARD }; - } else if (acc.tier === 2) { - userLimits = { soft: memoryLimits.TIER_2_SOFT, hard: memoryLimits.TIER_2_HARD }; - } else if (acc.tier === 3) { - userLimits = { soft: memoryLimits.TIER_3_SOFT, hard: memoryLimits.TIER_3_HARD }; - } - - /* if the user has exceeded their soft memory limit, which is the one described in the - resource limit guidelines, we'll inform staff. - */ - console.log(memoryConversion, userLimits.soft, userLimits.hard); - if (memoryConversion >= userLimits.soft) { - client.signale.info(`RAM Soft Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.soft} MB`); - const embed = new RichEmbed(); - if (client.users.get(acc.userID)) embed.setThumbnail(client.users.get(acc.userID).avatarURL); - embed.addField('User', `${acc.username} | <@${acc.userID}> | ${acc.userID}`, true); - embed.addField('Tier', String(acc.tier), true); - embed.addField('Memory Usage', `${String(memoryConversion)} MB`, true); - embed.addField('Memory Limit', `${String(userLimits.soft)} MB`, true); - embed.setFooter(client.user.username, client.user.avatarURL); - embed.setTimestamp(); - - // if they exceed the hard limit, we'll kill all of their processes. - if (memoryConversion >= userLimits.hard) { - client.signale.info(`RAM Hard Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.hard} MB`); - client.util.exec(`killall -9 -u ${acc.username}`); - 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.'); - client.util.createModerationLog(acc.userID, client.guilds.get('446067825673633794').members.get(client.user.id), 1, '[AUTO] Exceeded resource limit for RAM.'); - client.util.transport.sendMail({ - to: acc.emailAddress, - from: 'Library of Code sp-us | Cloud Services ', - subject: 'Your account has been warned', - html: ` -

    Library of Code sp-us | Cloud Services

    -

    Your account has received an official warning from a Moderator. Please get the underlying issue resolved to avoid possible moderative action.

    -

    Reason: [AUTO] Exceeded resource limit for RAM.

    -

    Moderator: ${client.user.username}

    - - Library of Code sp-us | Support Team - `, - }); - } else { - embed.setTitle('Resource Limit Notification'); - embed.setDescription('Someone has reached the (soft) resource limit for their tier on RAM.'); + try { + const accounts = await client.db.Account.find(); + console.log(accounts); + for (const acc of accounts) { + console.log(acc); + if (acc.root === true) return; + // memory in bytes + const mem = Number(await client.util.exec(`memory ${acc.username}`)) * 1000; + console.log(mem); + // memory in megabytes + const memoryConversion = mem / 1024 / 1024; + console.log(memoryConversion); + let userLimits: { soft: number, hard: number }; + if (acc.tier === 1) { + userLimits = { soft: memoryLimits.TIER_1_SOFT, hard: memoryLimits.TIER_1_HARD }; + } else if (acc.tier === 2) { + userLimits = { soft: memoryLimits.TIER_2_SOFT, hard: memoryLimits.TIER_2_HARD }; + } else if (acc.tier === 3) { + userLimits = { soft: memoryLimits.TIER_3_SOFT, hard: memoryLimits.TIER_3_HARD }; + } + + /* if the user has exceeded their soft memory limit, which is the one described in the + resource limit guidelines, we'll inform staff. + */ + console.log(memoryConversion, userLimits.soft, userLimits.hard); + if (memoryConversion >= userLimits.soft) { + client.signale.info(`RAM Soft Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.soft} MB`); + const embed = new RichEmbed(); + if (client.users.get(acc.userID)) embed.setThumbnail(client.users.get(acc.userID).avatarURL); + embed.addField('User', `${acc.username} | <@${acc.userID}> | ${acc.userID}`, true); + embed.addField('Tier', String(acc.tier), true); + embed.addField('Memory Usage', `${String(memoryConversion)} MB`, true); + embed.addField('Memory Limit', `${String(userLimits.soft)} MB`, true); + embed.setFooter(client.user.username, client.user.avatarURL); + embed.setTimestamp(); + + // if they exceed the hard limit, we'll kill all of their processes. + if (memoryConversion >= userLimits.hard) { + client.signale.info(`RAM Hard Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.hard} MB`); + client.util.exec(`killall -9 -u ${acc.username}`); + 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.'); + client.util.createModerationLog(acc.userID, client.guilds.get('446067825673633794').members.get(client.user.id), 1, '[AUTO] Exceeded resource limit for RAM.'); + client.util.transport.sendMail({ + to: acc.emailAddress, + from: 'Library of Code sp-us | Cloud Services ', + subject: 'Your account has been warned', + html: ` +

    Library of Code sp-us | Cloud Services

    +

    Your account has received an official warning from a Moderator. Please get the underlying issue resolved to avoid possible moderative action.

    +

    Reason: [AUTO] Exceeded resource limit for RAM.

    +

    Moderator: ${client.user.username}

    + + Library of Code sp-us | Support Team + `, + }); + } else { + embed.setTitle('Resource Limit Notification'); + embed.setDescription('Someone has reached the (soft) resource limit for their tier on RAM.'); + } + // @ts-ignore + client.createMessage(channelID, { embed }); } - // @ts-ignore - client.createMessage(channelID, { embed }); } + } catch (err) { + client.util.handleError(err); } }, 60000); } -- 2.20.1 From 0b08700140e348a63005918d5e7c6d50817cb83a Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 05:37:14 -0400 Subject: [PATCH 151/516] fix memory checking issue --- src/intervals/memory.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 334d9b6..fef3803 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -19,7 +19,8 @@ export default function memory(client: Client) { const accounts = await client.db.Account.find(); console.log(accounts); for (const acc of accounts) { - console.log(acc); + console.log(acc.username); + console.log(acc.root); if (acc.root === true) return; // memory in bytes const mem = Number(await client.util.exec(`memory ${acc.username}`)) * 1000; -- 2.20.1 From 2cec8a45ae05b171c60233e5416985e78c2b82bb Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 05:43:40 -0400 Subject: [PATCH 152/516] fix memory checking issue --- src/intervals/memory.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index fef3803..70f08b4 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-continue */ /* eslint-disable no-await-in-loop */ import { Client } from '..'; import { RichEmbed } from '../class'; @@ -17,17 +18,12 @@ export default function memory(client: Client) { setInterval(async () => { try { const accounts = await client.db.Account.find(); - console.log(accounts); for (const acc of accounts) { - console.log(acc.username); - console.log(acc.root); - if (acc.root === true) return; + if (acc.root === true) continue; // memory in bytes const mem = Number(await client.util.exec(`memory ${acc.username}`)) * 1000; - console.log(mem); // memory in megabytes const memoryConversion = mem / 1024 / 1024; - console.log(memoryConversion); let userLimits: { soft: number, hard: number }; if (acc.tier === 1) { userLimits = { soft: memoryLimits.TIER_1_SOFT, hard: memoryLimits.TIER_1_HARD }; @@ -40,7 +36,6 @@ export default function memory(client: Client) { /* if the user has exceeded their soft memory limit, which is the one described in the resource limit guidelines, we'll inform staff. */ - console.log(memoryConversion, userLimits.soft, userLimits.hard); if (memoryConversion >= userLimits.soft) { client.signale.info(`RAM Soft Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.soft} MB`); const embed = new RichEmbed(); -- 2.20.1 From 4f6233548b78f7fd6a61beb3fdd1718e67ecc49c Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 05:47:42 -0400 Subject: [PATCH 153/516] fix memory checking issue --- src/intervals/memory.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 70f08b4..6492524 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -5,7 +5,7 @@ import { RichEmbed } from '../class'; const channelID = '691824484230889546'; -export const memoryLimits = { +const memoryLimits = { TIER_1_SOFT: 200, TIER_1_HARD: 350, TIER_2_SOFT: 350, @@ -24,6 +24,7 @@ export default function memory(client: Client) { const mem = Number(await client.util.exec(`memory ${acc.username}`)) * 1000; // memory in megabytes const memoryConversion = mem / 1024 / 1024; + console.log(memoryLimits); let userLimits: { soft: number, hard: number }; if (acc.tier === 1) { userLimits = { soft: memoryLimits.TIER_1_SOFT, hard: memoryLimits.TIER_1_HARD }; @@ -32,6 +33,7 @@ export default function memory(client: Client) { } else if (acc.tier === 3) { userLimits = { soft: memoryLimits.TIER_3_SOFT, hard: memoryLimits.TIER_3_HARD }; } + console.log(userLimits); /* if the user has exceeded their soft memory limit, which is the one described in the resource limit guidelines, we'll inform staff. -- 2.20.1 From 6ebddbf9e0110d339359496718d67bfa21e392ad Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 05:47:53 -0400 Subject: [PATCH 154/516] fix memory checking issue --- src/intervals/memory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 6492524..5677bc9 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -80,5 +80,5 @@ export default function memory(client: Client) { } catch (err) { client.util.handleError(err); } - }, 60000); + }, 30000); } -- 2.20.1 From c5ddad81c743ad93b57aeb6cf79d2502ef906e0e Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 05:53:15 -0400 Subject: [PATCH 155/516] fix memory checking issue --- src/intervals/memory.ts | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 5677bc9..369ae19 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -25,13 +25,22 @@ export default function memory(client: Client) { // memory in megabytes const memoryConversion = mem / 1024 / 1024; console.log(memoryLimits); - let userLimits: { soft: number, hard: number }; - if (acc.tier === 1) { - userLimits = { soft: memoryLimits.TIER_1_SOFT, hard: memoryLimits.TIER_1_HARD }; - } else if (acc.tier === 2) { - userLimits = { soft: memoryLimits.TIER_2_SOFT, hard: memoryLimits.TIER_2_HARD }; - } else if (acc.tier === 3) { - userLimits = { soft: memoryLimits.TIER_3_SOFT, hard: memoryLimits.TIER_3_HARD }; + const userLimits: { soft?: number, hard?: number } = {}; + switch (acc.tier) { + case 1: + userLimits.soft = memoryLimits.TIER_1_SOFT; + userLimits.hard = memoryLimits.TIER_1_HARD; + break; + case 2: + userLimits.soft = memoryLimits.TIER_2_SOFT; + userLimits.hard = memoryLimits.TIER_2_HARD; + break; + case 3: + userLimits.soft = memoryLimits.TIER_3_SOFT; + userLimits.hard = memoryLimits.TIER_3_HARD; + break; + default: + break; } console.log(userLimits); @@ -80,5 +89,5 @@ export default function memory(client: Client) { } catch (err) { client.util.handleError(err); } - }, 30000); + }, 60000); } -- 2.20.1 From c4541b7ec09bccf2a677f1801d0b585152a3d4e5 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 05:59:57 -0400 Subject: [PATCH 156/516] fix memory checking issue --- src/intervals/memory.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 369ae19..b61451f 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -24,7 +24,6 @@ export default function memory(client: Client) { const mem = Number(await client.util.exec(`memory ${acc.username}`)) * 1000; // memory in megabytes const memoryConversion = mem / 1024 / 1024; - console.log(memoryLimits); const userLimits: { soft?: number, hard?: number } = {}; switch (acc.tier) { case 1: @@ -42,7 +41,6 @@ export default function memory(client: Client) { default: break; } - console.log(userLimits); /* if the user has exceeded their soft memory limit, which is the one described in the resource limit guidelines, we'll inform staff. -- 2.20.1 From 682d067f67def5ea05ec3151bebfea3101350ed7 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 06:19:32 -0400 Subject: [PATCH 157/516] add role on account creation --- src/class/AccountUtil.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/class/AccountUtil.ts b/src/class/AccountUtil.ts index 87cba9a..339f48d 100644 --- a/src/class/AccountUtil.ts +++ b/src/class/AccountUtil.ts @@ -64,6 +64,7 @@ export default class AccountUtil { `, }); + this.client.guilds.get('446067825673633794').members.get(data.userID).addRole('546457886440685578'); const dmChannel = await this.client.getDMChannel(data.userID).catch(); dmChannel.createMessage('<: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` -- 2.20.1 From 363917895297f1eedd3344f1f82bf2ace28ef051 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 06:48:20 -0400 Subject: [PATCH 158/516] notifs --- src/intervals/checkStaffStatus.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/intervals/checkStaffStatus.ts b/src/intervals/checkStaffStatus.ts index 48f7c0e..0d318de 100644 --- a/src/intervals/checkStaffStatus.ts +++ b/src/intervals/checkStaffStatus.ts @@ -1,5 +1,6 @@ /* eslint-disable no-await-in-loop */ import { Client } from '..'; +import { RichEmbed } from '../class'; export default function checkStaffStatus(client: Client) { setInterval(async () => { @@ -28,6 +29,15 @@ export default function checkStaffStatus(client: Client) { if (acc.permissions.staff && acc.tier < 3) { await client.db.Account.updateOne({ username: acc.username }, { $set: { tier: 3 } }); + const embed = new RichEmbed(); + embed.setTitle('Cloud Account | Tier Change'); + embed.setColor('#0099ff'); + embed.addField('User', `${acc.username} | <@${acc.userID}>`, true); + embed.addField('Moderator', `<@${client.user.id}>`, true); + embed.addField('Old Tier -> New Tier', `${acc.tier} -> 3`, true); + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + embed.setTimestamp(); + this.client.createMessage('580950455581147146', { embed }); client.getDMChannel(acc.userID).then((chan) => { chan.createMessage('***Your account has automatically been upgraded to Tier 3 since you are a Staff member.***'); }); -- 2.20.1 From e07211d0f8d1ccc8d3640407a2df660ae64709de Mon Sep 17 00:00:00 2001 From: Bsian Date: Sun, 29 Mar 2020 22:40:50 +0100 Subject: [PATCH 159/516] Bug fixes --- src/commands/cwg_create.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index 8a5a8a1..2d8937e 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -155,7 +155,7 @@ export default class CWG_Create extends Command { key: '/etc/ssl/private/cloud-libraryofcode-org.key', }; } - let cfg = await fs.readFile('/opt/CloudServices/dist/static/nginx.conf', { encoding: 'utf8' }); + let cfg = await fs.readFile('/opt/CloudServices/src/static/nginx.conf', { encoding: 'utf8' }); cfg = cfg.replace(/\[DOMAIN]/g, domain); cfg = cfg.replace(/\[PORT]/g, String(port)); cfg = cfg.replace(/\[CERTIFICATE]/g, x509.cert); @@ -180,9 +180,8 @@ export default class CWG_Create extends Command { } return entry.save(); } catch (error) { - await fs.unlink(`/etc/nginx/sites-enabled/${domain}`); - await fs.unlink(`/etc/nginx/sites-available/${domain}`); - await this.client.db.Domain.deleteMany({ domain }); + const tasks = [fs.unlink(`/etc/nginx/sites-enabled/${domain}`), fs.unlink(`/etc/nginx/sites-available/${domain}`), this.client.db.Domain.deleteMany({ domain })]; + await Promise.allSettled(tasks); throw error; } } -- 2.20.1 From 09bec4ad43d5856e3669769e4b022e6f4c27397f Mon Sep 17 00:00:00 2001 From: Bsian Date: Sun, 29 Mar 2020 22:43:47 +0100 Subject: [PATCH 160/516] Matt stop changing the fucking target --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index febdc18..10493bf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "ES2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ + "target": "ES2020", /* 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'. */ "lib": ["ES2019.Object", "ES2020.Promise"], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ -- 2.20.1 From f55db08f362735ffb9dcee118541e14c4381d8ad Mon Sep 17 00:00:00 2001 From: Bsian Date: Sun, 29 Mar 2020 22:51:17 +0100 Subject: [PATCH 161/516] More bug fixes? --- src/commands/cwg_create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index 2d8937e..ce53fa5 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -182,7 +182,7 @@ export default class CWG_Create extends Command { } catch (error) { const tasks = [fs.unlink(`/etc/nginx/sites-enabled/${domain}`), fs.unlink(`/etc/nginx/sites-available/${domain}`), this.client.db.Domain.deleteMany({ domain })]; await Promise.allSettled(tasks); - throw error; + return Promise.reject(error); } } -- 2.20.1 From d6ec1d6a6ccab7c0bf6b69d3150e12a5b9ce4d07 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sun, 29 Mar 2020 22:59:21 +0100 Subject: [PATCH 162/516] More bug fixes --- src/commands/cwg_create.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index ce53fa5..33d009f 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -126,9 +126,8 @@ export default class CWG_Create extends Command { return Promise.all(completed); } catch (err) { - await fs.unlink(`/etc/nginx/sites-available/${args[1]}`); - await fs.unlink(`/etc/nginx/sites-enabled/${args[1]}`); - await this.client.db.Domain.deleteMany({ domain: args[1] }); + const tasks = [fs.unlink(`/etc/nginx/sites-enabled/${args[1]}`), fs.unlink(`/etc/nginx/sites-available/${args[1]}`), this.client.db.Domain.deleteMany({ domain: args[1] })]; + await Promise.allSettled(tasks); return this.client.util.handleError(err, message, this); } } @@ -182,7 +181,7 @@ export default class CWG_Create extends Command { } catch (error) { const tasks = [fs.unlink(`/etc/nginx/sites-enabled/${domain}`), fs.unlink(`/etc/nginx/sites-available/${domain}`), this.client.db.Domain.deleteMany({ domain })]; await Promise.allSettled(tasks); - return Promise.reject(error); + throw error; } } -- 2.20.1 From 7ade77878824a5b4c5bed5c2585b5ff986b283b1 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sun, 29 Mar 2020 23:11:21 +0100 Subject: [PATCH 163/516] Bug fix --- src/intervals/checkStaffStatus.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intervals/checkStaffStatus.ts b/src/intervals/checkStaffStatus.ts index 0d318de..2bc8448 100644 --- a/src/intervals/checkStaffStatus.ts +++ b/src/intervals/checkStaffStatus.ts @@ -6,7 +6,7 @@ export default function checkStaffStatus(client: Client) { setInterval(async () => { const accounts = await client.db.Account.find(); for (const acc of accounts) { - const user = client.guilds.get('446067825673633794').members.get(acc.userID) ?? await client.guilds.get('446067825673633794').getRESTMember(acc.userID); + const user = client.guilds.get('446067825673633794').members.get(acc.userID) || await client.guilds.get('446067825673633794').getRESTMember(acc.userID); if (!acc.permissions.facultyMarshal && user.roles.includes('662163685439045632')) { await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.facultyMarshal': true } }); } -- 2.20.1 From 5c869bd803841ad8943a61b1ba6b5db7b75a1d80 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 18:12:36 -0400 Subject: [PATCH 164/516] fix interval --- src/intervals/checkStaffStatus.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intervals/checkStaffStatus.ts b/src/intervals/checkStaffStatus.ts index 0d318de..2bc8448 100644 --- a/src/intervals/checkStaffStatus.ts +++ b/src/intervals/checkStaffStatus.ts @@ -6,7 +6,7 @@ export default function checkStaffStatus(client: Client) { setInterval(async () => { const accounts = await client.db.Account.find(); for (const acc of accounts) { - const user = client.guilds.get('446067825673633794').members.get(acc.userID) ?? await client.guilds.get('446067825673633794').getRESTMember(acc.userID); + const user = client.guilds.get('446067825673633794').members.get(acc.userID) || await client.guilds.get('446067825673633794').getRESTMember(acc.userID); if (!acc.permissions.facultyMarshal && user.roles.includes('662163685439045632')) { await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.facultyMarshal': true } }); } -- 2.20.1 From dbf931bbde69c047b19d212e55140bca1bbec413 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 29 Mar 2020 23:57:55 -0400 Subject: [PATCH 165/516] fix editing issue --- src/commands/tier.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/tier.ts b/src/commands/tier.ts index a86d2e6..9c2c76f 100644 --- a/src/commands/tier.ts +++ b/src/commands/tier.ts @@ -24,7 +24,7 @@ export default class Tier extends Command { if (Number(args[1]) > 3 || Number(args[1]) < 1) return edit.edit(`***${this.client.stores.emojis.error} You can only choose a Tier between 1 and 3.***`); message.delete(); await account.updateOne({ $set: { tier: Number(args[1]) } }); - message.channel.createMessage(`***${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(); embed.setTitle('Cloud Account | Tier Change'); embed.setColor('#0099ff'); -- 2.20.1 From 4579e9495fc2ab9f29493163298434611d5e178e Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 30 Mar 2020 02:43:05 -0400 Subject: [PATCH 166/516] remove build.sh --- build.sh | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 build.sh diff --git a/build.sh b/build.sh deleted file mode 100644 index b6536fc..0000000 --- a/build.sh +++ /dev/null @@ -1,8 +0,0 @@ -# This file builds the Go binaries. Hardcoded by LOC Engineering -# DEPRECATED, USE MAKEFILE INSTEAD -go build -ldflags="-s -w" -o dist/bin/storage src/go/storage/storage.go src/go/storage/dirsize.go -file dist/bin/storage -go build -ldflags="-s -w" -o dist/bin/checkCertificate src/go/checkCertificate/checkCertificate.go -file dist/bin/checkCertificate -go build -ldflags="-s -w" -o dist/bin/checkCertSignatures src/go/checkCertSignatures/checkCertSignatures.go -file dist/bin/checkCertSignatures -- 2.20.1 From 50531f07cada9bccd57e87ce4cfaa2af9127c1bd Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 30 Mar 2020 11:47:42 +0100 Subject: [PATCH 167/516] Bug fix --- src/commands/whois.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/commands/whois.ts b/src/commands/whois.ts index 48465a7..38a74c0 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -27,12 +27,9 @@ export default class Whois extends Command { embed.setTitle('Account Information'); if (this.client.users.get(account.userID)) embed.setThumbnail(this.client.users.get(account.userID).avatarURL); embed.setColor(0x36393f); - let fingerInformation: string; - const result = await this.client.util.exec(`finger ${account.username}`); - if (message.member && !message.member.roles.includes('143414786913206272')) { - fingerInformation = result.replace(/((^\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, '[MASKED IP ADDRESS]'); - } else { - fingerInformation = result; + let fingerInformation = await this.client.util.exec(`finger ${account.username}`); + if (message.member && !message.member.roles.includes('662163685439045632')) { + fingerInformation = fingerInformation.replace(/((^\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, '[MASKED IP ADDRESS]'); } embed.setDescription(`${fingerInformation}\n${await this.client.util.exec(`chage -l ${account.username}`)}`); embed.addField('Username', `${account.username} | <@${account.userID}>`, true); -- 2.20.1 From 8ca73f2b62fdc26d4c295084443618e47916f845 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 30 Mar 2020 12:22:32 +0100 Subject: [PATCH 168/516] Cleanup and stuff --- src/class/Command.ts | 84 ++++++++++----------- src/commands/bearer.ts | 63 ++++++++-------- src/commands/createaccount.ts | 1 - src/commands/disk.ts | 1 - src/commands/emailcode.ts | 5 +- src/commands/eval.ts | 138 +++++++++++++++++----------------- src/commands/modlogs.ts | 1 - src/commands/notify.ts | 5 +- src/commands/tier.ts | 5 +- src/commands/warn.ts | 85 +++++++++++---------- src/commands/whois.ts | 5 +- src/commands/whois_user.ts | 5 +- src/events/messageCreate.ts | 88 +++++++++++----------- 13 files changed, 238 insertions(+), 248 deletions(-) diff --git a/src/class/Command.ts b/src/class/Command.ts index e1caa2c..0fb911e 100644 --- a/src/class/Command.ts +++ b/src/class/Command.ts @@ -1,42 +1,42 @@ -import { Message } from 'eris'; -import { Client } from '..'; -import { Collection } from '.'; - -export default class Command { - name: string - - parentName: string - - description?: string - - usage?: string - - enabled: boolean - - aliases?: string[] - - client: Client - - permissions?: { roles?: string[], users?: string[] } - - guildOnly?: boolean - - subcmds?: any[] - - subcommands?: Collection - - public run(message: Message, args: string[]) {} // eslint-disable-line - - constructor(client: Client) { - this.name = 'None'; - this.description = 'No description given'; - this.usage = 'No usage given'; - this.enabled = true; - this.aliases = []; - this.guildOnly = true; - this.client = client; - this.subcmds = []; - this.subcommands = new Collection(); - this.permissions = {}; - } -} +import { Message } from 'eris'; +import { Client } from '..'; +import { Collection } from '.'; + +export default class Command { + name: string + + parentName: string + + description?: string + + usage?: string + + enabled: boolean + + aliases?: string[] + + client: Client + + permissions?: { roles?: string[], users?: string[] } + + guildOnly?: boolean + + subcmds?: any[] + + subcommands?: Collection + + public run(message: Message, args: string[]): Promise { return Promise.resolve(); } + + constructor(client: Client) { + this.name = 'None'; + this.description = 'No description given'; + this.usage = 'No usage given'; + this.enabled = true; + this.aliases = []; + this.guildOnly = true; + this.client = client; + this.subcmds = []; + this.subcommands = new Collection(); + this.permissions = {}; + } +} diff --git a/src/commands/bearer.ts b/src/commands/bearer.ts index fd0d70a..74d9cf8 100644 --- a/src/commands/bearer.ts +++ b/src/commands/bearer.ts @@ -1,32 +1,31 @@ -/* eslint-disable consistent-return */ -import { Message } from 'eris'; -import { Command } from '../class'; -import { Client } from '..'; - -export default class Bearer extends Command { - constructor(client: Client) { - super(client); - this.name = 'bearer'; - this.description = 'Creates a bearer token.'; - this.usage = `${this.client.config.prefix}bearer`; - this.guildOnly = false; - this.enabled = true; - } - - public async run(message: Message) { - try { - const account = await this.client.db.Account.findOne({ userID: message.author.id }); - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); - // eslint-disable-next-line no-underscore-dangle - const bearer = await this.client.server.security.createBearer(account._id); - const dm = await this.client.getDMChannel(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}`); - message.channel.createMessage(`***${this.client.stores.emojis.success} Bearer token sent to direct messages.***`); - setTimeout(() => { - msg.delete(); - }, 60000); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} +import { Message } from 'eris'; +import { Command } from '../class'; +import { Client } from '..'; + +export default class Bearer extends Command { + constructor(client: Client) { + super(client); + this.name = 'bearer'; + this.description = 'Creates a bearer token.'; + this.usage = `${this.client.config.prefix}bearer`; + this.guildOnly = false; + this.enabled = true; + } + + public async run(message: Message) { + try { + const account = await this.client.db.Account.findOne({ userID: message.author.id }); + if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); + // eslint-disable-next-line no-underscore-dangle + const bearer = await this.client.server.security.createBearer(account._id); + const dm = await this.client.getDMChannel(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}`); + message.channel.createMessage(`***${this.client.stores.emojis.success} Bearer token sent to direct messages.***`); + return setTimeout(() => { + msg.delete(); + }, 60000); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/createaccount.ts b/src/commands/createaccount.ts index 15c04b5..d2eb954 100644 --- a/src/commands/createaccount.ts +++ b/src/commands/createaccount.ts @@ -1,5 +1,4 @@ import { Message, PrivateChannel, GroupChannel } from 'eris'; -import uuid from 'uuid/v4'; import { Client } from '..'; import { Command, RichEmbed } from '../class'; diff --git a/src/commands/disk.ts b/src/commands/disk.ts index b53b45c..5721961 100644 --- a/src/commands/disk.ts +++ b/src/commands/disk.ts @@ -3,7 +3,6 @@ import moment from 'moment'; import { Client } from '..'; import { RichEmbed, Command } from '../class'; import { dataConversion } from '../functions'; -// eslint-disable-next-line import/no-unresolved import 'moment-precise-range-plugin'; export default class Disk extends Command { diff --git a/src/commands/emailcode.ts b/src/commands/emailcode.ts index ad203c1..c4949d3 100644 --- a/src/commands/emailcode.ts +++ b/src/commands/emailcode.ts @@ -1,4 +1,3 @@ -/* eslint-disable consistent-return */ import { randomBytes } from 'crypto'; import { Message } from 'eris'; import { Client } from '..'; @@ -35,9 +34,9 @@ export default class EmailCode extends Command { `, }); - message.channel.createMessage(`***${this.client.stores.emojis.success} Code: \`${code}\` | Email Address: ${args[0]}***`); + return message.channel.createMessage(`***${this.client.stores.emojis.success} Code: \`${code}\` | Email Address: ${args[0]}***`); } catch (error) { - await this.client.util.handleError(error, message, this); + return this.client.util.handleError(error, message, this); } } } diff --git a/src/commands/eval.ts b/src/commands/eval.ts index 06fb02c..9cab205 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -1,69 +1,69 @@ -/* eslint-disable no-eval */ -import { Message } from 'eris'; -import { inspect } from 'util'; -import axios from 'axios'; -import { Client } from '..'; -import { Command } from '../class'; - -export default class Eval extends Command { - constructor(client: Client) { - super(client); - this.name = 'eval'; - this.aliases = ['e']; - this.description = 'Evaluate JavaScript code'; - this.enabled = true; - this.permissions = { users: ['253600545972027394', '278620217221971968', '155698776512790528'] }; - this.guildOnly = false; - } - - public async run(message: Message, args: string[]) { - try { - // const evalMessage = message.content.slice(this.client.config.prefix.length).split(' ').slice(1).join(' '); - let evalString = args.join(' ').trim(); - let evaled: any; - let depth = 0; - - if (args[0] && args[0].startsWith('-d')) { - depth = Number(args[0].replace('-d', '')); - if (!depth || depth < 0) depth = 0; - args.shift(); - evalString = args.join(' ').trim(); - } - if (args[0] === '-a' || args[0] === '-async') { - args.shift(); - evalString = `const top = this; (async () => { ${args.join(' ').trim()} })()`; - } - - try { - evaled = await eval(evalString); - if (typeof evaled !== 'string') { - evaled = inspect(evaled, { depth }); - } - if (evaled === undefined) { - evaled = 'undefined'; - } - } catch (error) { - evaled = error.stack; - } - - evaled = evaled.replace(new RegExp(this.client.config.token, 'gi'), 'juul'); - evaled = evaled.replace(new RegExp(this.client.config.emailPass, 'gi'), 'juul'); - evaled = evaled.replace(new RegExp(this.client.config.cloudflare, 'gi'), 'juul'); - - - const display = this.client.util.splitString(evaled, 1975); - if (display[5]) { - try { - const { data } = await axios.post('https://snippets.cloud.libraryofcode.org/documents', display.join('')); - return message.channel.createMessage(`${this.client.stores.emojis.success} Your evaluation evaled can be found on https://snippets.cloud.libraryofcode.org/${data.key}`); - } catch (error) { - return message.channel.createMessage(`${this.client.stores.emojis.error} ${error}`); - } - } - - return display.forEach((m) => message.channel.createMessage(`\`\`\`js\n${m}\n\`\`\``)); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} +/* eslint-disable no-eval */ +import { Message } from 'eris'; +import { inspect } from 'util'; +import axios from 'axios'; +import { Client } from '..'; +import { Command } from '../class'; + +export default class Eval extends Command { + constructor(client: Client) { + super(client); + this.name = 'eval'; + this.aliases = ['e']; + this.description = 'Evaluate JavaScript code'; + this.enabled = true; + this.permissions = { users: ['253600545972027394', '278620217221971968', '155698776512790528'] }; + this.guildOnly = false; + } + + public async run(message: Message, args: string[]) { + try { + const evalMessage = message.content.slice(this.client.config.prefix.length).split(' ').slice(1); + let evalString = evalMessage.join(' ').trim(); + let evaled: any; + let depth = 0; + + if (args[0] && args[0].startsWith('-d')) { + depth = Number(args[0].replace('-d', '')); + if (!depth || depth < 0) depth = 0; + const index = evalMessage.findIndex((v) => v.startsWith('-d')); + evalString = evalMessage.slice(index).join(' ').trim(); + } + if (args[0] === '-a') { + const index = evalMessage.findIndex((v) => v === '-a'); + evalString = `(async () => { ${evalMessage.slice(index).join(' ').trim()} })()`; + } + + try { + evaled = await eval(evalString); + if (typeof evaled !== 'string') { + evaled = inspect(evaled, { depth }); + } + if (evaled === undefined) { + evaled = 'undefined'; + } + } catch (error) { + evaled = error.stack; + } + + evaled = evaled.replace(new RegExp(this.client.config.token, 'gi'), 'juul'); + evaled = evaled.replace(new RegExp(this.client.config.emailPass, 'gi'), 'juul'); + evaled = evaled.replace(new RegExp(this.client.config.cloudflare, 'gi'), 'juul'); + + + const display = this.client.util.splitString(evaled, 1975); + if (display[5]) { + try { + const { data } = await axios.post('https://snippets.cloud.libraryofcode.org/documents', display.join('')); + return message.channel.createMessage(`${this.client.stores.emojis.success} Your evaluation evaled can be found on https://snippets.cloud.libraryofcode.org/${data.key}`); + } catch (error) { + return message.channel.createMessage(`${this.client.stores.emojis.error} ${error}`); + } + } + + return display.forEach((m) => message.channel.createMessage(`\`\`\`js\n${m}\n\`\`\``)); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/modlogs.ts b/src/commands/modlogs.ts index da620c2..4b9f60a 100644 --- a/src/commands/modlogs.ts +++ b/src/commands/modlogs.ts @@ -1,5 +1,4 @@ import { Message } from 'eris'; -// eslint-disable-next-line import/no-unresolved import { createPaginationEmbed } from 'eris-pagination'; import { Client } from '..'; import { Command, RichEmbed } from '../class'; diff --git a/src/commands/notify.ts b/src/commands/notify.ts index c7b4cfd..71fcaff 100644 --- a/src/commands/notify.ts +++ b/src/commands/notify.ts @@ -1,4 +1,3 @@ -/* eslint-disable consistent-return */ import { Message } from 'eris'; import { Client } from '..'; import { Command, RichEmbed } from '../class'; @@ -43,9 +42,9 @@ export default class Notify extends Command { `, }); message.delete(); - edit.edit(`***${this.client.stores.emojis.success} Send notification to ${account.username}.***`); + return edit.edit(`***${this.client.stores.emojis.success} Send notification to ${account.username}.***`); } catch (error) { - await this.client.util.handleError(error, message, this); + return this.client.util.handleError(error, message, this); } } } diff --git a/src/commands/tier.ts b/src/commands/tier.ts index 9c2c76f..5a13d98 100644 --- a/src/commands/tier.ts +++ b/src/commands/tier.ts @@ -1,4 +1,3 @@ -/* eslint-disable consistent-return */ import { Message } from 'eris'; import { Client } from '..'; import { Command, RichEmbed } from '../class'; @@ -33,9 +32,9 @@ export default class Tier extends Command { embed.addField('Old Tier -> New Tier', `${account.tier} -> ${args[1]}`, true); embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setTimestamp(); - this.client.createMessage('580950455581147146', { embed }); this.client.getDMChannel(account.userID).then((channel) => channel.createMessage({ embed })).catch(); + this.client.createMessage('580950455581147146', { embed }); return this.client.getDMChannel(account.userID).then((channel) => channel.createMessage({ embed })).catch(); } catch (error) { - await this.client.util.handleError(error, message, this); + return this.client.util.handleError(error, message, this); } } } diff --git a/src/commands/warn.ts b/src/commands/warn.ts index 49d66af..00e0bff 100644 --- a/src/commands/warn.ts +++ b/src/commands/warn.ts @@ -1,43 +1,42 @@ -/* eslint-disable consistent-return */ -import { Message } from 'eris'; -import { Client } from '..'; -import { Command } from '../class'; - -export default class Warn extends Command { - constructor(client: Client) { - super(client); - this.name = 'warn'; - this.description = 'Sends an official warning to user.'; - this.usage = `${this.client.config.prefix}warn [username | user ID]`; - this.permissions = { roles: ['446104438969466890'] }; - this.enabled = true; - } - - public async run(message: Message, args: string[]) { - try { - if (!args.length) return this.client.commands.get('help').run(message, [this.name]); - const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Sending warning...***`); - 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.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(' ')); - message.delete(); - edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been warned by Moderator ${message.author.username}#${message.author.discriminator}.***`); - this.client.util.transport.sendMail({ - to: account.emailAddress, - from: 'Library of Code sp-us | Cloud Services ', - subject: 'Your account has been warned', - html: ` -

    Library of Code sp-us | Cloud Services

    -

    Your account has received an official warning from a Moderator. Please get the underlying issue resolved to avoid possible moderative action.

    -

    Reason: ${args.slice(1).join(' ') ? args.slice(1).join(' ') : 'Not Specified'}

    -

    Moderator: ${message.author.username}

    - - Library of Code sp-us | Support Team - `, - }); - } catch (error) { - await this.client.util.handleError(error, message, this); - } - } -} +import { Message } from 'eris'; +import { Client } from '..'; +import { Command } from '../class'; + +export default class Warn extends Command { + constructor(client: Client) { + super(client); + this.name = 'warn'; + this.description = 'Sends an official warning to user.'; + this.usage = `${this.client.config.prefix}warn [username | user ID]`; + this.permissions = { roles: ['446104438969466890'] }; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + if (!args.length) return this.client.commands.get('help').run(message, [this.name]); + const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Sending warning...***`); + 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.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(' ')); + message.delete(); + edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been warned by Moderator ${message.author.username}#${message.author.discriminator}.***`); + return this.client.util.transport.sendMail({ + to: account.emailAddress, + from: 'Library of Code sp-us | Cloud Services ', + subject: 'Your account has been warned', + html: ` +

    Library of Code sp-us | Cloud Services

    +

    Your account has received an official warning from a Moderator. Please get the underlying issue resolved to avoid possible moderative action.

    +

    Reason: ${args.slice(1).join(' ') ? args.slice(1).join(' ') : 'Not Specified'}

    +

    Moderator: ${message.author.username}

    + + Library of Code sp-us | Support Team + `, + }); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/whois.ts b/src/commands/whois.ts index 38a74c0..fd05802 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -1,4 +1,3 @@ -/* eslint-disable consistent-return */ import moment from 'moment'; import { Message } from 'eris'; import { Client } from '..'; @@ -53,9 +52,9 @@ export default class Whois extends Command { if (details) embed.addField('Additional Details', details, true); embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setTimestamp(); - message.channel.createMessage({ embed }); + return message.channel.createMessage({ embed }); } catch (error) { - await this.client.util.handleError(error, message, this); + return this.client.util.handleError(error, message, this); } } } diff --git a/src/commands/whois_user.ts b/src/commands/whois_user.ts index e4076f8..9254e07 100644 --- a/src/commands/whois_user.ts +++ b/src/commands/whois_user.ts @@ -1,4 +1,3 @@ -/* eslint-disable consistent-return */ import moment from 'moment'; import { Message } from 'eris'; import { Client } from '..'; @@ -44,9 +43,9 @@ export default class Whois_User extends Command { if (details) embed.addField('Additional Details', details, true); embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setTimestamp(); - message.channel.createMessage({ embed }); + return message.channel.createMessage({ embed }); } catch (error) { - this.client.util.handleError(error, message, this); + return this.client.util.handleError(error, message, this); } } } diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts index b9048cb..39684d7 100644 --- a/src/events/messageCreate.ts +++ b/src/events/messageCreate.ts @@ -1,44 +1,44 @@ -import { Message, TextChannel } from 'eris'; -import { Client } from '..'; -import Command from '../class/Command'; - -export default class { - public client: Client - - constructor(client: Client) { - this.client = client; - } - - public async run(message: Message) { - try { - if (message.author.bot) return; - if (message.content.indexOf(this.client.config.prefix) !== 0) return; - const noPrefix: string[] = message.content.slice(this.client.config.prefix.length).trim().split(/ +/g); - const resolved = await this.client.util.resolveCommand(noPrefix, message); - if (!resolved) return; - if (resolved.cmd.guildOnly && !(message.channel instanceof TextChannel)) return; - let hasUserPerms: boolean; - if (resolved.cmd.permissions.users) { - hasUserPerms = resolved.cmd.permissions.users.includes(message.author.id); - } - let hasRolePerms: boolean = false; - if (resolved.cmd.permissions.roles) { - for (const role of resolved.cmd.permissions.roles) { - if (message.member && message.member.roles.includes(role)) { - // this.client.signale.debug(message.member.roles.includes(role)); - hasRolePerms = true; break; - } - } - } - if (!resolved.cmd.permissions.users && !resolved.cmd.permissions.roles) { - hasUserPerms = true; - hasRolePerms = true; - } - if (!hasRolePerms && !hasUserPerms) return; - if (!resolved.cmd.enabled) { message.channel.createMessage(`***${this.client.stores.emojis.error} This command has been disabled***`); return; } - resolved.cmd.run(message, resolved.args); - } catch (error) { - this.client.util.handleError(error, message); - } - } -} +import { Message, TextChannel } from 'eris'; +import { Client } from '..'; +import Command from '../class/Command'; + +export default class { + public client: Client + + constructor(client: Client) { + this.client = client; + } + + public async run(message: Message) { + try { + if (message.author.bot) return; + if (message.content.indexOf(this.client.config.prefix) !== 0) return; + const noPrefix: string[] = message.content.slice(this.client.config.prefix.length).trim().split(/ +/g); + const resolved = await this.client.util.resolveCommand(noPrefix, message); + if (!resolved) return; + if (resolved.cmd.guildOnly && !(message.channel instanceof TextChannel)) return; + let hasUserPerms: boolean; + if (resolved.cmd.permissions.users) { + hasUserPerms = resolved.cmd.permissions.users.includes(message.author.id); + } + let hasRolePerms: boolean = false; + if (resolved.cmd.permissions.roles) { + for (const role of resolved.cmd.permissions.roles) { + if (message.member && message.member.roles.includes(role)) { + // this.client.signale.debug(message.member.roles.includes(role)); + hasRolePerms = true; break; + } + } + } + if (!resolved.cmd.permissions.users && !resolved.cmd.permissions.roles) { + hasUserPerms = true; + hasRolePerms = true; + } + if (!hasRolePerms && !hasUserPerms) return; + if (!resolved.cmd.enabled) { message.channel.createMessage(`***${this.client.stores.emojis.error} This command has been disabled***`); return; } + await resolved.cmd.run(message, resolved.args); + } catch (error) { + this.client.util.handleError(error, message); + } + } +} -- 2.20.1 From f96b35f20e962cdf093e12e3bed21eb25785fd09 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 30 Mar 2020 16:41:06 +0100 Subject: [PATCH 169/516] Added command --- src/commands/cloudflare.ts | 40 ++++++++++++++++++++++++++++++++++++++ src/commands/index.ts | 1 + 2 files changed, 41 insertions(+) create mode 100644 src/commands/cloudflare.ts diff --git a/src/commands/cloudflare.ts b/src/commands/cloudflare.ts new file mode 100644 index 0000000..9be5417 --- /dev/null +++ b/src/commands/cloudflare.ts @@ -0,0 +1,40 @@ +import { Message } from 'eris'; +import axios from 'axios'; +import { Client } from '..'; +import { Command } from '../class'; + +export default class Cloudflare extends Command { + constructor(client: Client) { + super(client); + this.name = 'cloudflare'; + this.description = 'Remove an entry from Cloudflare DNS records'; + this.permissions = { + roles: ['525441307037007902'], + }; + this.aliases = ['cf']; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Locating entry...***`); + const { data } = await axios({ + method: 'get', + url: `https://api.cloudflare.com/client/v4/zones/5e82fc3111ed4fbf9f58caa34f7553a7/dns_records?name=${args[0]}`, + headers: { Authorization: `Bearer ${this.client.config.cloudflare}` }, + }); + if (!data.result.length) return msg.edit(`${this.client.stores.emojis.error} ***Entry not found***`); + msg.edit(`${this.client.stores.emojis.success} ***Located entry***\n${this.client.stores.emojis.loading} ***Deleting entry...***`); + const { id }: { id: string } = data.result[0]; + await axios({ + method: 'delete', + url: `https://api.cloudflare.com/client/v4/zones/5e82fc3111ed4fbf9f58caa34f7553a7/dns_records/${id}`, + headers: { Authorization: `Bearer ${this.client.config.cloudflare}` }, + }); + this.client.commands.get('cwg').subcommands.get('create').enabled = true; + return msg.edit(`${this.client.stores.emojis.success} ***Located entry***\n${this.client.stores.emojis.success} ***Deleted entry***`); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/index.ts b/src/commands/index.ts index 0abb76d..eb05106 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,5 +1,6 @@ export { default as announce } from './announce'; export { default as bearer } from './bearer'; +export { default as cloudflare } from './cloudflare'; export { default as createaccount } from './createaccount'; export { default as cwg } from './cwg'; export { default as deleteaccount } from './deleteaccount'; -- 2.20.1 From e3d6c108d7f2a65d57043713f258976116626639 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 30 Mar 2020 16:48:59 +0100 Subject: [PATCH 170/516] Bug fixes --- src/commands/cloudflare.ts | 1 + src/commands/cwg_create.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/cloudflare.ts b/src/commands/cloudflare.ts index 9be5417..6f0c7ce 100644 --- a/src/commands/cloudflare.ts +++ b/src/commands/cloudflare.ts @@ -17,6 +17,7 @@ export default class Cloudflare extends Command { public async run(message: Message, args: string[]) { try { + if (!args.length) return this.client.commands.get('help').run(message, ['cloudflare']); const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Locating entry...***`); const { data } = await axios({ method: 'get', diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index 33d009f..5855157 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -95,7 +95,7 @@ export default class CWG_Create extends Command { .setTimestamp(new Date(message.timestamp)); const completed = [ - edit.edit(`***${this.client.stores.emojis.success} Successfully binded ${domain.domain} to port ${domain.port} for ${account.userID}.***`), + edit.edit(`***${this.client.stores.emojis.success} Successfully binded ${domain.domain} to port ${domain.port} for ${account.username}.***`), this.client.createMessage('580950455581147146', { embed }), this.client.getDMChannel(account.userID).then((r) => r.createMessage({ embed })), this.client.util.transport.sendMail({ -- 2.20.1 From 16a6a01e6bc81e398a46991d7146b567ab936aba Mon Sep 17 00:00:00 2001 From: Bsian Date: Thu, 2 Apr 2020 01:04:08 +0100 Subject: [PATCH 171/516] trying to see where this shit breaks --- src/commands/eval.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index 9cab205..c79e73d 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -34,6 +34,8 @@ export default class Eval extends Command { evalString = `(async () => { ${evalMessage.slice(index).join(' ').trim()} })()`; } + message.channel.createMessage(`${evalString}`); + try { evaled = await eval(evalString); if (typeof evaled !== 'string') { -- 2.20.1 From 3651e9fcadbadaae553563ebabf78062eec5baed Mon Sep 17 00:00:00 2001 From: Bsian Date: Thu, 2 Apr 2020 01:07:37 +0100 Subject: [PATCH 172/516] trying to see where this shit breaks --- src/commands/eval.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index c79e73d..38c64ae 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -34,7 +34,7 @@ export default class Eval extends Command { evalString = `(async () => { ${evalMessage.slice(index).join(' ').trim()} })()`; } - message.channel.createMessage(`${evalString}`); + message.channel.createMessage(`${evalString}\n${args[0]}\n${args[1]}`); try { evaled = await eval(evalString); -- 2.20.1 From 12086cf8150c76d9864df8b03515c04accd34a4e Mon Sep 17 00:00:00 2001 From: Bsian Date: Thu, 2 Apr 2020 01:09:56 +0100 Subject: [PATCH 173/516] Fix? --- src/commands/eval.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index 38c64ae..8f1e49b 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -18,7 +18,7 @@ export default class Eval extends Command { public async run(message: Message, args: string[]) { try { - const evalMessage = message.content.slice(this.client.config.prefix.length).split(' ').slice(1); + const evalMessage = message.content.slice(this.client.config.prefix.length).trim().split(' ').slice(1); let evalString = evalMessage.join(' ').trim(); let evaled: any; let depth = 0; -- 2.20.1 From fa2a0c8c10cf01cc4a77885234e924ba489d4cef Mon Sep 17 00:00:00 2001 From: Bsian Date: Thu, 2 Apr 2020 01:11:29 +0100 Subject: [PATCH 174/516] trying to see where this shit breaks --- src/commands/eval.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index 8f1e49b..ba00814 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -31,6 +31,7 @@ export default class Eval extends Command { } if (args[0] === '-a') { const index = evalMessage.findIndex((v) => v === '-a'); + message.channel.createMessage(`${index}`); evalString = `(async () => { ${evalMessage.slice(index).join(' ').trim()} })()`; } -- 2.20.1 From 1d780c313da1bb1a80e9db9609f215a3a2f3c4e1 Mon Sep 17 00:00:00 2001 From: Bsian Date: Thu, 2 Apr 2020 01:14:24 +0100 Subject: [PATCH 175/516] Fix? --- src/commands/eval.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index ba00814..f5ea0cf 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -26,11 +26,11 @@ export default class Eval extends Command { if (args[0] && args[0].startsWith('-d')) { depth = Number(args[0].replace('-d', '')); if (!depth || depth < 0) depth = 0; - const index = evalMessage.findIndex((v) => v.startsWith('-d')); + const index = evalMessage.findIndex((v) => v.startsWith('-d')) + 1; evalString = evalMessage.slice(index).join(' ').trim(); } if (args[0] === '-a') { - const index = evalMessage.findIndex((v) => v === '-a'); + const index = evalMessage.findIndex((v) => v === '-a') + 1; message.channel.createMessage(`${index}`); evalString = `(async () => { ${evalMessage.slice(index).join(' ').trim()} })()`; } -- 2.20.1 From 9cff96318ad3bb2b93adedd5f46597edde535519 Mon Sep 17 00:00:00 2001 From: Bsian Date: Thu, 2 Apr 2020 01:15:33 +0100 Subject: [PATCH 176/516] Fix. --- src/commands/eval.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index f5ea0cf..1836ffc 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -31,12 +31,9 @@ export default class Eval extends Command { } if (args[0] === '-a') { const index = evalMessage.findIndex((v) => v === '-a') + 1; - message.channel.createMessage(`${index}`); evalString = `(async () => { ${evalMessage.slice(index).join(' ').trim()} })()`; } - message.channel.createMessage(`${evalString}\n${args[0]}\n${args[1]}`); - try { evaled = await eval(evalString); if (typeof evaled !== 'string') { -- 2.20.1 From 3dcff26c5924feaee41c53f34e0906f7d24ac160 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Thu, 2 Apr 2020 01:51:23 -0400 Subject: [PATCH 177/516] import of named module 'axios' should appear before destructured/local imports --- src/commands/cloudflare.ts | 2 +- src/commands/eval.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/cloudflare.ts b/src/commands/cloudflare.ts index 6f0c7ce..18958a6 100644 --- a/src/commands/cloudflare.ts +++ b/src/commands/cloudflare.ts @@ -1,5 +1,5 @@ -import { Message } from 'eris'; import axios from 'axios'; +import { Message } from 'eris'; import { Client } from '..'; import { Command } from '../class'; diff --git a/src/commands/eval.ts b/src/commands/eval.ts index 1836ffc..a0f0ea7 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -1,7 +1,7 @@ /* eslint-disable no-eval */ +import axios from 'axios'; import { Message } from 'eris'; import { inspect } from 'util'; -import axios from 'axios'; import { Client } from '..'; import { Command } from '../class'; -- 2.20.1 From 9adaa33636b4bc30e42aae4de6378413fde197d4 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Thu, 2 Apr 2020 01:51:46 -0400 Subject: [PATCH 178/516] update memory tier limits --- src/intervals/memory.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index b61451f..8127368 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -6,8 +6,8 @@ import { RichEmbed } from '../class'; const channelID = '691824484230889546'; const memoryLimits = { - TIER_1_SOFT: 200, - TIER_1_HARD: 350, + TIER_1_SOFT: 250, + TIER_1_HARD: 300, TIER_2_SOFT: 350, TIER_2_HARD: 400, TIER_3_SOFT: 500, -- 2.20.1 From 585b86f9a2cf2ecd8a6d4f1b58f8e9c0e9906be3 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Wed, 8 Apr 2020 07:02:49 -0400 Subject: [PATCH 179/516] change whois command styling --- src/commands/whois.ts | 20 +++++++++++++++----- src/commands/whois_user.ts | 21 +++++++++++++++------ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/commands/whois.ts b/src/commands/whois.ts index fd05802..945a67a 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -44,11 +44,21 @@ export default class Whois extends Command { const data = await this.client.redis.get(`storage-${account.username}`) ? dataConversion(Number(await this.client.redis.get(`storage-${account.username}`))) : 'N/A'; embed.addField('Storage', data, true); let details = ''; - if (account.locked) details += 'This account is currently locked.\n'; - if (account.permissions.facultyMarshal) details += 'This account belongs to a Faculty Marshal.\n'; - else if (account.permissions.sheriff) details += 'This account belongs to a Sheriff.\n'; - else if (account.permissions.staff) details += 'This account belongs to a Staff member.\n'; - if (account.root) details += 'This account has root/administrative privileges.\n'; + if (account.locked) details += '__This account is currently locked.__\n'; + if (account.permissions.facultyMarshal) { + details += 'This account belongs to a Faculty Marshal.\n'; + const roleColor = this.client.guilds.get('446067825673633794').roles.get('662163685439045632').color; + embed.setColor(roleColor); + } else if (account.permissions.sheriff) { + details += 'This account belongs to a Sheriff.\n'; + const roleColor = this.client.guilds.get('446067825673633794').roles.get('455972169449734144').color; + embed.setColor(roleColor); + } else if (account.permissions.staff) { + details += 'This account belongs to a Staff member.\n'; + const roleColor = this.client.guilds.get('446067825673633794').roles.get('453689940140883988').color; + embed.setColor(roleColor); + } else embed.setColor(0x36393f); + if (account.root) details += '**This account has root/administrative privileges.**\n'; if (details) embed.addField('Additional Details', details, true); embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setTimestamp(); diff --git a/src/commands/whois_user.ts b/src/commands/whois_user.ts index 9254e07..b9d99d4 100644 --- a/src/commands/whois_user.ts +++ b/src/commands/whois_user.ts @@ -23,7 +23,6 @@ export default class Whois_User extends Command { const embed = new RichEmbed(); embed.setTitle('Account Information'); if (this.client.users.get(account.userID)) embed.setThumbnail(this.client.users.get(account.userID).avatarURL); - embed.setColor(0x36393f); embed.addField('Username', `${account.username} | <@${account.userID}>`, true); embed.addField('ID', account.userID, true); embed.addField('Tier', String(account.tier), true); @@ -35,11 +34,21 @@ export default class Whois_User extends Command { const data = await this.client.redis.get(`storage-${account.username}`) ? dataConversion(Number(await this.client.redis.get(`storage-${account.username}`))) : 'N/A'; embed.addField('Storage', data, true); let details = ''; - if (account.locked) details += 'This account is currently locked.\n'; - if (account.permissions.facultyMarshal) details += 'This account belongs to a Faculty Marshal.\n'; - else if (account.permissions.sheriff) details += 'This account belongs to a Sheriff.\n'; - else if (account.permissions.staff) details += 'This account belongs to a Staff member.\n'; - if (account.root) details += 'This account has root/administrative privileges.\n'; + if (account.locked) details += '__This account is currently locked.__\n'; + if (account.permissions.facultyMarshal) { + details += 'This account belongs to a Faculty Marshal.\n'; + const roleColor = this.client.guilds.get('446067825673633794').roles.get('662163685439045632').color; + embed.setColor(roleColor); + } else if (account.permissions.sheriff) { + details += 'This account belongs to a Sheriff.\n'; + const roleColor = this.client.guilds.get('446067825673633794').roles.get('455972169449734144').color; + embed.setColor(roleColor); + } else if (account.permissions.staff) { + details += 'This account belongs to a Staff member.\n'; + const roleColor = this.client.guilds.get('446067825673633794').roles.get('453689940140883988').color; + embed.setColor(roleColor); + } else embed.setColor(0x36393f); + if (account.root) details += '**This account has root/administrative privileges.**\n'; if (details) embed.addField('Additional Details', details, true); embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setTimestamp(); -- 2.20.1 From 86668ead8ba85502855a8bdd61724d6b5dfc1411 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 19 Apr 2020 11:35:24 -0400 Subject: [PATCH 180/516] major permissions change --- src/commands/announce.ts | 2 +- src/commands/cloudflare.ts | 2 +- src/commands/createaccount.ts | 2 +- src/commands/cwg_create.ts | 2 +- src/commands/cwg_data.ts | 2 +- src/commands/cwg_delete.ts | 2 +- src/commands/cwg_updatecert.ts | 2 +- src/commands/deleteaccount.ts | 2 +- src/commands/disk.ts | 2 +- src/commands/emailcode.ts | 2 +- src/commands/load.ts | 2 +- src/commands/lock.ts | 2 +- src/commands/modlogs.ts | 2 +- src/commands/notify.ts | 2 +- src/commands/reload.ts | 19 +++++++++++++++++++ src/commands/resetpassword.ts | 2 +- src/commands/tier.ts | 2 +- src/commands/unban.ts | 2 +- src/commands/unlock.ts | 2 +- src/commands/warn.ts | 2 +- src/commands/whois.ts | 2 +- 21 files changed, 39 insertions(+), 20 deletions(-) create mode 100644 src/commands/reload.ts diff --git a/src/commands/announce.ts b/src/commands/announce.ts index 1b0207b..65cb8c6 100644 --- a/src/commands/announce.ts +++ b/src/commands/announce.ts @@ -9,7 +9,7 @@ export default class Announce extends Command { this.description = 'Sends an announcement to all active terminals'; this.usage = `${this.client.config.prefix}announce Hi there! | ${this.client.config.prefix}announce -e EMERGENCY!`; this.aliases = ['ann']; - this.permissions = { roles: ['662163685439045632'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/cloudflare.ts b/src/commands/cloudflare.ts index 18958a6..35bc18d 100644 --- a/src/commands/cloudflare.ts +++ b/src/commands/cloudflare.ts @@ -9,7 +9,7 @@ export default class Cloudflare extends Command { this.name = 'cloudflare'; this.description = 'Remove an entry from Cloudflare DNS records'; this.permissions = { - roles: ['525441307037007902'], + roles: ['662163685439045632'], }; this.aliases = ['cf']; this.enabled = true; diff --git a/src/commands/createaccount.ts b/src/commands/createaccount.ts index d2eb954..68da2d2 100644 --- a/src/commands/createaccount.ts +++ b/src/commands/createaccount.ts @@ -9,7 +9,7 @@ export default class CreateAccount extends Command { this.description = 'Create an account on the Cloud VM'; this.usage = `${this.client.config.prefix}createaccount [User ID] [Email] [Account name]`; this.aliases = ['createacc', 'cacc', 'caccount', 'create']; - this.permissions = { roles: ['662163685439045632', '455972169449734144'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index 5855157..86819b6 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -14,7 +14,7 @@ export default class CWG_Create extends Command { this.name = 'create'; this.description = 'Bind a domain to the CWG'; this.usage = `${this.client.config.prefix}cwg create [User ID | Username] [Domain] [Port] || Use snippets raw URL`; - this.permissions = { roles: ['525441307037007902'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300'] }; this.aliases = ['bind']; this.enabled = true; this.urlRegex = /^[a-zA-Z0-9\-._~:/?#[\]@!$&'()*+,;=]+$/; diff --git a/src/commands/cwg_data.ts b/src/commands/cwg_data.ts index 58c947f..01ed4a4 100644 --- a/src/commands/cwg_data.ts +++ b/src/commands/cwg_data.ts @@ -12,7 +12,7 @@ export default class CWG_Data extends Command { this.name = 'data'; this.description = 'Check CWG data'; this.usage = `${this.client.config.prefix}cwg data [Domain | Port]`; - this.permissions = { roles: ['446104438969466890'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/cwg_delete.ts b/src/commands/cwg_delete.ts index 53424c5..be9fd19 100644 --- a/src/commands/cwg_delete.ts +++ b/src/commands/cwg_delete.ts @@ -10,7 +10,7 @@ export default class CWG_Delete extends Command { this.name = 'delete'; this.description = 'Unbind a domain to the CWG'; this.usage = `${this.client.config.prefix}cwg delete [Domain | Port]`; - this.permissions = { roles: ['525441307037007902'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300'] }; this.aliases = ['unbind']; this.enabled = true; } diff --git a/src/commands/cwg_updatecert.ts b/src/commands/cwg_updatecert.ts index 6c58ed2..49087f2 100644 --- a/src/commands/cwg_updatecert.ts +++ b/src/commands/cwg_updatecert.ts @@ -10,7 +10,7 @@ export default class CWG_UpdateCert extends Command { this.name = 'updatecert'; this.description = 'Update a CWG certificate'; this.usage = `${this.client.config.prefix}cwg updatecert [Domain | Port] [Cert Chain] [Private Key] || Use snippets raw URL`; - this.permissions = { roles: ['525441307037007902'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300'] }; this.aliases = ['update', 'updatecrt', 'renew', 'renewcert', 'renewcrt']; this.enabled = true; } diff --git a/src/commands/deleteaccount.ts b/src/commands/deleteaccount.ts index 694fb79..61529e6 100644 --- a/src/commands/deleteaccount.ts +++ b/src/commands/deleteaccount.ts @@ -10,7 +10,7 @@ export default class DeleteAccount extends Command { this.description = 'Delete an account on the Cloud VM'; this.usage = `${this.client.config.prefix}deleteaccount [User Name | User ID | Email Address] [Reason]`; this.aliases = ['deleteacc', 'dacc', 'daccount', 'delete']; - this.permissions = { roles: ['662163685439045632'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300'] }; this.guildOnly = true; this.enabled = true; } diff --git a/src/commands/disk.ts b/src/commands/disk.ts index 5721961..48ecc57 100644 --- a/src/commands/disk.ts +++ b/src/commands/disk.ts @@ -11,7 +11,7 @@ export default class Disk extends Command { this.name = 'disk'; this.description = 'Checks the used disk space by a user'; this.usage = `${this.client.config.prefix}disk [Username/User ID/Email]`; - this.permissions = { roles: ['446104438969466890'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; this.enabled = false; } diff --git a/src/commands/emailcode.ts b/src/commands/emailcode.ts index c4949d3..e1acbf6 100644 --- a/src/commands/emailcode.ts +++ b/src/commands/emailcode.ts @@ -9,7 +9,7 @@ export default class EmailCode extends Command { this.name = 'emailcode'; this.description = 'Sends a code to an email address to use for address verification.'; this.usage = `${this.client.config.prefix}emailcode `; - this.permissions = { roles: ['446104438969466890'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; this.aliases = ['code']; this.enabled = true; } diff --git a/src/commands/load.ts b/src/commands/load.ts index 92ce2bd..39df7c9 100644 --- a/src/commands/load.ts +++ b/src/commands/load.ts @@ -8,7 +8,7 @@ export default class Load extends Command { this.name = 'load'; this.description = '(Re)loads command, config or util'; this.aliases = ['reload']; - this.permissions = { roles: ['525441307037007902'] }; + this.permissions = { roles: ['662163685439045632'] }; this.enabled = true; } diff --git a/src/commands/lock.ts b/src/commands/lock.ts index 245013a..77e6f8c 100644 --- a/src/commands/lock.ts +++ b/src/commands/lock.ts @@ -8,7 +8,7 @@ export default class Lock extends Command { super(client); this.name = 'lock'; this.description = 'Locks an account.'; - this.permissions = { roles: ['455972169449734144', '662163685439045632'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/modlogs.ts b/src/commands/modlogs.ts index 4b9f60a..b8cf5b9 100644 --- a/src/commands/modlogs.ts +++ b/src/commands/modlogs.ts @@ -10,7 +10,7 @@ export default class Modlogs extends Command { this.description = 'Check a user\'s Cloud Modlogs'; this.aliases = ['infractions', 'modlog']; this.enabled = true; - this.permissions = { roles: ['446104438969466890'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; } public async run(message: Message, args: string[]) { diff --git a/src/commands/notify.ts b/src/commands/notify.ts index 71fcaff..bff60d1 100644 --- a/src/commands/notify.ts +++ b/src/commands/notify.ts @@ -8,7 +8,7 @@ export default class Notify extends Command { this.name = 'notify'; this.description = 'Sends a notification to a user.'; this.usage = `${this.client.config.prefix}notify [username | user ID]`; - this.permissions = { roles: ['446104438969466890'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/reload.ts b/src/commands/reload.ts new file mode 100644 index 0000000..9aeb4c0 --- /dev/null +++ b/src/commands/reload.ts @@ -0,0 +1,19 @@ +/* eslint-disable consistent-return */ +import { Message } from 'eris'; +import { Command } from '../class'; +import { Client } from '..'; + +export default class Reload extends Command { + constructor(client: Client) { + super(client); + this.name = 'reload'; + this.description = 'Reloads a command.'; + this.usage = `${this.client.config.prefix}reload [command name]`; + this.permissions = { roles: ['525441307037007902'] }; + this.enabled = true; + } + + public run(message: Message, args: string[]): void { + if (!args.length) return this.client.commands.get('help').run(message, [this.name]); + } +} diff --git a/src/commands/resetpassword.ts b/src/commands/resetpassword.ts index ca38507..eddc7ef 100644 --- a/src/commands/resetpassword.ts +++ b/src/commands/resetpassword.ts @@ -10,7 +10,7 @@ export default class ResetPassword extends Command { this.description = 'Reset a cloud account password'; this.aliases = ['resetpasswd', 'resetpw']; this.usage = `${this.client.config.prefix}resetpassword [Username | User ID | Email]`; - this.permissions = { roles: ['662163685439045632'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/tier.ts b/src/commands/tier.ts index 5a13d98..15a353e 100644 --- a/src/commands/tier.ts +++ b/src/commands/tier.ts @@ -8,7 +8,7 @@ export default class Tier extends Command { this.name = 'tier'; this.description = 'Changes the tier level for an account.'; this.usage = `${this.client.config.prefix}tier <1 | 2 | 3>`; - this.permissions = { roles: ['446104438969466890'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/unban.ts b/src/commands/unban.ts index a443c99..dc5f5a7 100644 --- a/src/commands/unban.ts +++ b/src/commands/unban.ts @@ -10,7 +10,7 @@ export default class Unban extends Command { this.description = 'Unban an IP from Cloud/NGINX'; this.aliases = ['unbanip']; this.usage = `${this.client.config.prefix}unban [service] [ip]`; - this.permissions = { roles: ['455972169449734144', '662163685439045632'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/unlock.ts b/src/commands/unlock.ts index e4ee5da..e5ab578 100644 --- a/src/commands/unlock.ts +++ b/src/commands/unlock.ts @@ -7,7 +7,7 @@ export default class Unlock extends Command { super(client); this.name = 'unlock'; this.description = 'Unlocks an account.'; - this.permissions = { roles: ['455972169449734144', '662163685439045632'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/warn.ts b/src/commands/warn.ts index 00e0bff..5ee3a9d 100644 --- a/src/commands/warn.ts +++ b/src/commands/warn.ts @@ -8,7 +8,7 @@ export default class Warn extends Command { this.name = 'warn'; this.description = 'Sends an official warning to user.'; this.usage = `${this.client.config.prefix}warn [username | user ID]`; - this.permissions = { roles: ['446104438969466890'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/whois.ts b/src/commands/whois.ts index 945a67a..d29a364 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -12,7 +12,7 @@ export default class Whois extends Command { this.description = 'Views information for a cloud account.'; this.aliases = ['account', 'user']; this.usage = `${this.client.config.prefix}account [User Name | User ID | Email Address]`; - this.permissions = { roles: ['446104438969466890'] }; + this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; this.subcmds = [User]; this.enabled = true; } -- 2.20.1 From 910afefcbf2de4e859fa8484531c770425ffb84a Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 19 Apr 2020 12:37:43 -0400 Subject: [PATCH 181/516] perms change for pull cmd --- src/commands/pull.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/pull.ts b/src/commands/pull.ts index cdd0fe7..cc21674 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -9,7 +9,7 @@ export default class Pull extends Command { this.description = 'Fetches the latest commit from Gitlab'; this.aliases = ['update']; this.enabled = true; - this.permissions = { roles: ['525441307037007902'] }; + this.permissions = { roles: ['662163685439045632'] }; } public async run(message: Message) { -- 2.20.1 From 11cc0fcabb018e4459d7bc6200107ee6aaacba50 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 20 Apr 2020 16:04:38 -0400 Subject: [PATCH 182/516] update staff intervals/db entries --- src/commands/whois.ts | 10 +++++----- src/commands/whois_user.ts | 10 +++++----- src/intervals/checkStaffStatus.ts | 16 ++++++++-------- src/models/Account.ts | 8 ++++---- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/commands/whois.ts b/src/commands/whois.ts index d29a364..e1624c9 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -45,13 +45,13 @@ export default class Whois extends Command { embed.addField('Storage', data, true); let details = ''; if (account.locked) details += '__This account is currently locked.__\n'; - if (account.permissions.facultyMarshal) { - details += 'This account belongs to a Faculty Marshal.\n'; + if (account.permissions.director) { + details += 'This account belongs to a Director.\n'; const roleColor = this.client.guilds.get('446067825673633794').roles.get('662163685439045632').color; embed.setColor(roleColor); - } else if (account.permissions.sheriff) { - details += 'This account belongs to a Sheriff.\n'; - const roleColor = this.client.guilds.get('446067825673633794').roles.get('455972169449734144').color; + } else if (account.permissions.technician) { + details += 'This account belongs to a Technician.\n'; + const roleColor = this.client.guilds.get('701454780828221450').roles.get('701454780828221450').color; embed.setColor(roleColor); } else if (account.permissions.staff) { details += 'This account belongs to a Staff member.\n'; diff --git a/src/commands/whois_user.ts b/src/commands/whois_user.ts index b9d99d4..6a26ddd 100644 --- a/src/commands/whois_user.ts +++ b/src/commands/whois_user.ts @@ -35,13 +35,13 @@ export default class Whois_User extends Command { embed.addField('Storage', data, true); let details = ''; if (account.locked) details += '__This account is currently locked.__\n'; - if (account.permissions.facultyMarshal) { - details += 'This account belongs to a Faculty Marshal.\n'; + if (account.permissions.director) { + details += 'This account belongs to a Director.\n'; const roleColor = this.client.guilds.get('446067825673633794').roles.get('662163685439045632').color; embed.setColor(roleColor); - } else if (account.permissions.sheriff) { - details += 'This account belongs to a Sheriff.\n'; - const roleColor = this.client.guilds.get('446067825673633794').roles.get('455972169449734144').color; + } else if (account.permissions.technician) { + details += 'This account belongs to a Technician.\n'; + const roleColor = this.client.guilds.get('701454780828221450').roles.get('701454780828221450').color; embed.setColor(roleColor); } else if (account.permissions.staff) { details += 'This account belongs to a Staff member.\n'; diff --git a/src/intervals/checkStaffStatus.ts b/src/intervals/checkStaffStatus.ts index 2bc8448..b746e53 100644 --- a/src/intervals/checkStaffStatus.ts +++ b/src/intervals/checkStaffStatus.ts @@ -7,21 +7,21 @@ export default function checkStaffStatus(client: Client) { const accounts = await client.db.Account.find(); for (const acc of accounts) { const user = client.guilds.get('446067825673633794').members.get(acc.userID) || await client.guilds.get('446067825673633794').getRESTMember(acc.userID); - if (!acc.permissions.facultyMarshal && user.roles.includes('662163685439045632')) { - await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.facultyMarshal': true } }); + if (!acc.permissions.director && user.roles.includes('662163685439045632')) { + await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.director': true } }); } - if (!acc.permissions.sheriff && user.roles.includes('455972169449734144')) { - await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.sheriff': true } }); + if (!acc.permissions.technician && user.roles.includes('701454780828221450')) { + await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.technician': true } }); } if (!acc.permissions.staff && user.roles.includes('446104438969466890')) { await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.staff': true } }); } - if (acc.permissions.facultyMarshal && !user.roles.includes('662163685439045632')) { - await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.facultyMarshal': false } }); + if (acc.permissions.director && !user.roles.includes('662163685439045632')) { + await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.director': false } }); } - if (acc.permissions.sheriff && !user.roles.includes('455972169449734144')) { - await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.sheriff': false } }); + if (acc.permissions.technician && !user.roles.includes('701454780828221450')) { + await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.technician': false } }); } if (acc.permissions.staff && !user.roles.includes('446104438969466890')) { await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.staff': false } }); diff --git a/src/models/Account.ts b/src/models/Account.ts index 7ba490b..e105680 100644 --- a/src/models/Account.ts +++ b/src/models/Account.ts @@ -12,8 +12,8 @@ export interface AccountInterface extends Document { supportKey: string, permissions: { staff: boolean, - sheriff: boolean, - facultyMarshal: boolean, + technician: boolean, + director: boolean, }, root: boolean, hash: boolean, @@ -33,8 +33,8 @@ const Account: Schema = new Schema({ supportKey: String, permissions: { staff: Boolean, - sheriff: Boolean, - facultyMarshal: Boolean, + technician: Boolean, + director: Boolean, }, root: Boolean, hash: Boolean, -- 2.20.1 From f43ef83dda7576c98045f5aee68b9f76c8c05d84 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 20 Apr 2020 16:18:19 -0400 Subject: [PATCH 183/516] perm fix --- src/commands/announce.ts | 2 +- src/commands/createaccount.ts | 2 +- src/commands/cwg_create.ts | 2 +- src/commands/cwg_data.ts | 2 +- src/commands/cwg_delete.ts | 2 +- src/commands/cwg_updatecert.ts | 2 +- src/commands/deleteaccount.ts | 2 +- src/commands/disk.ts | 2 +- src/commands/emailcode.ts | 2 +- src/commands/lock.ts | 2 +- src/commands/modlogs.ts | 2 +- src/commands/notify.ts | 2 +- src/commands/resetpassword.ts | 2 +- src/commands/tier.ts | 2 +- src/commands/unban.ts | 2 +- src/commands/unlock.ts | 2 +- src/commands/warn.ts | 2 +- src/commands/whois.ts | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/commands/announce.ts b/src/commands/announce.ts index 65cb8c6..a8f92c1 100644 --- a/src/commands/announce.ts +++ b/src/commands/announce.ts @@ -9,7 +9,7 @@ export default class Announce extends Command { this.description = 'Sends an announcement to all active terminals'; this.usage = `${this.client.config.prefix}announce Hi there! | ${this.client.config.prefix}announce -e EMERGENCY!`; this.aliases = ['ann']; - this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; + this.permissions = { roles: ['662163685439045632', ' ', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/createaccount.ts b/src/commands/createaccount.ts index 68da2d2..1599ebf 100644 --- a/src/commands/createaccount.ts +++ b/src/commands/createaccount.ts @@ -9,7 +9,7 @@ export default class CreateAccount extends Command { this.description = 'Create an account on the Cloud VM'; this.usage = `${this.client.config.prefix}createaccount [User ID] [Email] [Account name]`; this.aliases = ['createacc', 'cacc', 'caccount', 'create']; - this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; + this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index 86819b6..a3120c4 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -14,7 +14,7 @@ export default class CWG_Create extends Command { this.name = 'create'; this.description = 'Bind a domain to the CWG'; this.usage = `${this.client.config.prefix}cwg create [User ID | Username] [Domain] [Port] || Use snippets raw URL`; - this.permissions = { roles: ['662163685439045632', '701454855952138300'] }; + this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; this.aliases = ['bind']; this.enabled = true; this.urlRegex = /^[a-zA-Z0-9\-._~:/?#[\]@!$&'()*+,;=]+$/; diff --git a/src/commands/cwg_data.ts b/src/commands/cwg_data.ts index 01ed4a4..19e9d35 100644 --- a/src/commands/cwg_data.ts +++ b/src/commands/cwg_data.ts @@ -12,7 +12,7 @@ export default class CWG_Data extends Command { this.name = 'data'; this.description = 'Check CWG data'; this.usage = `${this.client.config.prefix}cwg data [Domain | Port]`; - this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; + this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/cwg_delete.ts b/src/commands/cwg_delete.ts index be9fd19..38dd1e2 100644 --- a/src/commands/cwg_delete.ts +++ b/src/commands/cwg_delete.ts @@ -10,7 +10,7 @@ export default class CWG_Delete extends Command { this.name = 'delete'; this.description = 'Unbind a domain to the CWG'; this.usage = `${this.client.config.prefix}cwg delete [Domain | Port]`; - this.permissions = { roles: ['662163685439045632', '701454855952138300'] }; + this.permissions = { roles: ['662163685439045632'] }; this.aliases = ['unbind']; this.enabled = true; } diff --git a/src/commands/cwg_updatecert.ts b/src/commands/cwg_updatecert.ts index 49087f2..5e837e8 100644 --- a/src/commands/cwg_updatecert.ts +++ b/src/commands/cwg_updatecert.ts @@ -10,7 +10,7 @@ export default class CWG_UpdateCert extends Command { this.name = 'updatecert'; this.description = 'Update a CWG certificate'; this.usage = `${this.client.config.prefix}cwg updatecert [Domain | Port] [Cert Chain] [Private Key] || Use snippets raw URL`; - this.permissions = { roles: ['662163685439045632', '701454855952138300'] }; + this.permissions = { roles: ['662163685439045632'] }; this.aliases = ['update', 'updatecrt', 'renew', 'renewcert', 'renewcrt']; this.enabled = true; } diff --git a/src/commands/deleteaccount.ts b/src/commands/deleteaccount.ts index 61529e6..694fb79 100644 --- a/src/commands/deleteaccount.ts +++ b/src/commands/deleteaccount.ts @@ -10,7 +10,7 @@ export default class DeleteAccount extends Command { this.description = 'Delete an account on the Cloud VM'; this.usage = `${this.client.config.prefix}deleteaccount [User Name | User ID | Email Address] [Reason]`; this.aliases = ['deleteacc', 'dacc', 'daccount', 'delete']; - this.permissions = { roles: ['662163685439045632', '701454855952138300'] }; + this.permissions = { roles: ['662163685439045632'] }; this.guildOnly = true; this.enabled = true; } diff --git a/src/commands/disk.ts b/src/commands/disk.ts index 48ecc57..867a3e9 100644 --- a/src/commands/disk.ts +++ b/src/commands/disk.ts @@ -11,7 +11,7 @@ export default class Disk extends Command { this.name = 'disk'; this.description = 'Checks the used disk space by a user'; this.usage = `${this.client.config.prefix}disk [Username/User ID/Email]`; - this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; + this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; this.enabled = false; } diff --git a/src/commands/emailcode.ts b/src/commands/emailcode.ts index e1acbf6..d4947e2 100644 --- a/src/commands/emailcode.ts +++ b/src/commands/emailcode.ts @@ -9,7 +9,7 @@ export default class EmailCode extends Command { this.name = 'emailcode'; this.description = 'Sends a code to an email address to use for address verification.'; this.usage = `${this.client.config.prefix}emailcode `; - this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; + this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; this.aliases = ['code']; this.enabled = true; } diff --git a/src/commands/lock.ts b/src/commands/lock.ts index 77e6f8c..bf88d6b 100644 --- a/src/commands/lock.ts +++ b/src/commands/lock.ts @@ -8,7 +8,7 @@ export default class Lock extends Command { super(client); this.name = 'lock'; this.description = 'Locks an account.'; - this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; + this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/modlogs.ts b/src/commands/modlogs.ts index b8cf5b9..73ab718 100644 --- a/src/commands/modlogs.ts +++ b/src/commands/modlogs.ts @@ -10,7 +10,7 @@ export default class Modlogs extends Command { this.description = 'Check a user\'s Cloud Modlogs'; this.aliases = ['infractions', 'modlog']; this.enabled = true; - this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; + this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; } public async run(message: Message, args: string[]) { diff --git a/src/commands/notify.ts b/src/commands/notify.ts index bff60d1..8fc3583 100644 --- a/src/commands/notify.ts +++ b/src/commands/notify.ts @@ -8,7 +8,7 @@ export default class Notify extends Command { this.name = 'notify'; this.description = 'Sends a notification to a user.'; this.usage = `${this.client.config.prefix}notify [username | user ID]`; - this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; + this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/resetpassword.ts b/src/commands/resetpassword.ts index eddc7ef..e122f42 100644 --- a/src/commands/resetpassword.ts +++ b/src/commands/resetpassword.ts @@ -10,7 +10,7 @@ export default class ResetPassword extends Command { this.description = 'Reset a cloud account password'; this.aliases = ['resetpasswd', 'resetpw']; this.usage = `${this.client.config.prefix}resetpassword [Username | User ID | Email]`; - this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; + this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/tier.ts b/src/commands/tier.ts index 15a353e..6febb27 100644 --- a/src/commands/tier.ts +++ b/src/commands/tier.ts @@ -8,7 +8,7 @@ export default class Tier extends Command { this.name = 'tier'; this.description = 'Changes the tier level for an account.'; this.usage = `${this.client.config.prefix}tier <1 | 2 | 3>`; - this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; + this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/unban.ts b/src/commands/unban.ts index dc5f5a7..408e3e0 100644 --- a/src/commands/unban.ts +++ b/src/commands/unban.ts @@ -10,7 +10,7 @@ export default class Unban extends Command { this.description = 'Unban an IP from Cloud/NGINX'; this.aliases = ['unbanip']; this.usage = `${this.client.config.prefix}unban [service] [ip]`; - this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; + this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/unlock.ts b/src/commands/unlock.ts index e5ab578..81e757a 100644 --- a/src/commands/unlock.ts +++ b/src/commands/unlock.ts @@ -7,7 +7,7 @@ export default class Unlock extends Command { super(client); this.name = 'unlock'; this.description = 'Unlocks an account.'; - this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; + this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/warn.ts b/src/commands/warn.ts index 5ee3a9d..218307d 100644 --- a/src/commands/warn.ts +++ b/src/commands/warn.ts @@ -8,7 +8,7 @@ export default class Warn extends Command { this.name = 'warn'; this.description = 'Sends an official warning to user.'; this.usage = `${this.client.config.prefix}warn [username | user ID]`; - this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; + this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; this.enabled = true; } diff --git a/src/commands/whois.ts b/src/commands/whois.ts index e1624c9..5b129a2 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -12,7 +12,7 @@ export default class Whois extends Command { this.description = 'Views information for a cloud account.'; this.aliases = ['account', 'user']; this.usage = `${this.client.config.prefix}account [User Name | User ID | Email Address]`; - this.permissions = { roles: ['662163685439045632', '701454855952138300', '701454780828221450'] }; + this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; this.subcmds = [User]; this.enabled = true; } -- 2.20.1 From 7ec7c864cbb04dc1bf14097a6fe56b19d5a7615f Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 21 Apr 2020 14:59:53 -0400 Subject: [PATCH 184/516] fix issues with whois guild resolve --- src/commands/whois.ts | 2 +- src/commands/whois_user.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/whois.ts b/src/commands/whois.ts index 5b129a2..67d1f67 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -51,7 +51,7 @@ export default class Whois extends Command { embed.setColor(roleColor); } else if (account.permissions.technician) { details += 'This account belongs to a Technician.\n'; - const roleColor = this.client.guilds.get('701454780828221450').roles.get('701454780828221450').color; + const roleColor = this.client.guilds.get('446067825673633794').roles.get('701454780828221450').color; embed.setColor(roleColor); } else if (account.permissions.staff) { details += 'This account belongs to a Staff member.\n'; diff --git a/src/commands/whois_user.ts b/src/commands/whois_user.ts index 6a26ddd..b42b5fb 100644 --- a/src/commands/whois_user.ts +++ b/src/commands/whois_user.ts @@ -41,7 +41,7 @@ export default class Whois_User extends Command { embed.setColor(roleColor); } else if (account.permissions.technician) { details += 'This account belongs to a Technician.\n'; - const roleColor = this.client.guilds.get('701454780828221450').roles.get('701454780828221450').color; + const roleColor = this.client.guilds.get('446067825673633794').roles.get('701454780828221450').color; embed.setColor(roleColor); } else if (account.permissions.staff) { details += 'This account belongs to a Staff member.\n'; -- 2.20.1 From 3731ecb863974636ebd2887cecf51da6425d1987 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Thu, 23 Apr 2020 20:59:24 -0400 Subject: [PATCH 185/516] allow whois lookup by support key --- src/commands/whois.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/whois.ts b/src/commands/whois.ts index 67d1f67..5afa012 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -20,7 +20,7 @@ export default class Whois extends Command { public async run(message: Message, args: string[]) { try { if (!args[0]) 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] }, { supportKey: args[0].toUpperCase() }] }); if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found.***`); const embed = new RichEmbed(); embed.setTitle('Account Information'); -- 2.20.1 From 50a9d05f972c0d1bc6da418df59d380a2c89ebb5 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Fri, 1 May 2020 02:51:02 -0400 Subject: [PATCH 186/516] various changes --- src/class/AccountUtil.ts | 2 +- src/class/Util.ts | 10 +++++----- src/commands/createaccount.ts | 1 + src/commands/deleteaccount.ts | 7 ++++--- src/commands/lock.ts | 4 ++-- src/commands/notify.ts | 2 +- src/commands/sysinfo.ts | 4 ++-- src/commands/unban.ts | 2 +- src/commands/unlock.ts | 3 ++- src/commands/warn.ts | 4 ++-- 10 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/class/AccountUtil.ts b/src/class/AccountUtil.ts index 339f48d..43816e8 100644 --- a/src/class/AccountUtil.ts +++ b/src/class/AccountUtil.ts @@ -55,7 +55,7 @@ export default class AccountUtil {
  • #cloud-announcements - Announcements regarding the cloud machine will be here. These include planned maintenance, updates to preinstalled services etc.
  • #cloud-info - Important information you will need to, or should, know to a certain extent. These include our infractions system and Tier limits
  • #cloud-support - A support channel specifically for the cloud machine, you can use this to ask how to renew your certificates, for example
  • -
  • Library of Code Support Desk - Our Support desk, you can contact Staff here.
  • +
  • Library of Code Support Desk - Our Support desk, you can contact Staff here.
  • Want to support us?

    You can support us on Patreon! Head to our Patreon page and feel free to donate as much or as little as you want!
    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!

    diff --git a/src/class/Util.ts b/src/class/Util.ts index fb093d2..f834f51 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -229,11 +229,11 @@ export default class Util { let archType: string; switch (type) { default: archType = 'Staff'; embedTitle = 'Cloud Account | Generic'; color = '0892e1'; break; - case 0: archType = 'Administrator'; embedTitle = 'Cloud Account | Create'; color = '00ff00'; break; - case 1: archType = 'Staff'; embedTitle = 'Account Warning | Warn'; color = 'ffff00'; break; - case 2: archType = 'Moderator'; embedTitle = 'Account Infraction | Lock'; color = 'ff6600'; break; - case 3: archType = 'Moderator'; embedTitle = 'Account Reclaim | Unlock'; color = '0099ff'; break; - case 4: archType = 'Administrator'; embedTitle = 'Cloud Account | Delete'; color = 'ff0000'; break; + case 0: archType = 'Technician'; embedTitle = 'Cloud Account | Create'; color = '00ff00'; break; + case 1: archType = 'Technician'; embedTitle = 'Account Warning | Warn'; color = 'ffff00'; break; + case 2: archType = 'Technician'; embedTitle = 'Account Infraction | Lock'; color = 'ff6600'; break; + case 3: archType = 'Technician'; embedTitle = 'Account Reclaim | Unlock'; color = '0099ff'; break; + case 4: archType = 'Director'; embedTitle = 'Cloud Account | Delete'; color = 'ff0000'; break; } const embed = new RichEmbed() .setTitle(embedTitle) diff --git a/src/commands/createaccount.ts b/src/commands/createaccount.ts index 1599ebf..d9047b0 100644 --- a/src/commands/createaccount.ts +++ b/src/commands/createaccount.ts @@ -37,6 +37,7 @@ export default class CreateAccount extends Command { const confirmation = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Creating account...***`); const data = await this.client.util.accounts.createAccount({ userID: args[0], username: args[2], emailAddress: args[1] }, message.author.id); + message.delete(); return confirmation.edit(`${this.client.stores.emojis.success} ***Account successfully created***\n**Username:** \`${args[2]}\`\n**Temporary Password:** \`${data.tempPass}\``); } catch (error) { diff --git a/src/commands/deleteaccount.ts b/src/commands/deleteaccount.ts index 694fb79..28a4431 100644 --- a/src/commands/deleteaccount.ts +++ b/src/commands/deleteaccount.ts @@ -41,6 +41,7 @@ export default class DeleteAccount extends Command { if (reason) logInput.reason = reason; await this.client.util.createModerationLog(args[0], message.member, 4, reason); await this.client.util.deleteAccount(username); + message.delete(); this.client.util.transport.sendMail({ to: account.emailAddress, @@ -48,15 +49,15 @@ export default class DeleteAccount extends Command { subject: 'Your account has been deleted', html: `

    Library of Code | Cloud Services

    -

    Your Cloud Account has been deleted by our Engineers. If your account was deleted due to infractions, this will not be appealable. We're sorry to see you go.

    +

    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.

    Reason: ${reason}

    -

    Engineer: ${message.author.username}

    +

    Director: ${message.author.username}

    Library of Code sp-us | Support Team `, }); - return deleting.edit(`${this.client.stores.emojis.success} ***Account ${username} has been deleted by Engineer ${message.author.username}#${message.author.discriminator}***`); + return deleting.edit(`${this.client.stores.emojis.success} ***Account ${username} has been deleted by Director ${message.author.username}#${message.author.discriminator}***`); } catch (error) { return this.client.util.handleError(error, message, this); } diff --git a/src/commands/lock.ts b/src/commands/lock.ts index bf88d6b..17e3740 100644 --- a/src/commands/lock.ts +++ b/src/commands/lock.ts @@ -31,7 +31,7 @@ export default class Lock extends Command { const reason = momentMilliseconds ? args.slice(2).join(' ') : args.slice(1).join(' '); await this.client.util.createModerationLog(account.userID, message.member, 2, reason, momentMilliseconds); - edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been locked by Moderator ${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(); this.client.util.transport.sendMail({ @@ -42,7 +42,7 @@ export default class Lock extends Command {

    Library of Code | Cloud Services

    Your Cloud Account has been locked until ${momentMilliseconds ? moment(expiry).calendar() : 'indefinitely'} under the EULA.

    Reason: ${momentMilliseconds ? args.slice(2).join(' ') : args.slice(1).join(' ')}

    -

    Supervisor: ${message.author.username}

    +

    Technician: ${message.author.username}

    Expiration: ${momentMilliseconds ? moment(expiry).format('dddd, MMMM Do YYYY, h:mm:ss A') : 'N/A'}

    Library of Code sp-us | Support Team diff --git a/src/commands/notify.ts b/src/commands/notify.ts index 8fc3583..fcb57df 100644 --- a/src/commands/notify.ts +++ b/src/commands/notify.ts @@ -36,7 +36,7 @@ export default class Notify extends Command { html: `

    Library of Code sp-us | Cloud Services

    ${args.slice(1).join(' ')}

    -

    Moderator: ${message.author.username}

    +

    Technician: ${message.author.username}

    Library of Code sp-us | Support Team `, diff --git a/src/commands/sysinfo.ts b/src/commands/sysinfo.ts index 8925cae..6dc5ce9 100644 --- a/src/commands/sysinfo.ts +++ b/src/commands/sysinfo.ts @@ -26,8 +26,8 @@ export default class SysInfo extends Command { embed.addField('CPU', `${os.cpus()[0].model} ${os.cpus()[0].speed / 1000}GHz | ${os.cpus().length} Cores | ${os.arch()}`, true); embed.addField('Load Average (last 15 minutes)', os.loadavg()[2].toFixed(3), true); embed.addField('Memory/RAM', `${usedMemory} / ${dataConversion(totalmem())}`, true); - embed.addField('Network Interfaces (IPv4)', os.networkInterfaces().eth0.filter((r) => r.family === 'IPv4')[0].address, true); - embed.addField('Network Interfaces (IPv6)', os.networkInterfaces().eth0.filter((r) => r.family === 'IPv6')[0].address.replace(/:/gi, '\:'), true); // eslint-disable-line + embed.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.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setTimestamp(); message.channel.createMessage({ embed }); diff --git a/src/commands/unban.ts b/src/commands/unban.ts index 408e3e0..fca5352 100644 --- a/src/commands/unban.ts +++ b/src/commands/unban.ts @@ -11,7 +11,7 @@ export default class Unban extends Command { this.aliases = ['unbanip']; this.usage = `${this.client.config.prefix}unban [service] [ip]`; this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; - this.enabled = true; + this.enabled = false; } public async run(message: Message, args: string[]) { diff --git a/src/commands/unlock.ts b/src/commands/unlock.ts index 81e757a..66cb00f 100644 --- a/src/commands/unlock.ts +++ b/src/commands/unlock.ts @@ -23,7 +23,8 @@ export default class Unlock extends Command { await account.updateOne({ locked: false }); await this.client.util.createModerationLog(account.userID, message.member, 3, args.slice(1).join(' ')); - edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been unlocked by Moderator ${message.author.username}#${message.author.discriminator}.***`); + message.delete(); + edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been unlocked by Technician ${message.author.username}#${message.author.discriminator}.***`); } catch (error) { await this.client.util.handleError(error, message, this); } diff --git a/src/commands/warn.ts b/src/commands/warn.ts index 218307d..1c42332 100644 --- a/src/commands/warn.ts +++ b/src/commands/warn.ts @@ -21,7 +21,7 @@ export default class Warn extends Command { 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(' ')); message.delete(); - edit.edit(`***${this.client.stores.emojis.success} Account ${account.username} has been warned by Moderator ${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}.***`); return this.client.util.transport.sendMail({ to: account.emailAddress, from: 'Library of Code sp-us | Cloud Services ', @@ -30,7 +30,7 @@ export default class Warn extends Command {

    Library of Code sp-us | Cloud Services

    Your account has received an official warning from a Moderator. Please get the underlying issue resolved to avoid possible moderative action.

    Reason: ${args.slice(1).join(' ') ? args.slice(1).join(' ') : 'Not Specified'}

    -

    Moderator: ${message.author.username}

    +

    Technician: ${message.author.username}

    Library of Code sp-us | Support Team `, -- 2.20.1 From 961f0e6c748abc9a76e6bdf5280e18fb41ec8cdb Mon Sep 17 00:00:00 2001 From: Matthew R Date: Fri, 1 May 2020 17:45:53 -0400 Subject: [PATCH 187/516] fix issue with emailcode --- src/commands/emailcode.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/emailcode.ts b/src/commands/emailcode.ts index d4947e2..19e4ff8 100644 --- a/src/commands/emailcode.ts +++ b/src/commands/emailcode.ts @@ -16,6 +16,7 @@ export default class EmailCode extends Command { public async run(message: Message, args: string[]) { try { + if (!args.length) return this.client.commands.get('help').run(message, [this.name]); const code = randomBytes(5).toString('hex'); if (!this.client.util.isValidEmail(args[0])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid email address supplied.***`); this.client.util.transport.sendMail({ -- 2.20.1 From 2414c2aa6a5eb22d7b2c8e3b9198278da5673f1e Mon Sep 17 00:00:00 2001 From: Matthew R Date: Fri, 1 May 2020 17:46:05 -0400 Subject: [PATCH 188/516] change eval/exec perms --- src/commands/eval.ts | 2 +- src/commands/exec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index a0f0ea7..0f3bf3e 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -12,7 +12,7 @@ export default class Eval extends Command { this.aliases = ['e']; this.description = 'Evaluate JavaScript code'; this.enabled = true; - this.permissions = { users: ['253600545972027394', '278620217221971968', '155698776512790528'] }; + this.permissions = { users: ['253600545972027394', '278620217221971968', '239261547959025665'] }; this.guildOnly = false; } diff --git a/src/commands/exec.ts b/src/commands/exec.ts index f286635..c4363c6 100644 --- a/src/commands/exec.ts +++ b/src/commands/exec.ts @@ -10,7 +10,7 @@ export default class Exec extends Command { this.description = 'Executes command'; this.aliases = ['ex']; this.enabled = true; - this.permissions = { users: ['253600545972027394', '278620217221971968', '155698776512790528'] }; + this.permissions = { users: ['253600545972027394', '278620217221971968', '239261547959025665'] }; this.guildOnly = false; } -- 2.20.1 From 637c01ae49e4857e0cc07d59d052e45bc2096061 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 2 May 2020 02:34:40 -0400 Subject: [PATCH 189/516] command to view resource limits --- src/commands/limits.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/commands/limits.ts diff --git a/src/commands/limits.ts b/src/commands/limits.ts new file mode 100644 index 0000000..78bd292 --- /dev/null +++ b/src/commands/limits.ts @@ -0,0 +1,31 @@ +import { Message } from 'eris'; +import { Command, RichEmbed } from '../class'; +import { dataConversion } from '../functions'; +import { Client } from '..'; + +export default class SetLimit extends Command { + constructor(client: Client) { + super(client); + this.name = 'limits'; + this.description = 'Views resource limits for each tier.'; + this.usage = `${this.client.config.prefix}limits`; + this.subcmds = []; + this.enabled = true; + } + + public async run(message: Message) { + try { + const tiers = await this.client.db.Tier.find(); + const embed = new RichEmbed(); + embed.setTitle('Resource Limit Information'); + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + embed.setTimestamp(); + 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'}`); + } + return message.channel.createMessage({ embed }); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} -- 2.20.1 From 84cf60069f765d7f15b14e171e0df14505c85cfe Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 2 May 2020 02:34:52 -0400 Subject: [PATCH 190/516] commands to set resource limits --- src/commands/setlimit.ts | 23 +++++++++++++++++++++++ src/commands/setlimit_ram.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/commands/setlimit.ts create mode 100644 src/commands/setlimit_ram.ts diff --git a/src/commands/setlimit.ts b/src/commands/setlimit.ts new file mode 100644 index 0000000..741e63c --- /dev/null +++ b/src/commands/setlimit.ts @@ -0,0 +1,23 @@ +import { Message } from 'eris'; +import { Command } from '../class'; +import { Client } from '..'; + +export default class SetLimit extends Command { + constructor(client: Client) { + super(client); + this.name = 'setlimit'; + this.description = 'Sets resource limits for the various tiers'; + this.usage = `Run ${this.client.config.prefix}${this.name} [subcommand] for usage information`; + this.permissions = { roles: ['662163685439045632'] }; + this.subcmds = []; + this.enabled = true; + } + + public async run(message: Message) { + try { + return this.client.commands.get('help').run(message, [this.name]); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/setlimit_ram.ts b/src/commands/setlimit_ram.ts new file mode 100644 index 0000000..10f47c2 --- /dev/null +++ b/src/commands/setlimit_ram.ts @@ -0,0 +1,27 @@ +import { Message } from 'eris'; +import { Command } from '../class'; +import { Client } from '..'; + +export default class SetLimit_RAM extends Command { + constructor(client: Client) { + super(client); + this.name = 'ram'; + this.description = 'Sets tier limits for RAM.'; + this.usage = `${this.client.config.prefix}setlimit ram `; + this.permissions = { roles: ['662163685439045632'] }; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + if (!args[0]) return this.client.commands.get('help').run(message, ['setlimit', this.name]); + const tier = await this.client.db.Tier.findOne({ id: Number(args[0]) }); + if (!tier) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate that tier.***`); + if (Number.isNaN(Number(args[1]))) return message.channel.createMessage(`***${this.client.stores.emojis.error} This is not a valid number.***`); + await tier.updateOne({ 'resourceLimits.ram': Number(args[1]) }); + return message.channel.createMessage(`***${this.client.stores.emojis.success} Tier ${tier.id} RAM resource limit set to ${args[1]} MB.***`); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} -- 2.20.1 From 24715e77d6353fcd55734d3f05b831cc4389d905 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 2 May 2020 02:35:03 -0400 Subject: [PATCH 191/516] fixup of functions --- src/functions/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functions/index.ts b/src/functions/index.ts index 6afeb0e..8c3a5ac 100644 --- a/src/functions/index.ts +++ b/src/functions/index.ts @@ -1,4 +1,4 @@ -export { default as checkLock, clear as clearLock } from './checkLock'; +export { default as checkLock, clear as clearLock } from '../intervals/checkLock'; export { default as dataConversion } from './dataConversion'; // export { default as checkSS, clear as clearSS } from './checkSS'; export { default as parseCertificate, Certificate } from './parseCertificate'; -- 2.20.1 From 8df5589242f07225ed59373a2376a3b6b901d256 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 2 May 2020 02:35:17 -0400 Subject: [PATCH 192/516] fix of intervals, change how memory.ts gets info --- src/intervals/checkLock.ts | 31 ++++++++++++++++++++++++ src/intervals/checkSS.ts | 49 ++++++++++++++++++++++++++++++++++++++ src/intervals/memory.ts | 20 ++++------------ 3 files changed, 84 insertions(+), 16 deletions(-) create mode 100644 src/intervals/checkLock.ts create mode 100644 src/intervals/checkSS.ts diff --git a/src/intervals/checkLock.ts b/src/intervals/checkLock.ts new file mode 100644 index 0000000..da8d33f --- /dev/null +++ b/src/intervals/checkLock.ts @@ -0,0 +1,31 @@ +import { Client } from '..'; + +let interval: NodeJS.Timeout; + +export default function checkLock(client: Client) { + interval = setInterval(async () => { + try { + const moderations = await client.db.Moderation.find(); + moderations.forEach(async (moderation) => { + if (!moderation.expiration) return; + if (moderation.expiration.processed) return; + if (new Date() > moderation.expiration.date) { + const account = await client.db.Account.findOne({ username: moderation.username }); + if (!account) return; + await client.util.exec(`unlock ${account.username}`); + await moderation.updateOne({ 'expiration.processed': true }); + await account.updateOne({ locked: false }); + await client.util.createModerationLog(account.userID, client.user, 3, 'Auto'); + client.signale.complete(`Unlocked account ${account.username} | Queue date at ${moderation.expiration.date.toLocaleString('en-us')}`); + } + }); + } catch (error) { + await client.util.handleError(error); + } + }, 10000); + return interval; +} + +export function clear() { + clearInterval(interval); +} diff --git a/src/intervals/checkSS.ts b/src/intervals/checkSS.ts new file mode 100644 index 0000000..39cee9d --- /dev/null +++ b/src/intervals/checkSS.ts @@ -0,0 +1,49 @@ +/* eslint-disable consistent-return */ +/* eslint-disable no-unreachable */ +/* eslint-disable no-await-in-loop */ +import axios from 'axios'; +import { inspect } from 'util'; +import { Client } from '..'; + +let interval: NodeJS.Timeout; +export default function checkSS(client: Client) { + return; + interval = setInterval(async () => { + try { + const accounts = await client.db.Account.find(); + for (const { userID, homepath, hash } of accounts) { + try { + const Authorization = client.util.getAcctHash(homepath); + if (hash === null) throw new Error('Unable to locate auth file, homepath is probably incorrect'); + await axios({ + method: 'get', + url: 'https://api.securesign.org/account/details', + headers: { Authorization }, + }); + if (!hash) { + await client.db.Account.updateOne({ userID }, { $set: { hash: true } }); + client.getDMChannel(userID).then((channel) => channel.createMessage('Your SecureSign account has been automatically initialized via the SecureSign CLI.')).catch(); + } + } catch (error) { + if (!hash) return; + try { + const { status } = error.response; + if (status === 400 || status === 401 || status === 403 || status === 404) { + await client.db.Account.updateOne({ userID }, { $set: { hash: false } }); + client.getDMChannel(userID).then((channel) => channel.createMessage('Your SecureSign password has been reset - please reinitialize your SecureSign account. Run `=securesign init` for more information')).catch(); + } + } catch (e) { + throw error; + } + } + } + } catch (error) { + client.util.handleError(error); + } + }, 60000); + return interval; +} + +export function clear() { + clearTimeout(interval); +} diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 8127368..443a69f 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -2,6 +2,7 @@ /* eslint-disable no-await-in-loop */ import { Client } from '..'; import { RichEmbed } from '../class'; +import { TierInterface } from '../models'; const channelID = '691824484230889546'; @@ -25,22 +26,9 @@ export default function memory(client: Client) { // memory in megabytes const memoryConversion = mem / 1024 / 1024; const userLimits: { soft?: number, hard?: number } = {}; - switch (acc.tier) { - case 1: - userLimits.soft = memoryLimits.TIER_1_SOFT; - userLimits.hard = memoryLimits.TIER_1_HARD; - break; - case 2: - userLimits.soft = memoryLimits.TIER_2_SOFT; - userLimits.hard = memoryLimits.TIER_2_HARD; - break; - case 3: - userLimits.soft = memoryLimits.TIER_3_SOFT; - userLimits.hard = memoryLimits.TIER_3_HARD; - break; - default: - break; - } + const tier: TierInterface = await client.db.Tier.findOne({ id: acc.tier }).lean().exec(); + userLimits.soft = tier.resourceLimits.ram; + userLimits.hard = tier.resourceLimits.ram + 50; /* if the user has exceeded their soft memory limit, which is the one described in the resource limit guidelines, we'll inform staff. -- 2.20.1 From 688e24383932f6939a5a68026b14f45397c46e6f Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 2 May 2020 02:35:25 -0400 Subject: [PATCH 193/516] add tier model --- src/models/Tier.ts | 21 +++++++++++++++++++++ src/models/index.ts | 1 + 2 files changed, 22 insertions(+) create mode 100644 src/models/Tier.ts diff --git a/src/models/Tier.ts b/src/models/Tier.ts new file mode 100644 index 0000000..ca9e3cf --- /dev/null +++ b/src/models/Tier.ts @@ -0,0 +1,21 @@ +import { Document, Schema, model } from 'mongoose'; + +export interface TierInterface extends Document { + id: number, + resourceLimits: { + // in MB + ram: number, + // in MB + storage: number, + }, +} + +const Tier: Schema = new Schema({ + id: Number, + resourceLimits: { + ram: Number, + storage: Number, + }, +}, { id: false }); + +export default model('Tier', Tier); diff --git a/src/models/index.ts b/src/models/index.ts index 2dc3728..6cac9a8 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -1,3 +1,4 @@ export { default as Account, AccountInterface } from './Account'; export { default as Moderation, ModerationInterface } from './Moderation'; export { default as Domain, DomainInterface } from './Domain'; +export { default as Tier, TierInterface } from './Tier'; -- 2.20.1 From 9f2fdc6a173a5355f78966619e17a252e5285c87 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 2 May 2020 02:35:32 -0400 Subject: [PATCH 194/516] client changes --- src/Client.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index 9e1a074..236897d 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -5,7 +5,7 @@ import signale from 'signale'; import fs from 'fs-extra'; import config from './config.json'; import { Server } from './api'; -import { Account, AccountInterface, Moderation, ModerationInterface, Domain, DomainInterface } from './models'; +import { Account, AccountInterface, Moderation, ModerationInterface, Domain, DomainInterface, Tier, TierInterface } from './models'; import { emojis } from './stores'; import { Command, Util, Collection } from './class'; import * as commands from './commands'; @@ -18,12 +18,14 @@ export default class Client extends Eris.Client { public commands: Collection; - public db: { Account: mongoose.Model; Domain: mongoose.Model; Moderation: mongoose.Model; }; + public db: { Account: mongoose.Model; Domain: mongoose.Model; Moderation: mongoose.Model; Tier: mongoose.Model; }; public redis: Redis.Redis; public stores: { emojis: { success: string, loading: string, error: string }; }; + public functions: Collection; + public signale: signale.Signale; public server: Server; @@ -39,7 +41,8 @@ export default class Client extends Eris.Client { this.config = config; this.util = new Util(this); this.commands = new Collection(); - this.db = { Account, Domain, Moderation }; + this.functions = new Collection(); + this.db = { Account, Domain, Moderation, Tier }; this.redis = new Redis(); this.stores = { emojis }; this.signale = signale; @@ -64,9 +67,10 @@ export default class Client extends Eris.Client { private async loadFunctions() { const functions = await fs.readdir('./functions'); functions.forEach(async (func) => { - if (func === 'index.ts' || func === 'index.js' || func === 'dataConversion.js') return; + if (func === 'index.ts' || func === 'index.js') return; try { - (require(`./functions/${func}`).default)(this); + const funcRequire: Function = require(`./functions/${func}`).default; + this.functions.set(func.split('.')[0], funcRequire); } catch (error) { this.signale.error(`Error occured loading ${func}`); await this.util.handleError(error); -- 2.20.1 From 5e5735676b225f98a9e9885cd30b85ba9a8a858b Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 2 May 2020 02:41:10 -0400 Subject: [PATCH 195/516] update index --- src/commands/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/commands/index.ts b/src/commands/index.ts index eb05106..be52d7c 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -9,6 +9,7 @@ export { default as emailcode } from './emailcode'; export { default as eval } from './eval'; export { default as exec } from './exec'; export { default as help } from './help'; +export { default as limits } from './limits'; export { default as load } from './load'; export { default as lock } from './lock'; export { default as modlogs } from './modlogs'; @@ -20,6 +21,7 @@ export { default as pull } from './pull'; export { default as resetpassword } from './resetpassword'; export { default as restart } from './restart'; export { default as securesign } from './securesign'; +export { default as setlimit } from './setlimit'; export { default as sysinfo } from './sysinfo'; export { default as tier } from './tier'; export { default as unban } from './unban'; -- 2.20.1 From fbf75653a490858d00fc509b5fcd7023b47204f4 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 2 May 2020 02:44:17 -0400 Subject: [PATCH 196/516] more CHANges --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 10493bf..febdc18 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "ES2020", /* 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'. */ "lib": ["ES2019.Object", "ES2020.Promise"], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ -- 2.20.1 From 321878d85dad631eca72fc50a783709a8082f064 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 2 May 2020 02:47:04 -0400 Subject: [PATCH 197/516] changes to setlimit cmd --- src/commands/setlimit.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/setlimit.ts b/src/commands/setlimit.ts index 741e63c..60fd53b 100644 --- a/src/commands/setlimit.ts +++ b/src/commands/setlimit.ts @@ -1,6 +1,7 @@ import { Message } from 'eris'; import { Command } from '../class'; import { Client } from '..'; +import SetLimit_RAM from './setlimit_ram'; export default class SetLimit extends Command { constructor(client: Client) { @@ -9,7 +10,7 @@ export default class SetLimit extends Command { this.description = 'Sets resource limits for the various tiers'; this.usage = `Run ${this.client.config.prefix}${this.name} [subcommand] for usage information`; this.permissions = { roles: ['662163685439045632'] }; - this.subcmds = []; + this.subcmds = [SetLimit_RAM]; this.enabled = true; } -- 2.20.1 From 0a7ebc9f34f560f954fa5f6f58d4c2fffefe04cd Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 15:58:56 -0400 Subject: [PATCH 198/516] change hard designation to 5mb over instead of 50mb --- src/intervals/memory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 443a69f..a75b5ca 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -28,7 +28,7 @@ export default function memory(client: Client) { const userLimits: { soft?: number, hard?: number } = {}; const tier: TierInterface = await client.db.Tier.findOne({ id: acc.tier }).lean().exec(); userLimits.soft = tier.resourceLimits.ram; - userLimits.hard = tier.resourceLimits.ram + 50; + userLimits.hard = tier.resourceLimits.ram + 5; /* if the user has exceeded their soft memory limit, which is the one described in the resource limit guidelines, we'll inform staff. -- 2.20.1 From ee2ea41d8bd13faa814b39b6e66c3da53b05054a Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 16:35:47 -0400 Subject: [PATCH 199/516] changes to memory --- src/intervals/memory.ts | 97 +++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 33 deletions(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index a75b5ca..5dcfd01 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -16,6 +16,10 @@ const memoryLimits = { }; export default function memory(client: Client) { + const set = new Set(); + setInterval(() => { + set.clear(); + }, 3600000); setInterval(async () => { try { const accounts = await client.db.Account.find(); @@ -27,49 +31,76 @@ export default function memory(client: Client) { const memoryConversion = mem / 1024 / 1024; const userLimits: { soft?: number, hard?: number } = {}; const tier: TierInterface = await client.db.Tier.findOne({ id: acc.tier }).lean().exec(); - userLimits.soft = tier.resourceLimits.ram; - userLimits.hard = tier.resourceLimits.ram + 5; + userLimits.soft = tier.resourceLimits.ram - 50; + userLimits.hard = tier.resourceLimits.ram + 10; /* if the user has exceeded their soft memory limit, which is the one described in the resource limit guidelines, we'll inform staff. */ - if (memoryConversion >= userLimits.soft) { - client.signale.info(`RAM Soft Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.soft} MB`); + if (memoryConversion >= userLimits.hard && set.has(acc.username)) { + client.signale.info(`RAM Hard Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.hard} MB`); + client.util.exec(`killall -9 -u ${acc.username}`); const embed = new RichEmbed(); - if (client.users.get(acc.userID)) embed.setThumbnail(client.users.get(acc.userID).avatarURL); + 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.addField('User', `${acc.username} | <@${acc.userID}> | ${acc.userID}`, true); embed.addField('Tier', String(acc.tier), true); embed.addField('Memory Usage', `${String(memoryConversion)} MB`, true); - embed.addField('Memory Limit', `${String(userLimits.soft)} MB`, true); + embed.addField('Memory Limit', `${String(userLimits.hard)} MB`, true); + client.createMessage(channelID, { embed }); + client.util.createModerationLog(acc.userID, client.guilds.get('446067825673633794').members.get(client.user.id), 1, '[AUTO] Exceeded resource limit for RAM.'); + client.util.transport.sendMail({ + to: acc.emailAddress, + from: 'Library of Code sp-us | Cloud Services ', + subject: 'Your account has been warned', + html: ` +

    Library of Code sp-us | Cloud Services

    +

    Your account has received an official warning from a Technician. Please get the underlying issue resolved to avoid possible moderative action.

    +

    Reason: [AUTO] Exceeded resource limit for RAM.

    +

    Moderator: ${client.user.username}

    + + Library of Code sp-us | Support Team + `, + }); + client.createMessage(channelID, { embed }); + set.delete(acc.username); + } else if (memoryConversion >= userLimits.soft && !set.has(acc.username)) { + client.signale.info(`RAM Soft Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.soft} MB`); + const embed = new RichEmbed(); + if (client.users.get(acc.userID)) embed.setThumbnail(client.users.get(acc.userID).avatarURL); + embed.setTitle('Resource Limit Notification'); + 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('Tier', String(acc.tier), true); + embed.addField('Memory Usage', `${String(memoryConversion)} MB`, true); + embed.addField('Memory Limit', `${String(userLimits.hard)} MB`, true); embed.setFooter(client.user.username, client.user.avatarURL); embed.setTimestamp(); - - // if they exceed the hard limit, we'll kill all of their processes. - if (memoryConversion >= userLimits.hard) { - client.signale.info(`RAM Hard Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.hard} MB`); - client.util.exec(`killall -9 -u ${acc.username}`); - 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.'); - client.util.createModerationLog(acc.userID, client.guilds.get('446067825673633794').members.get(client.user.id), 1, '[AUTO] Exceeded resource limit for RAM.'); - client.util.transport.sendMail({ - to: acc.emailAddress, - from: 'Library of Code sp-us | Cloud Services ', - subject: 'Your account has been warned', - html: ` -

    Library of Code sp-us | Cloud Services

    -

    Your account has received an official warning from a Moderator. Please get the underlying issue resolved to avoid possible moderative action.

    -

    Reason: [AUTO] Exceeded resource limit for RAM.

    -

    Moderator: ${client.user.username}

    - - Library of Code sp-us | Support Team - `, - }); - } else { - embed.setTitle('Resource Limit Notification'); - embed.setDescription('Someone has reached the (soft) resource limit for their tier on RAM.'); - } - // @ts-ignore - client.createMessage(channelID, { embed }); + await client.createMessage(channelID, { embed }); + const notifyEmbed = new RichEmbed() + .setTitle('Cloud Account | Notification') + .setDescription(`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.`) + .addField('Technician', 'SYSTEM', true) + .setFooter(this.client.user.username, this.client.user.avatarURL) + .setTimestamp(); + this.client.getDMChannel(acc.userID).then((channel) => { + channel.createMessage({ notifyEmbed }); + }); + notifyEmbed.addField('User', `${acc.username} | <@${acc.userID}>`, true); + this.client.createMessage('580950455581147146', { embed }); + this.client.util.transport.sendMail({ + to: acc.emailAddress, + from: 'Library of Code sp-us | Cloud Services ', + subject: 'Notification', + html: ` +

    Library of Code sp-us | Cloud Services

    +

    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.

    +

    Technician: SYSTEM

    + + Library of Code sp-us | Support Team + `, + }); + set.add(acc.username); } } } catch (err) { -- 2.20.1 From b5a1744002d5c6eca9a14403a86c88353b297598 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 16:44:42 -0400 Subject: [PATCH 200/516] memory int various fixes --- src/intervals/memory.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 5dcfd01..a7fa307 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -37,7 +37,7 @@ export default function memory(client: Client) { /* if the user has exceeded their soft memory limit, which is the one described in the resource limit guidelines, we'll inform staff. */ - if (memoryConversion >= userLimits.hard && set.has(acc.username)) { + if ((memoryConversion >= userLimits.hard) && set.has(acc.username)) { client.signale.info(`RAM Hard Limit Reached | ${acc.username} | ${memoryConversion}/${userLimits.hard} MB`); client.util.exec(`killall -9 -u ${acc.username}`); const embed = new RichEmbed(); @@ -64,7 +64,7 @@ export default function memory(client: Client) { }); client.createMessage(channelID, { embed }); 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`); const embed = new RichEmbed(); if (client.users.get(acc.userID)) embed.setThumbnail(client.users.get(acc.userID).avatarURL); @@ -81,14 +81,14 @@ export default function memory(client: Client) { .setTitle('Cloud Account | Notification') .setDescription(`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.`) .addField('Technician', 'SYSTEM', true) - .setFooter(this.client.user.username, this.client.user.avatarURL) + .setFooter(client.user.username, client.user.avatarURL) .setTimestamp(); - this.client.getDMChannel(acc.userID).then((channel) => { - channel.createMessage({ notifyEmbed }); + client.getDMChannel(acc.userID).then((channel) => { + channel.createMessage({ embed: notifyEmbed }); }); notifyEmbed.addField('User', `${acc.username} | <@${acc.userID}>`, true); - this.client.createMessage('580950455581147146', { embed }); - this.client.util.transport.sendMail({ + client.createMessage('580950455581147146', { embed }); + client.util.transport.sendMail({ to: acc.emailAddress, from: 'Library of Code sp-us | Cloud Services ', subject: 'Notification', -- 2.20.1 From c3f6867f4b62761f8af5ca4c8d481b87675e48f2 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 17:48:40 -0400 Subject: [PATCH 201/516] set ram notification threshold default on account creation --- src/class/Util.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index f834f51..11e61d3 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -150,9 +150,10 @@ export default class Util { public async createAccount(hash: string, etcPasswd: string, username: string, userID: string, emailAddress: string, moderatorID: string, code: string): Promise { await this.exec(`useradd -m -p ${hash} -c ${etcPasswd} -s /bin/bash ${username}`); await this.exec(`chage -d0 ${username}`); + const tier = await this.client.db.Tier.findOne({ id: 1 }); const account = new this.client.db.Account({ - username, userID, emailAddress, createdBy: moderatorID, createdAt: new Date(), locked: false, tier: 1, supportKey: code, ssInit: false, homepath: `/home/${username}`, + username, userID, emailAddress, createdBy: moderatorID, ramLimitNotification: tier.resourceLimits.ram - 20, createdAt: new Date(), locked: false, tier: 1, supportKey: code, ssInit: false, homepath: `/home/${username}`, }); return account.save(); } -- 2.20.1 From 0182b0af144173295ba2fcd18608a2c8a6be9a82 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 17:48:58 -0400 Subject: [PATCH 202/516] commands for viewing limit and changing limit threshold --- src/commands/limits.ts | 16 ++++++++++-- src/commands/limits_setramnotification.ts | 31 +++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 src/commands/limits_setramnotification.ts diff --git a/src/commands/limits.ts b/src/commands/limits.ts index 78bd292..1db6bf4 100644 --- a/src/commands/limits.ts +++ b/src/commands/limits.ts @@ -1,15 +1,16 @@ import { Message } from 'eris'; import { Command, RichEmbed } from '../class'; import { dataConversion } from '../functions'; +import setRamNotification from './limits_setramnotification'; import { Client } from '..'; -export default class SetLimit extends Command { +export default class Limits extends Command { constructor(client: Client) { super(client); this.name = 'limits'; this.description = 'Views resource limits for each tier.'; this.usage = `${this.client.config.prefix}limits`; - this.subcmds = []; + this.subcmds = [setRamNotification]; this.enabled = true; } @@ -18,6 +19,17 @@ export default class SetLimit extends Command { const tiers = await this.client.db.Tier.find(); const embed = new RichEmbed(); embed.setTitle('Resource Limit Information'); + const account = await this.client.db.Account.findOne({ userID: message.author.id }); + if (account) { + const tier = await this.client.db.Tier.findOne({ id: account.tier }); + let msg: string; + if (account.ramLimitNotification !== -1) { + msg = `You will be notified when you are using ${account.ramLimitNotification} MB+.`; + } else { + msg = 'You will not be notified about impending resource limits for your account.'; + } + 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.setTimestamp(); for (const tier of tiers.sort((a, b) => a.id - b.id)) { diff --git a/src/commands/limits_setramnotification.ts b/src/commands/limits_setramnotification.ts new file mode 100644 index 0000000..11ecf9c --- /dev/null +++ b/src/commands/limits_setramnotification.ts @@ -0,0 +1,31 @@ +import { Message } from 'eris'; +import { Command, RichEmbed } from '../class'; +import { Client } from '..'; + +export default class Limits_SetRAMNotification extends Command { + constructor(client: Client) { + super(client); + 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.usage = `${this.client.config.prefix}limits set-ram-notification `; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + const account = await this.client.db.Account.findOne({ userID: message.author.id }); + if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} You do not have a Cloud Account.***`); + const tier = await this.client.db.Tier.findOne({ id: account.tier }); + if (Number(args[0]) >= tier.resourceLimits.ram) return message.channel.createMessage(`***${this.client.stores.emojis.error} You cannot set your notification limit to be set to or above your hard limit.***`); + if ((Number(args[0]) < 1) && (Number(args[0]) !== -1)) return message.channel.createMessage(`***${this.client.stores.emojis.error} You cannot set your notification limit to a negative number.***`); + if (Number(args[0]) === -1) { + await account.updateOne({ $set: { ramLimitNotification: -1 } }); + return message.channel.createMessage(`***${this.client.stores.emojis.success} You have disabled notifications.***`); + } + await account.updateOne({ $set: { ramLimitNotification: Number(args[0]) } }); + return message.channel.createMessage(`***${this.client.stores.emojis.success} You will now receive notifications when you go above ${Number(args[0])} MB.***`); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} -- 2.20.1 From 9836554be7da9f0544786a0efea84a2b454a4431 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 17:49:29 -0400 Subject: [PATCH 203/516] auto-update ram limit notification threshold on tier change --- src/commands/tier.ts | 7 ++++++- src/intervals/checkStaffStatus.ts | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/commands/tier.ts b/src/commands/tier.ts index 6febb27..0d2200e 100644 --- a/src/commands/tier.ts +++ b/src/commands/tier.ts @@ -22,7 +22,12 @@ export default class Tier extends Command { if (Number.isNaN(Number(args[1]))) return edit.edit(`***${this.client.stores.emojis.error} The tier you provided is not a valid number. It should be between 1 and 3.***`); if (Number(args[1]) > 3 || Number(args[1]) < 1) return edit.edit(`***${this.client.stores.emojis.error} You can only choose a Tier between 1 and 3.***`); message.delete(); - await account.updateOne({ $set: { tier: Number(args[1]) } }); + const tier = await this.client.db.Tier.findOne({ id: Number(args[1]) }); + if (account.ramLimitNotification !== -1) { + await account.updateOne({ $set: { tier: Number(args[1]), ramLimitNotification: tier.resourceLimits.ram - 20 } }); + } else { + 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]}.***`); const embed = new RichEmbed(); embed.setTitle('Cloud Account | Tier Change'); diff --git a/src/intervals/checkStaffStatus.ts b/src/intervals/checkStaffStatus.ts index b746e53..6ea44e2 100644 --- a/src/intervals/checkStaffStatus.ts +++ b/src/intervals/checkStaffStatus.ts @@ -6,15 +6,26 @@ export default function checkStaffStatus(client: Client) { setInterval(async () => { const accounts = await client.db.Account.find(); for (const acc of accounts) { + const tier3 = await client.db.Tier.findOne({ id: 3 }); + const user = client.guilds.get('446067825673633794').members.get(acc.userID) || await client.guilds.get('446067825673633794').getRESTMember(acc.userID); if (!acc.permissions.director && user.roles.includes('662163685439045632')) { await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.director': true } }); + if (acc.ramLimitNotification !== -1) { + await client.db.Account.updateOne({ username: acc.username }, { $set: { ramLimitNotification: tier3.resourceLimits.ram - 20 } }); + } } if (!acc.permissions.technician && user.roles.includes('701454780828221450')) { await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.technician': true } }); + if (acc.ramLimitNotification !== -1) { + await client.db.Account.updateOne({ username: acc.username }, { $set: { ramLimitNotification: tier3.resourceLimits.ram - 20 } }); + } } if (!acc.permissions.staff && user.roles.includes('446104438969466890')) { await client.db.Account.updateOne({ username: acc.username }, { $set: { 'permissions.staff': true } }); + if (acc.ramLimitNotification !== -1) { + await client.db.Account.updateOne({ username: acc.username }, { $set: { ramLimitNotification: tier3.resourceLimits.ram - 20 } }); + } } if (acc.permissions.director && !user.roles.includes('662163685439045632')) { -- 2.20.1 From 7897ff2165e10d8410d29db97efdfb15fe215e80 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 17:49:40 -0400 Subject: [PATCH 204/516] update account model --- src/models/Account.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/models/Account.ts b/src/models/Account.ts index e105680..1af607d 100644 --- a/src/models/Account.ts +++ b/src/models/Account.ts @@ -15,6 +15,7 @@ export interface AccountInterface extends Document { technician: boolean, director: boolean, }, + ramLimitNotification: number, root: boolean, hash: boolean, salt: string, @@ -36,6 +37,7 @@ const Account: Schema = new Schema({ technician: Boolean, director: Boolean, }, + ramLimitNotification: Number, root: Boolean, hash: Boolean, salt: String, -- 2.20.1 From 3985b0c3aaa221bf2dca8e7fe70e6999a2641ef5 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 17:49:50 -0400 Subject: [PATCH 205/516] multiple changes to memory notification handling --- src/intervals/memory.ts | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index a7fa307..d80685a 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -33,7 +33,9 @@ export default function memory(client: Client) { const tier: TierInterface = await client.db.Tier.findOne({ id: acc.tier }).lean().exec(); userLimits.soft = tier.resourceLimits.ram - 50; userLimits.hard = tier.resourceLimits.ram + 10; - + if (memoryConversion <= userLimits.soft) { + set.delete(acc.username); + } /* if the user has exceeded their soft memory limit, which is the one described in the resource limit guidelines, we'll inform staff. */ @@ -77,29 +79,32 @@ export default function memory(client: Client) { embed.setFooter(client.user.username, client.user.avatarURL); embed.setTimestamp(); await client.createMessage(channelID, { embed }); - const notifyEmbed = new RichEmbed() - .setTitle('Cloud Account | Notification') - .setDescription(`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.`) - .addField('Technician', 'SYSTEM', true) - .setFooter(client.user.username, client.user.avatarURL) - .setTimestamp(); - client.getDMChannel(acc.userID).then((channel) => { - channel.createMessage({ embed: notifyEmbed }); - }); - notifyEmbed.addField('User', `${acc.username} | <@${acc.userID}>`, true); - client.createMessage('580950455581147146', { embed }); - client.util.transport.sendMail({ - to: acc.emailAddress, - from: 'Library of Code sp-us | Cloud Services ', - subject: 'Notification', - html: ` + if (memoryConversion >= acc.ramLimitNotification) { + if (acc.ramLimitNotification === -1) return; + const notifyEmbed = new RichEmbed() + .setTitle('Cloud Account | Notification') + .setDescription(`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.\nYou can set your notification preferences by running \`=limits set-ram-notification \`, you can disable these notifications by running \`=limits set-ram-notification -1\`.`) + .addField('User', `${acc.username} | <@${acc.userID}>`, true) + .addField('Technician', 'SYSTEM', true) + .setFooter(client.user.username, client.user.avatarURL) + .setTimestamp(); + client.getDMChannel(acc.userID).then((channel) => { + channel.createMessage({ embed: notifyEmbed }); + }); + client.util.transport.sendMail({ + to: acc.emailAddress, + from: 'Library of Code sp-us | Cloud Services ', + subject: 'Notification', + html: `

    Library of Code sp-us | Cloud Services

    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.

    Technician: SYSTEM

    Library of Code sp-us | Support Team `, - }); + }); + } + client.createMessage('580950455581147146', { embed }); set.add(acc.username); } } -- 2.20.1 From 4f1a9b01d900583aa0a0cd5de8e5c155ce589ff7 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 17:50:06 -0400 Subject: [PATCH 206/516] function for updating all existing accounts --- src/functions/existingLimitsSetup.ts | 26 ++++++++++++++++++++++++++ src/functions/index.ts | 1 + 2 files changed, 27 insertions(+) create mode 100644 src/functions/existingLimitsSetup.ts diff --git a/src/functions/existingLimitsSetup.ts b/src/functions/existingLimitsSetup.ts new file mode 100644 index 0000000..5b7a572 --- /dev/null +++ b/src/functions/existingLimitsSetup.ts @@ -0,0 +1,26 @@ +import { Client } from '..'; + +export default async function existingLimitsSetup(client: Client): Promise { + const tier1 = await client.db.Tier.findOne({ id: 1 }); + const tier2 = await client.db.Tier.findOne({ id: 2 }); + const tier3 = await await client.db.Tier.findOne({ id: 3 }); + + const accounts = await client.db.Account.find(); + let numOfAccountsUpdated = 0; + + for (const account of accounts) { + if (account.tier === 1) { + account.updateOne({ $set: { ramLimitNotification: tier1.resourceLimits.ram - 20 } }); + numOfAccountsUpdated += 1; + } + if (account.tier === 2) { + account.updateOne({ $set: { ramLimitNotification: tier2.resourceLimits.ram - 20 } }); + numOfAccountsUpdated += 1; + } + if (account.tier === 3) { + account.updateOne({ $set: { ramLimitNotification: tier3.resourceLimits.ram - 20 } }); + numOfAccountsUpdated += 1; + } + } + return numOfAccountsUpdated; +} diff --git a/src/functions/index.ts b/src/functions/index.ts index 8c3a5ac..b933c35 100644 --- a/src/functions/index.ts +++ b/src/functions/index.ts @@ -1,4 +1,5 @@ export { default as checkLock, clear as clearLock } from '../intervals/checkLock'; export { default as dataConversion } from './dataConversion'; +export { default as existingLimitsSetup } from './existingLimitsSetup'; // export { default as checkSS, clear as clearSS } from './checkSS'; export { default as parseCertificate, Certificate } from './parseCertificate'; -- 2.20.1 From a67cc4d59518b1b2f02e01b2879e953990244773 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 17:56:27 -0400 Subject: [PATCH 207/516] fixes --- src/functions/existingLimitsSetup.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/functions/existingLimitsSetup.ts b/src/functions/existingLimitsSetup.ts index 5b7a572..a0bce3a 100644 --- a/src/functions/existingLimitsSetup.ts +++ b/src/functions/existingLimitsSetup.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-await-in-loop */ import { Client } from '..'; export default async function existingLimitsSetup(client: Client): Promise { @@ -10,15 +11,15 @@ export default async function existingLimitsSetup(client: Client): Promise Date: Sun, 3 May 2020 18:23:28 -0400 Subject: [PATCH 208/516] fixes --- src/intervals/memory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index d80685a..f0367b7 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -31,7 +31,7 @@ export default function memory(client: Client) { const memoryConversion = mem / 1024 / 1024; const userLimits: { soft?: number, hard?: number } = {}; const tier: TierInterface = await client.db.Tier.findOne({ id: acc.tier }).lean().exec(); - userLimits.soft = tier.resourceLimits.ram - 50; + userLimits.soft = acc.ramLimitNotification; userLimits.hard = tier.resourceLimits.ram + 10; if (memoryConversion <= userLimits.soft) { set.delete(acc.username); -- 2.20.1 From f87a02fd17ac0380873e70489f64bff0c7f880c4 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 18:31:31 -0400 Subject: [PATCH 209/516] fixes --- src/intervals/memory.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index f0367b7..fd0d3b6 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -83,7 +83,7 @@ export default function memory(client: Client) { if (acc.ramLimitNotification === -1) return; const notifyEmbed = new RichEmbed() .setTitle('Cloud Account | Notification') - .setDescription(`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.\nYou can set your notification preferences by running \`=limits set-ram-notification \`, you can disable these notifications by running \`=limits set-ram-notification -1\`.`) + .setDescription(`You are about to reach your RAM resource limits, you are currently using '${String(memoryConversion)} MB' and your limit is '${String(userLimits.hard - 10)} MB'. Please correct your usage to avoid further action.\nYou can set your notification preferences by running \`=limits set-ram-notification \`, you can disable these notifications by running \`=limits set-ram-notification -1\`.`) .addField('User', `${acc.username} | <@${acc.userID}>`, true) .addField('Technician', 'SYSTEM', true) .setFooter(client.user.username, client.user.avatarURL) @@ -103,8 +103,8 @@ export default function memory(client: Client) { Library of Code sp-us | Support Team `, }); + client.createMessage('580950455581147146', { embed: notifyEmbed }); } - client.createMessage('580950455581147146', { embed }); set.add(acc.username); } } -- 2.20.1 From 9201599aae05f8767ffeeaa6260f6bf99e6d843b Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 18:36:18 -0400 Subject: [PATCH 210/516] fixes --- src/intervals/memory.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index fd0d3b6..c3390c9 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -17,9 +17,6 @@ const memoryLimits = { export default function memory(client: Client) { const set = new Set(); - setInterval(() => { - set.clear(); - }, 3600000); setInterval(async () => { try { const accounts = await client.db.Account.find(); -- 2.20.1 From 911218cdafcb818e676b63688d6352b0e286a547 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sun, 3 May 2020 23:47:44 +0100 Subject: [PATCH 211/516] Set disable notif value to 0 --- src/commands/limits_setramnotification.ts | 4 ++-- src/intervals/memory.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commands/limits_setramnotification.ts b/src/commands/limits_setramnotification.ts index 11ecf9c..aa60271 100644 --- a/src/commands/limits_setramnotification.ts +++ b/src/commands/limits_setramnotification.ts @@ -17,8 +17,8 @@ export default class Limits_SetRAMNotification extends Command { if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} You do not have a Cloud Account.***`); const tier = await this.client.db.Tier.findOne({ id: account.tier }); if (Number(args[0]) >= tier.resourceLimits.ram) return message.channel.createMessage(`***${this.client.stores.emojis.error} You cannot set your notification limit to be set to or above your hard limit.***`); - if ((Number(args[0]) < 1) && (Number(args[0]) !== -1)) return message.channel.createMessage(`***${this.client.stores.emojis.error} You cannot set your notification limit to a negative number.***`); - if (Number(args[0]) === -1) { + if (Number(args[0]) < 0) return message.channel.createMessage(`***${this.client.stores.emojis.error} You cannot set your notification limit to a negative number.***`); + if (Number(args[0]) === 0) { await account.updateOne({ $set: { ramLimitNotification: -1 } }); return message.channel.createMessage(`***${this.client.stores.emojis.success} You have disabled notifications.***`); } diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index c3390c9..81702fd 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -77,7 +77,7 @@ export default function memory(client: Client) { embed.setTimestamp(); await client.createMessage(channelID, { embed }); if (memoryConversion >= acc.ramLimitNotification) { - if (acc.ramLimitNotification === -1) return; + if (acc.ramLimitNotification === 0) return; const notifyEmbed = new RichEmbed() .setTitle('Cloud Account | Notification') .setDescription(`You are about to reach your RAM resource limits, you are currently using '${String(memoryConversion)} MB' and your limit is '${String(userLimits.hard - 10)} MB'. Please correct your usage to avoid further action.\nYou can set your notification preferences by running \`=limits set-ram-notification \`, you can disable these notifications by running \`=limits set-ram-notification -1\`.`) -- 2.20.1 From eb1cce3d70eb186186c8e2dd60cdc6e118699aee Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 18:49:03 -0400 Subject: [PATCH 212/516] fixes --- src/intervals/memory.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index c3390c9..998ed29 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -76,8 +76,7 @@ export default function memory(client: Client) { embed.setFooter(client.user.username, client.user.avatarURL); embed.setTimestamp(); await client.createMessage(channelID, { embed }); - if (memoryConversion >= acc.ramLimitNotification) { - if (acc.ramLimitNotification === -1) return; + if ((memoryConversion >= acc.ramLimitNotification) && (acc.ramLimitNotification !== -1)) { const notifyEmbed = new RichEmbed() .setTitle('Cloud Account | Notification') .setDescription(`You are about to reach your RAM resource limits, you are currently using '${String(memoryConversion)} MB' and your limit is '${String(userLimits.hard - 10)} MB'. Please correct your usage to avoid further action.\nYou can set your notification preferences by running \`=limits set-ram-notification \`, you can disable these notifications by running \`=limits set-ram-notification -1\`.`) -- 2.20.1 From 2a6af24499f9420d00b03be3e5ab65219383d691 Mon Sep 17 00:00:00 2001 From: Bsian Date: Sun, 3 May 2020 23:55:57 +0100 Subject: [PATCH 213/516] Only show command line output on error --- src/commands/pull.ts | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/src/commands/pull.ts b/src/commands/pull.ts index cc21674..8ab1183 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -16,31 +16,28 @@ export default class Pull extends Command { try { if (this.client.updating) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Update in progress***`); this.client.updating = true; - const updateMessage = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Fetching latest commit...***\n\`\`\`sh\n$ git pull\n\`\`\``); + const updateMessage = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Fetching latest commit...***`); let pull: string; try { pull = await this.client.util.exec('git pull', { cwd: '/opt/CloudServices' }); } catch (error) { - const updatedMessage = updateMessage.content.replace(`${this.client.stores.emojis.loading} ***Fetching latest commit...***`, `${this.client.stores.emojis.error} ***Could not fetch latest commit***`) - .replace(/```$/, `${error.message}\n\`\`\``); + const updatedMessage = updateMessage.content.replace(`${this.client.stores.emojis.loading} ***Fetching latest commit...***`, `${this.client.stores.emojis.error} ***Could not fetch latest commit***\n` + + `\`\`\`\n${error.message}\n\`\`\``); this.client.updating = false; return updateMessage.edit(updatedMessage); } if (pull.includes('Already up to date')) { - const updatedMessage = updateMessage.content.replace(`${this.client.stores.emojis.loading} ***Fetching latest commit...***`, `${this.client.stores.emojis.success} ***No updates available***`) - .replace(/```$/, `${pull}\n\`\`\``); + const updatedMessage = updateMessage.content.replace(`${this.client.stores.emojis.loading} ***Fetching latest commit...***`, `${this.client.stores.emojis.success} ***No updates available***`); this.client.updating = false; return updateMessage.edit(updatedMessage); } if (!pull.includes('origin/master') && !pull.includes(' changed, ')) { - const updatedMessage = updateMessage.content.replace(`${this.client.stores.emojis.loading} ***Fetching latest commit...***`, `${this.client.stores.emojis.error} ***Unexpected git output***`) - .replace(/```$/, `${pull}\n\`\`\``); + const updatedMessage = updateMessage.content.replace(`${this.client.stores.emojis.loading} ***Fetching latest commit...***`, `${this.client.stores.emojis.error} ***Unexpected git output***`); this.client.updating = false; return updateMessage.edit(updatedMessage); } - const continueMessage = updateMessage.content.replace(`${this.client.stores.emojis.loading} ***Fetching latest commit...***`, `${this.client.stores.emojis.success} ***Pulled latest commit***\n${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`) - .replace(/```$/, `${pull}\n$ yarn install\n\`\`\``); + const continueMessage = updateMessage.content.replace(`${this.client.stores.emojis.loading} ***Fetching latest commit...***`, `${this.client.stores.emojis.success} ***Pulled latest commit***\n${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`); const passedPull = await updateMessage.edit(continueMessage); @@ -49,22 +46,20 @@ export default class Pull extends Command { install = await this.client.util.exec('yarn install', { cwd: '/opt/CloudServices' }); } catch (error) { this.client.updating = false; - const updatedMessage = passedPull.content.replace(`${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`, `${this.client.stores.emojis.error} ***Failed to reinstall dependencies***`) - .replace(/```$/, `${error.message}\n\`\`\``); + const updatedMessage = passedPull.content.replace(`${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`, `${this.client.stores.emojis.error} ***Failed to reinstall dependencies***\n` + + `\`\`\`\n${error.message}\n\`\`\``); return updateMessage.edit(updatedMessage); } let updatedPackages: Message; if (install.includes('Already up-to-date')) { - const updatedMessage = passedPull.content.replace(`${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`, `${this.client.stores.emojis.success} ***No dependency updates available***\n${this.client.stores.emojis.loading} ***Rebuilding files...***`) - .replace(/```$/, `${install}\n$ yarn run build\n\`\`\``); + const updatedMessage = passedPull.content.replace(`${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`, `${this.client.stores.emojis.success} ***No dependency updates available***\n${this.client.stores.emojis.loading} ***Rebuilding files...***`); updatedPackages = await updateMessage.edit(updatedMessage); } else if (install.includes('success Saved lockfile.')) { - const updatedMessage = passedPull.content.replace(`${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`, `${this.client.stores.emojis.success} ***Updated dependencies***\n${this.client.stores.emojis.loading} ***Rebuilding files...***`) - .replace(/```$/, `${install}\n$ yarn run build\n\`\`\``); + const updatedMessage = passedPull.content.replace(`${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`, `${this.client.stores.emojis.success} ***Updated dependencies***\n${this.client.stores.emojis.loading} ***Rebuilding files...***`); updatedPackages = await updateMessage.edit(updatedMessage); } else { - const updatedMessage = passedPull.content.replace(`${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`, `${this.client.stores.emojis.error} ***Unexpected yarn install output***`) - .replace(/```$/, `${pull}\n\`\`\``); + const updatedMessage = passedPull.content.replace(`${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`, `${this.client.stores.emojis.error} ***Unexpected yarn install output***\n` + + `\`\`\`\n${pull}\n\`\`\``); this.client.updating = false; return updateMessage.edit(updatedMessage); } @@ -73,14 +68,13 @@ export default class Pull extends Command { try { build = await this.client.util.exec('yarn run build', { cwd: '/opt/CloudServices' }); } catch (error) { - const updatedMessage = updatedPackages.content.replace(`${this.client.stores.emojis.loading} ***Rebuilding files...***`, `${this.client.stores.emojis.error} ***Failed to rebuild files***`) - .replace(/```$/, `${error.message}\n\`\`\``); + const updatedMessage = updatedPackages.content.replace(`${this.client.stores.emojis.loading} ***Rebuilding files...***`, `${this.client.stores.emojis.error} ***Failed to rebuild files***\n` + + `\`\`\`\n${error.message}\n\`\`\``); this.client.buildError = true; this.client.updating = false; return updateMessage.edit(updatedMessage); } - const finalMessage = updatedPackages.content.replace(`${this.client.stores.emojis.loading} ***Rebuilding files...***`, `${this.client.stores.emojis.success} ***Files rebuilt***`) - .replace(/```$/, `${build}\n\`\`\``); + const finalMessage = updatedPackages.content.replace(`${this.client.stores.emojis.loading} ***Rebuilding files...***`, `${this.client.stores.emojis.success} ***Files rebuilt***`); this.client.updating = false; this.client.buildError = false; return updateMessage.edit(finalMessage); -- 2.20.1 From caf27269a9bba43ba15e8af943afbff7c61b07af Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 19:00:18 -0400 Subject: [PATCH 214/516] set to 0 instead of -1 --- src/commands/limits_setramnotification.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/limits_setramnotification.ts b/src/commands/limits_setramnotification.ts index aa60271..4ecf5be 100644 --- a/src/commands/limits_setramnotification.ts +++ b/src/commands/limits_setramnotification.ts @@ -19,7 +19,7 @@ export default class Limits_SetRAMNotification extends Command { if (Number(args[0]) >= tier.resourceLimits.ram) return message.channel.createMessage(`***${this.client.stores.emojis.error} You cannot set your notification limit to be set to or above your hard limit.***`); if (Number(args[0]) < 0) return message.channel.createMessage(`***${this.client.stores.emojis.error} You cannot set your notification limit to a negative number.***`); if (Number(args[0]) === 0) { - await account.updateOne({ $set: { ramLimitNotification: -1 } }); + await account.updateOne({ $set: { ramLimitNotification: 0 } }); return message.channel.createMessage(`***${this.client.stores.emojis.success} You have disabled notifications.***`); } await account.updateOne({ $set: { ramLimitNotification: Number(args[0]) } }); -- 2.20.1 From eabea72f096335e2d5b438c863ecda476b5dfde1 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 19:00:36 -0400 Subject: [PATCH 215/516] default to -50 --- src/class/Util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index 11e61d3..3328565 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -153,7 +153,7 @@ export default class Util { const tier = await this.client.db.Tier.findOne({ id: 1 }); const account = new this.client.db.Account({ - username, userID, emailAddress, createdBy: moderatorID, ramLimitNotification: tier.resourceLimits.ram - 20, createdAt: new Date(), locked: false, tier: 1, supportKey: code, ssInit: false, homepath: `/home/${username}`, + username, userID, emailAddress, createdBy: moderatorID, ramLimitNotification: tier.resourceLimits.ram - 50, createdAt: new Date(), locked: false, tier: 1, supportKey: code, ssInit: false, homepath: `/home/${username}`, }); return account.save(); } -- 2.20.1 From b4ceed1de19947dd72e5f52e6fd4947fe28b8b97 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 19:05:41 -0400 Subject: [PATCH 216/516] fixes --- src/intervals/memory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index bbf2b34..470a160 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -21,7 +21,7 @@ export default function memory(client: Client) { const tier: TierInterface = await client.db.Tier.findOne({ id: acc.tier }).lean().exec(); userLimits.soft = acc.ramLimitNotification; userLimits.hard = tier.resourceLimits.ram; - if (memoryConversion <= userLimits.soft) { + if ((memoryConversion <= userLimits.soft) && (acc.ramLimitNotification !== 0)) { set.delete(acc.username); } /* if the user has exceeded their soft memory limit, which is the one described in the -- 2.20.1 From deb2c0fc205260f51e6405deef17dd8d173cd088 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 19:08:10 -0400 Subject: [PATCH 217/516] stuff --- src/functions/existingLimitsSetup.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/functions/existingLimitsSetup.ts b/src/functions/existingLimitsSetup.ts index a0bce3a..08040ee 100644 --- a/src/functions/existingLimitsSetup.ts +++ b/src/functions/existingLimitsSetup.ts @@ -10,15 +10,15 @@ export default async function existingLimitsSetup(client: Client): Promise Date: Sun, 3 May 2020 19:11:23 -0400 Subject: [PATCH 218/516] fixes for stuff --- src/intervals/memory.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 470a160..64adef3 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -66,7 +66,9 @@ export default function memory(client: Client) { embed.addField('Memory Limit', `${String(userLimits.hard)} MB`, true); embed.setFooter(client.user.username, client.user.avatarURL); embed.setTimestamp(); - await client.createMessage(channelID, { embed }); + if (acc.ramLimitNotification !== 0) { + await client.createMessage(channelID, { embed }); + } if ((memoryConversion >= acc.ramLimitNotification) && (acc.ramLimitNotification !== 0)) { const notifyEmbed = new RichEmbed() .setTitle('Cloud Account | Notification') -- 2.20.1 From 58989a9b7e6e123aab02af5d73373d8b8d5fcfb4 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 4 May 2020 00:25:04 +0100 Subject: [PATCH 219/516] Improve exec system --- src/class/Util.ts | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index 3328565..58f933a 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -1,6 +1,5 @@ /* eslint-disable no-param-reassign */ -import { promisify } from 'util'; -import childProcess from 'child_process'; +import { exec, ExecOptions } from 'child_process'; import nodemailer from 'nodemailer'; import { Message, PrivateChannel, GroupChannel, Member, User } from 'eris'; import uuid from 'uuid/v4'; @@ -31,16 +30,27 @@ export default class Util { * @param command The command to execute * @param options childProcess.ExecOptions */ - public async exec(command: string, options: childProcess.ExecOptions = {}): Promise { - const ex = promisify(childProcess.exec); - let result: string; - try { - const res = await ex(command, options); - result = `${res.stdout}${res.stderr}`; - } catch (err) { - return Promise.reject(new Error(`Command failed: ${err.cmd}\n${err.stderr}${err.stdout}`)); - } - return result; + public async exec(command: string, options: ExecOptions = {}): Promise { + return new Promise((res, rej) => { + let error = false; + let output = ''; + const writeFunction = (data: string|Buffer|Error) => { + if (data instanceof Error) error = true; + output += `${data}`; + }; + const cmd = exec(command, options); + cmd.stdout.on('data', writeFunction); + cmd.stderr.on('data', writeFunction); + cmd.on('error', writeFunction); + cmd.once('close', (code, signal) => { + output += `Command exited with code ${code}${signal ? `/${signal}` : ''}`; + cmd.stdout.removeListener('data', writeFunction); + cmd.stderr.removeListener('data', writeFunction); + cmd.removeListener('error', writeFunction); + if (error) rej(output); + res(output); + }); + }); } /** -- 2.20.1 From 6a0596d3a4371a422853afb92f6c512836b7b45e Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 4 May 2020 00:46:51 +0100 Subject: [PATCH 220/516] Fix too long error --- src/commands/pull.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/commands/pull.ts b/src/commands/pull.ts index 8ab1183..4cdcb3b 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -1,4 +1,5 @@ import { Message } from 'eris'; +import axios from 'axios'; import { Client } from '..'; import { Command } from '../class'; @@ -68,8 +69,21 @@ export default class Pull extends Command { try { build = await this.client.util.exec('yarn run build', { cwd: '/opt/CloudServices' }); } catch (error) { - const updatedMessage = updatedPackages.content.replace(`${this.client.stores.emojis.loading} ***Rebuilding files...***`, `${this.client.stores.emojis.error} ***Failed to rebuild files***\n` - + `\`\`\`\n${error.message}\n\`\`\``); + let updatedMessage = updatedPackages.content.replace(`${this.client.stores.emojis.loading} ***Rebuilding files...***`, `${this.client.stores.emojis.error} ***Failed to rebuild files***\n`); + if (error.message.length < 1800) updatedMessage += `\`\`\`\n${error.message}\n\`\`\``; + else { + const split = this.client.util.splitString(error.message, 1975); + if (split[5]) { + try { + const { data } = await axios.post('https://snippets.cloud.libraryofcode.org/documents', split.join('')); + updatedMessage += `${this.client.stores.emojis.success} The error output can be found on https://snippets.cloud.libraryofcode.org/${data.key}`; + } catch (e) { + updatedMessage += `${this.client.stores.emojis.error} Could not upload error: ${e}`; + } + } else { + split.forEach((m) => message.channel.createMessage(`\`\`\`bash\n${m}\n\`\`\``)); + } + } this.client.buildError = true; this.client.updating = false; return updateMessage.edit(updatedMessage); -- 2.20.1 From d81d6752ad668614c1f2b8373ecc6ffb236b97f1 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 4 May 2020 00:49:36 +0100 Subject: [PATCH 221/516] Add an extra space just to test something --- src/commands/reload.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/reload.ts b/src/commands/reload.ts index 9aeb4c0..4bdc024 100644 --- a/src/commands/reload.ts +++ b/src/commands/reload.ts @@ -14,6 +14,6 @@ export default class Reload extends Command { } public run(message: Message, args: string[]): void { - 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]); } } -- 2.20.1 From c7fb133a23323bfd2e19fceb2cc345a74f309c75 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 4 May 2020 00:50:57 +0100 Subject: [PATCH 222/516] Fix type error --- src/commands/reload.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/reload.ts b/src/commands/reload.ts index 4bdc024..84a4ba4 100644 --- a/src/commands/reload.ts +++ b/src/commands/reload.ts @@ -13,7 +13,7 @@ export default class Reload extends Command { this.enabled = true; } - public run(message: Message, args: string[]): void { - if (!args.length) return this.client.commands.get('help').run(message, [this.name]); + public run(message: Message, args: string[]) { + if (!args.length) return this.client.commands.get('help').run(message, [this.name]); } } -- 2.20.1 From 3030db18d9c352b827f5cc58940a206b021de03a Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 4 May 2020 01:00:52 +0100 Subject: [PATCH 223/516] TS2740 --- src/intervals/memory.ts | 4 ++-- src/models/Tier.ts | 14 ++++++++------ src/models/index.ts | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 64adef3..8149b2d 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -2,7 +2,7 @@ /* eslint-disable no-await-in-loop */ import { Client } from '..'; import { RichEmbed } from '../class'; -import { TierInterface } from '../models'; +import { Tiers } from '../models'; const channelID = '691824484230889546'; @@ -18,7 +18,7 @@ export default function memory(client: Client) { // memory in megabytes const memoryConversion = mem / 1024 / 1024; const userLimits: { soft?: number, hard?: number } = {}; - const tier: TierInterface = await client.db.Tier.findOne({ id: acc.tier }).lean().exec(); + const tier: Tiers = await client.db.Tier.findOne({ id: acc.tier }).lean().exec(); userLimits.soft = acc.ramLimitNotification; userLimits.hard = tier.resourceLimits.ram; if ((memoryConversion <= userLimits.soft) && (acc.ramLimitNotification !== 0)) { diff --git a/src/models/Tier.ts b/src/models/Tier.ts index ca9e3cf..7542a50 100644 --- a/src/models/Tier.ts +++ b/src/models/Tier.ts @@ -1,13 +1,15 @@ import { Document, Schema, model } from 'mongoose'; -export interface TierInterface extends Document { +export interface Tiers { id: number, resourceLimits: { - // in MB - ram: number, - // in MB - storage: number, - }, + // In MB + ram: number, storage: number + } +} + +export interface TierInterface extends Tiers, Document { + id: number; } const Tier: Schema = new Schema({ diff --git a/src/models/index.ts b/src/models/index.ts index 6cac9a8..351bbeb 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -1,4 +1,4 @@ export { default as Account, AccountInterface } from './Account'; export { default as Moderation, ModerationInterface } from './Moderation'; export { default as Domain, DomainInterface } from './Domain'; -export { default as Tier, TierInterface } from './Tier'; +export { default as Tier, TierInterface, Tiers } from './Tier'; -- 2.20.1 From 2fb3b79e51780a4e934963707873ab40905cd803 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 4 May 2020 01:40:10 +0100 Subject: [PATCH 224/516] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9cd9007..a71861b 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@types/fs-extra": "^8.0.0", "@types/helmet": "^0.0.45", "@types/ioredis": "^4.0.18", - "@types/mongoose": "^5.5.20", + "@types/mongoose": "^5.7.14", "@types/nodemailer": "^6.2.1", "@types/signale": "^1.2.1", "@types/uuid": "^3.4.5", -- 2.20.1 From ff3f4c0e9f6ca7bafef75e51ba40b3621b47a3aa Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 4 May 2020 02:00:16 +0100 Subject: [PATCH 225/516] No idea what's causing the errors --- package.json | 2 +- src/intervals/memory.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index a71861b..17183e4 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "axios": "^0.19.0", "body-parser": "^1.19.0", "eris": "^0.11.2", - "eris-pagination": "bsian03/eris-pagination#dev", + "eris-pagination": "git+https://github.com/bsian03/eris-pagination#a10c026e9ce0b9a99799294b7b2a64d5268be56e", "express": "^4.17.1", "fs-extra": "^8.1.0", "helmet": "^3.21.2", diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 8149b2d..a77ee17 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -18,6 +18,7 @@ export default function memory(client: Client) { // memory in megabytes const memoryConversion = mem / 1024 / 1024; const userLimits: { soft?: number, hard?: number } = {}; + // @ts-ignore const tier: Tiers = await client.db.Tier.findOne({ id: acc.tier }).lean().exec(); userLimits.soft = acc.ramLimitNotification; userLimits.hard = tier.resourceLimits.ram; -- 2.20.1 From e8cfac48cc4248345ab56c1db5e6d0694041c494 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 4 May 2020 02:14:31 +0100 Subject: [PATCH 226/516] Add force update version --- src/commands/pull.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/commands/pull.ts b/src/commands/pull.ts index 4cdcb3b..7639315 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -13,7 +13,7 @@ export default class Pull extends Command { this.permissions = { roles: ['662163685439045632'] }; } - public async run(message: Message) { + public async run(message: Message, args: string[]) { try { if (this.client.updating) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Update in progress***`); this.client.updating = true; @@ -28,7 +28,7 @@ export default class Pull extends Command { this.client.updating = false; return updateMessage.edit(updatedMessage); } - if (pull.includes('Already up to date')) { + if (pull.includes('Already up to date') && args[0] !== '-f') { const updatedMessage = updateMessage.content.replace(`${this.client.stores.emojis.loading} ***Fetching latest commit...***`, `${this.client.stores.emojis.success} ***No updates available***`); this.client.updating = false; return updateMessage.edit(updatedMessage); @@ -38,7 +38,8 @@ export default class Pull extends Command { this.client.updating = false; return updateMessage.edit(updatedMessage); } - const continueMessage = updateMessage.content.replace(`${this.client.stores.emojis.loading} ***Fetching latest commit...***`, `${this.client.stores.emojis.success} ***Pulled latest commit***\n${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`); + const continueMessage = updateMessage.content.replace(`${this.client.stores.emojis.loading} ***Fetching latest commit...***`, `${this.client.stores.emojis.success} ***${pull.includes('Already up to date') ? 'No updates available' : 'Fetched latest commit'}***\n` + + `${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`); const passedPull = await updateMessage.edit(continueMessage); -- 2.20.1 From 5fffe9f5f2cd12641380e508a80e95f049ace4ff Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 3 May 2020 23:55:12 -0400 Subject: [PATCH 227/516] fixes to util/exec --- src/class/Util.ts | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index 58f933a..c2d8649 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -1,5 +1,6 @@ /* eslint-disable no-param-reassign */ -import { exec, ExecOptions } from 'child_process'; +import { promisify } from 'util'; +import childProcess from 'child_process'; import nodemailer from 'nodemailer'; import { Message, PrivateChannel, GroupChannel, Member, User } from 'eris'; import uuid from 'uuid/v4'; @@ -30,27 +31,16 @@ export default class Util { * @param command The command to execute * @param options childProcess.ExecOptions */ - public async exec(command: string, options: ExecOptions = {}): Promise { - return new Promise((res, rej) => { - let error = false; - let output = ''; - const writeFunction = (data: string|Buffer|Error) => { - if (data instanceof Error) error = true; - output += `${data}`; - }; - const cmd = exec(command, options); - cmd.stdout.on('data', writeFunction); - cmd.stderr.on('data', writeFunction); - cmd.on('error', writeFunction); - cmd.once('close', (code, signal) => { - output += `Command exited with code ${code}${signal ? `/${signal}` : ''}`; - cmd.stdout.removeListener('data', writeFunction); - cmd.stderr.removeListener('data', writeFunction); - cmd.removeListener('error', writeFunction); - if (error) rej(output); - res(output); - }); - }); + public async exec(command: string, options: childProcess.ExecOptions = {}): Promise { + const ex = promisify(childProcess.exec); + let result: string; + try { + const res = await ex(command, options); + result = `${res.stdout}${res.stderr}`; + } catch (err) { + return Promise.reject(new Error(`Command failed: ${err.cmd}\n${err.stderr}${err.stdout}`)); + } + return result; } /** @@ -163,7 +153,7 @@ export default class Util { const tier = await this.client.db.Tier.findOne({ id: 1 }); const account = new this.client.db.Account({ - username, userID, emailAddress, createdBy: moderatorID, ramLimitNotification: tier.resourceLimits.ram - 50, createdAt: new Date(), locked: false, tier: 1, supportKey: code, ssInit: false, homepath: `/home/${username}`, + username, userID, emailAddress, createdBy: moderatorID, createdAt: new Date(), locked: false, tier: 1, supportKey: code, ssInit: false, ramLimitNotification: tier.resourceLimits.ram - 50, homepath: `/home/${username}`, }); return account.save(); } -- 2.20.1 From d8267112c71f38f842f2473eca3070b5482f070b Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 4 May 2020 12:13:17 +0100 Subject: [PATCH 228/516] Check something --- src/class/Util.ts | 30 +++++++++++++++++++++--------- src/commands/createaccount.ts | 1 + 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index c2d8649..a60eecd 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -32,15 +32,26 @@ export default class Util { * @param options childProcess.ExecOptions */ public async exec(command: string, options: childProcess.ExecOptions = {}): Promise { - const ex = promisify(childProcess.exec); - let result: string; - try { - const res = await ex(command, options); - result = `${res.stdout}${res.stderr}`; - } catch (err) { - return Promise.reject(new Error(`Command failed: ${err.cmd}\n${err.stderr}${err.stdout}`)); - } - return result; + return new Promise((res, rej) => { + let error = false; + let output = ''; + const writeFunction = (data: string|Buffer|Error) => { + if (data instanceof Error) error = true; + output += `${data}`; + }; + const cmd = childProcess.exec(command, options); + cmd.stdout.on('data', writeFunction); + cmd.stderr.on('data', writeFunction); + cmd.on('error', writeFunction); + cmd.once('close', (code, signal) => { + output += `Command exited with code ${code}${signal ? `/${signal}` : ''}`; + cmd.stdout.removeListener('data', writeFunction); + cmd.stderr.removeListener('data', writeFunction); + cmd.removeListener('error', writeFunction); + if (error) rej(output); + res(output); + }); + }); } /** @@ -155,6 +166,7 @@ export default class Util { const account = new this.client.db.Account({ username, userID, emailAddress, createdBy: moderatorID, createdAt: new Date(), locked: false, tier: 1, supportKey: code, ssInit: false, ramLimitNotification: tier.resourceLimits.ram - 50, homepath: `/home/${username}`, }); + this.client.createMessage('592170164322041856', JSON.stringify(account)); return account.save(); } diff --git a/src/commands/createaccount.ts b/src/commands/createaccount.ts index d9047b0..f677dbc 100644 --- a/src/commands/createaccount.ts +++ b/src/commands/createaccount.ts @@ -37,6 +37,7 @@ export default class CreateAccount extends Command { const confirmation = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Creating account...***`); const data = await this.client.util.accounts.createAccount({ userID: args[0], username: args[2], emailAddress: args[1] }, message.author.id); + this.client.createMessage('592170164322041856', JSON.stringify(data)); message.delete(); return confirmation.edit(`${this.client.stores.emojis.success} ***Account successfully created***\n**Username:** \`${args[2]}\`\n**Temporary Password:** \`${data.tempPass}\``); -- 2.20.1 From 723c46e3c4407f2b036c5cc7647d8b9e0debedd2 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 4 May 2020 12:18:57 +0100 Subject: [PATCH 229/516] Remove the shit that's breaking shit --- src/class/Util.ts | 2 -- src/commands/createaccount.ts | 1 - 2 files changed, 3 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index a60eecd..d3880d8 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -44,7 +44,6 @@ export default class Util { cmd.stderr.on('data', writeFunction); cmd.on('error', writeFunction); cmd.once('close', (code, signal) => { - output += `Command exited with code ${code}${signal ? `/${signal}` : ''}`; cmd.stdout.removeListener('data', writeFunction); cmd.stderr.removeListener('data', writeFunction); cmd.removeListener('error', writeFunction); @@ -166,7 +165,6 @@ export default class Util { const account = new this.client.db.Account({ username, userID, emailAddress, createdBy: moderatorID, createdAt: new Date(), locked: false, tier: 1, supportKey: code, ssInit: false, ramLimitNotification: tier.resourceLimits.ram - 50, homepath: `/home/${username}`, }); - this.client.createMessage('592170164322041856', JSON.stringify(account)); return account.save(); } diff --git a/src/commands/createaccount.ts b/src/commands/createaccount.ts index f677dbc..d9047b0 100644 --- a/src/commands/createaccount.ts +++ b/src/commands/createaccount.ts @@ -37,7 +37,6 @@ export default class CreateAccount extends Command { const confirmation = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Creating account...***`); const data = await this.client.util.accounts.createAccount({ userID: args[0], username: args[2], emailAddress: args[1] }, message.author.id); - this.client.createMessage('592170164322041856', JSON.stringify(data)); message.delete(); return confirmation.edit(`${this.client.stores.emojis.success} ***Account successfully created***\n**Username:** \`${args[2]}\`\n**Temporary Password:** \`${data.tempPass}\``); -- 2.20.1 From 810ad6e7be0f835b012ede5fa4e5ab8162ae89c5 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 4 May 2020 12:21:42 +0100 Subject: [PATCH 230/516] Fix message --- src/intervals/memory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index a77ee17..41a5996 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -73,7 +73,7 @@ export default function memory(client: Client) { if ((memoryConversion >= acc.ramLimitNotification) && (acc.ramLimitNotification !== 0)) { const notifyEmbed = new RichEmbed() .setTitle('Cloud Account | Notification') - .setDescription(`You are about to reach your RAM resource limits, you are currently using '${String(memoryConversion)} MB' and your limit is '${String(userLimits.hard - 10)} MB'. Please correct your usage to avoid further action.\nYou can set your notification preferences by running \`=limits set-ram-notification \`, you can disable these notifications by running \`=limits set-ram-notification -1\`.`) + .setDescription(`You are about to reach your RAM resource limits, you are currently using '${String(memoryConversion)} MB' and your limit is '${String(userLimits.hard - 10)} MB'. Please correct your usage to avoid further action.\nYou can set your notification preferences by running \`=limits set-ram-notification \`, you can disable these notifications by running \`=limits set-ram-notification 0\`.`) .addField('User', `${acc.username} | <@${acc.userID}>`, true) .addField('Technician', 'SYSTEM', true) .setFooter(client.user.username, client.user.avatarURL) -- 2.20.1 From e6b18182224366998d11698e0479a8d1a03abc73 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 4 May 2020 12:51:16 +0100 Subject: [PATCH 231/516] Trying to fix something with the CI? --- .gitlab-ci.yml | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 683d018..b1544f5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,19 +1,19 @@ -stages: - - build - - test - -typescript_build: - stage: build - script: - - cp ../config.json ./src/config.json - - yarn install --ignore-engines - - tsc -p ./tsconfig.json - -lint: - stage: test - before_script: - - cp ../config.json ./src/config.json - - yarn install --ignore-engines - script: - - yarn run lint-find - +stages: + - build + - test + +typescript_build: + stage: build + script: + - cp ../config.json ./src/config.json + - yarn install --ignore-engines + - tsc -p ./tsconfig.json --traceResolution + +lint: + stage: test + before_script: + - cp ../config.json ./src/config.json + - yarn install --ignore-engines + script: + - yarn run lint-find + -- 2.20.1 From 1b9d3c56f1c00e74be687b6a970eefaf4d4aef3f Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 4 May 2020 13:07:55 +0100 Subject: [PATCH 232/516] Fix CI --- package.json | 3 ++- src/api/Security.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 17183e4..47f9981 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,8 @@ "uuid": "^3.3.3" }, "devDependencies": { - "@types/express": "^4.17.2", + "@types/express": "^4.17.6", + "@types/express-serve-static-core": "^4.17.5", "@types/fs-extra": "^8.0.0", "@types/helmet": "^0.0.45", "@types/ioredis": "^4.0.18", diff --git a/src/api/Security.ts b/src/api/Security.ts index 2dc019f..5488662 100644 --- a/src/api/Security.ts +++ b/src/api/Security.ts @@ -70,7 +70,7 @@ export default class Security { return req.headers.authorization.split(' ')[1]; } if (req.query && req.query.token) { - return req.query.token; + return req.query.token as string; } return '0000000000'; } -- 2.20.1 From 9f4a7fcff7af2a311b22cbd814aaaae8550e3bcf Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 4 May 2020 13:08:21 +0100 Subject: [PATCH 233/516] Remove trace res --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b1544f5..a592cac 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,7 +7,7 @@ typescript_build: script: - cp ../config.json ./src/config.json - yarn install --ignore-engines - - tsc -p ./tsconfig.json --traceResolution + - tsc -p ./tsconfig.json lint: stage: test -- 2.20.1 From e646685bc3c6a492241e4b2347beb3fb34281cc4 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 4 May 2020 13:12:38 +0100 Subject: [PATCH 234/516] Lint --- src/commands/load.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/load.ts b/src/commands/load.ts index 39df7c9..2e44703 100644 --- a/src/commands/load.ts +++ b/src/commands/load.ts @@ -32,7 +32,7 @@ export default class Load extends Command { delete require.cache[`${corepath}/commands/index.js`]; delete require.cache[`${corepath}/commands/${args[1]}.js`]; Object.keys(require.cache).filter((path) => path.includes(`${args[1]}_`)).forEach((path) => delete require.cache[path]); - const cmdIndex = require('../commands'); + const cmdIndex = require('.'); let Cmd = cmdIndex[args[1]]; if (!Cmd) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Could not find file***`); Cmd = require(`${corepath}/commands/${args[1]}`).default; -- 2.20.1 From 8f58d22461fe97e9a98a2640e6bef98494b71625 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 5 May 2020 19:41:00 -0400 Subject: [PATCH 235/516] fix calculation error in memory.ts --- src/intervals/memory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index a77ee17..173b98b 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -73,7 +73,7 @@ export default function memory(client: Client) { if ((memoryConversion >= acc.ramLimitNotification) && (acc.ramLimitNotification !== 0)) { const notifyEmbed = new RichEmbed() .setTitle('Cloud Account | Notification') - .setDescription(`You are about to reach your RAM resource limits, you are currently using '${String(memoryConversion)} MB' and your limit is '${String(userLimits.hard - 10)} MB'. Please correct your usage to avoid further action.\nYou can set your notification preferences by running \`=limits set-ram-notification \`, you can disable these notifications by running \`=limits set-ram-notification -1\`.`) + .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.\nYou can set your notification preferences by running \`=limits set-ram-notification \`, you can disable these notifications by running \`=limits set-ram-notification -1\`.`) .addField('User', `${acc.username} | <@${acc.userID}>`, true) .addField('Technician', 'SYSTEM', true) .setFooter(client.user.username, client.user.avatarURL) -- 2.20.1 From 9455bb195db1a79070445d0c913a1d3686736970 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 5 May 2020 19:50:14 -0400 Subject: [PATCH 236/516] fix conflict --- src/commands/tier.ts | 2 +- src/intervals/memory.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/commands/tier.ts b/src/commands/tier.ts index 0d2200e..ec625cf 100644 --- a/src/commands/tier.ts +++ b/src/commands/tier.ts @@ -33,7 +33,7 @@ export default class Tier extends Command { embed.setTitle('Cloud Account | Tier Change'); embed.setColor('#0099ff'); embed.addField('User', `${account.username} | <@${account.userID}>`, true); - embed.addField('Moderator', `<@${message.author.id}>`, true); + embed.addField('Technician', `<@${message.author.id}>`, true); embed.addField('Old Tier -> New Tier', `${account.tier} -> ${args[1]}`, true); embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setTimestamp(); diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 173b98b..bb69754 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -39,7 +39,7 @@ export default function memory(client: Client) { embed.addField('Memory Usage', `${String(memoryConversion)} MB`, true); embed.addField('Memory Limit', `${String(userLimits.hard)} MB`, true); client.createMessage(channelID, { embed }); - client.util.createModerationLog(acc.userID, client.guilds.get('446067825673633794').members.get(client.user.id), 1, '[AUTO] Exceeded resource limit for RAM.'); + 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.`); client.util.transport.sendMail({ to: acc.emailAddress, from: 'Library of Code sp-us | Cloud Services ', @@ -47,8 +47,8 @@ export default function memory(client: Client) { html: `

    Library of Code sp-us | Cloud Services

    Your account has received an official warning from a Technician. Please get the underlying issue resolved to avoid possible moderative action.

    -

    Reason: [AUTO] Exceeded resource limit for RAM.

    -

    Moderator: ${client.user.username}

    +

    Reason: 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.

    +

    Moderator: SYSTEM

    Library of Code sp-us | Support Team `, @@ -84,7 +84,7 @@ export default function memory(client: Client) { client.util.transport.sendMail({ to: acc.emailAddress, from: 'Library of Code sp-us | Cloud Services ', - subject: 'Notification', + subject: 'Account Notification', html: `

    Library of Code sp-us | Cloud Services

    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.

    -- 2.20.1 From 8c611ff5b9e35ed4f5563a8e7be7a490f21a288f Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 5 May 2020 19:52:45 -0400 Subject: [PATCH 237/516] fix conflict --- src/intervals/memory.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index bb69754..307d0fe 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-useless-escape */ /* eslint-disable no-continue */ /* eslint-disable no-await-in-loop */ import { Client } from '..'; @@ -73,9 +74,10 @@ export default function memory(client: Client) { if ((memoryConversion >= acc.ramLimitNotification) && (acc.ramLimitNotification !== 0)) { const notifyEmbed = new RichEmbed() .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.\nYou can set your notification preferences by running \`=limits set-ram-notification \`, you can disable these notifications by running \`=limits set-ram-notification -1\`.`) + .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('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 \`, you can disable these notifications by running \`=limits set-ram-notification -1\`.') .setFooter(client.user.username, client.user.avatarURL) .setTimestamp(); client.getDMChannel(acc.userID).then((channel) => { -- 2.20.1 From 202f87e8320c6b405f486b564d918b9d567d4a5a Mon Sep 17 00:00:00 2001 From: Matthew R Date: Fri, 8 May 2020 19:10:53 -0400 Subject: [PATCH 238/516] various fixes --- src/commands/cwg_create.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index a3120c4..8029320 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -47,7 +47,7 @@ export default class CWG_Create extends Command { try { answer = await this.client.util.messageCollector( 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 binded 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, ); } catch (error) { @@ -189,16 +189,13 @@ export default class CWG_Create extends Command { if (!this.isValidCertificateChain(certChain)) throw new Error('Invalid Certificate Chain'); if (!this.isValidPrivateKey(privateKey)) throw new Error('Invalid Private Key'); const path = `/opt/CloudServices/temp/${domain}`; - const temp = [writeFile(`${path}.chain.crt`, certChain), writeFile(`${path}.key.pem`, privateKey)]; - const removeFiles = [unlink(`${path}.chain.crt`), unlink(`${path}.key.pem`)]; - await Promise.all(temp); + await Promise.all([writeFile(`${path}.chain.crt`, certChain), writeFile(`${path}.key.pem`, privateKey)]); if (!this.isMatchingPair(`${path}.chain.crt`, `${path}.key.pem`)) { - await Promise.all(removeFiles); + await Promise.all([unlink(`${path}.chain.crt`), unlink(`${path}.key.pem`)]); throw new Error('Certificate and Private Key do not match'); } - const tasks = [writeFile(`/etc/nginx/ssl/${domain}.chain.crt`, certChain), writeFile(`/etc/nginx/ssl/${domain}.key.pem`, privateKey)]; - await Promise.all(tasks); + await Promise.all([writeFile(`/etc/ssl/certs/cwg/${domain}.chain.crt`, certChain), writeFile(`/etc/certs/private/cwg/${domain}.key.pem`, privateKey)]); return { cert: `/etc/nginx/ssl/${domain}.chain.crt`, key: `/etc/nginx/ssl/${domain}.key.pem` }; } -- 2.20.1 From dcf7103913bc9772f7fa04fcc2a14e461b196b24 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Fri, 8 May 2020 19:14:01 -0400 Subject: [PATCH 239/516] various fixes --- src/commands/cwg_create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index 8029320..9c5b995 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -195,7 +195,7 @@ export default class CWG_Create extends Command { throw new Error('Certificate and Private Key do not match'); } - await Promise.all([writeFile(`/etc/ssl/certs/cwg/${domain}.chain.crt`, certChain), writeFile(`/etc/certs/private/cwg/${domain}.key.pem`, privateKey)]); + await Promise.all([writeFile(`/etc/ssl/certs/cwg/${domain}.chain.crt`, certChain), writeFile(`/etc/ssl/certs/private/cwg/${domain}.key.pem`, privateKey)]); return { cert: `/etc/nginx/ssl/${domain}.chain.crt`, key: `/etc/nginx/ssl/${domain}.key.pem` }; } -- 2.20.1 From 331afd449a577cb401fe60daea8598b467c61ee4 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Fri, 8 May 2020 19:16:22 -0400 Subject: [PATCH 240/516] various fixes --- src/commands/cwg_create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index 9c5b995..c16da15 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -195,7 +195,7 @@ export default class CWG_Create extends Command { throw new Error('Certificate and Private Key do not match'); } - await Promise.all([writeFile(`/etc/ssl/certs/cwg/${domain}.chain.crt`, certChain), writeFile(`/etc/ssl/certs/private/cwg/${domain}.key.pem`, privateKey)]); + await Promise.all([writeFile(`/etc/ssl/certs/cwg/${domain}.chain.crt`, certChain), writeFile(`/etc/ssl/private/cwg/${domain}.key.pem`, privateKey)]); return { cert: `/etc/nginx/ssl/${domain}.chain.crt`, key: `/etc/nginx/ssl/${domain}.key.pem` }; } -- 2.20.1 From 60a65f370927c306510ee5fc8bdefb0445d6f874 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Fri, 8 May 2020 19:27:45 -0400 Subject: [PATCH 241/516] various fixes --- src/commands/cwg_create.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index c16da15..f3135e7 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -1,5 +1,6 @@ import fs, { writeFile, unlink } from 'fs-extra'; import axios from 'axios'; +import { randomBytes } from 'crypto'; import { Message } from 'eris'; import { AccountInterface } from '../models'; import { Command, RichEmbed } from '../class'; @@ -87,7 +88,9 @@ export default class CWG_Create extends Command { .addField('Domain', domain.domain, true) .addField('Port', String(domain.port), true); - const cert = await parseCertificate(this.client, domain.x509.cert); + const certPath = `/opt/CloudServices/temp/${randomBytes(5).toString('hex')}`; + await writeFile(certPath, certs.cert, { encoding: 'utf8' }); + const cert = await parseCertificate(this.client, certPath); embed.addField('Certificate Issuer', cert.issuer.organizationName, true) .addField('Certificate Subject', cert.subject.commonName, true) -- 2.20.1 From f51ced85ae812c7c4be48cb26b216d7945d9b251 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Fri, 8 May 2020 19:37:24 -0400 Subject: [PATCH 242/516] various fixes --- src/commands/cwg_create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index f3135e7..9f48fdc 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -199,7 +199,7 @@ export default class CWG_Create extends Command { } await Promise.all([writeFile(`/etc/ssl/certs/cwg/${domain}.chain.crt`, certChain), writeFile(`/etc/ssl/private/cwg/${domain}.key.pem`, privateKey)]); - return { cert: `/etc/nginx/ssl/${domain}.chain.crt`, key: `/etc/nginx/ssl/${domain}.key.pem` }; + return { cert: `/etc/ssl/certs/cwg/${domain}.chain.crt`, key: `/etc/ssl/private/cwg/${domain}.chain.crt` }; } public checkOccurance(text: string, query: string) { -- 2.20.1 From 8ce060282e34beda6931118bc3698f5400e2f80e Mon Sep 17 00:00:00 2001 From: Matthew R Date: Fri, 8 May 2020 19:41:16 -0400 Subject: [PATCH 243/516] various fixes --- src/commands/cwg_create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index 9f48fdc..a54c3be 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -199,7 +199,7 @@ export default class CWG_Create extends Command { } await Promise.all([writeFile(`/etc/ssl/certs/cwg/${domain}.chain.crt`, certChain), writeFile(`/etc/ssl/private/cwg/${domain}.key.pem`, privateKey)]); - return { cert: `/etc/ssl/certs/cwg/${domain}.chain.crt`, key: `/etc/ssl/private/cwg/${domain}.chain.crt` }; + return { cert: `/etc/ssl/certs/cwg/${domain}.chain.crt`, key: `/etc/ssl/private/cwg/${domain}.key.pem` }; } public checkOccurance(text: string, query: string) { -- 2.20.1 From 88198b223469c7e65bdb13916e2d810c950c1fea Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Tue, 12 May 2020 10:21:30 -0400 Subject: [PATCH 244/516] roll back issue with exec --- src/class/Util.ts | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index d3880d8..b2338db 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -32,27 +32,18 @@ export default class Util { * @param options childProcess.ExecOptions */ public async exec(command: string, options: childProcess.ExecOptions = {}): Promise { - return new Promise((res, rej) => { - let error = false; - let output = ''; - const writeFunction = (data: string|Buffer|Error) => { - if (data instanceof Error) error = true; - output += `${data}`; - }; - const cmd = childProcess.exec(command, options); - cmd.stdout.on('data', writeFunction); - cmd.stderr.on('data', writeFunction); - cmd.on('error', writeFunction); - cmd.once('close', (code, signal) => { - cmd.stdout.removeListener('data', writeFunction); - cmd.stderr.removeListener('data', writeFunction); - cmd.removeListener('error', writeFunction); - if (error) rej(output); - res(output); - }); - }); + const ex = promisify(childProcess.exec); + let result: string; + try { + const res = await ex(command, options); + result = `${res.stdout}${res.stderr}`; + } catch (err) { + return Promise.reject(new Error(`Command failed: ${err.cmd}\n${err.stderr}${err.stdout}`)); + } + return result; } + /** * Resolves a command * @param query Command input -- 2.20.1 From a0479d1cff3e35a666ddf65d3726ec230733d7ce Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Tue, 12 May 2020 10:30:15 -0400 Subject: [PATCH 245/516] fix issue with cwg create --- src/commands/cwg_create.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index a54c3be..3bf37a1 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -71,6 +71,9 @@ export default class CWG_Create extends Command { if (!this.isValidPrivateKey(certAndPrivateKey[1])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid Private Key***`); certs = { cert: certAndPrivateKey[0], key: certAndPrivateKey[1] }; + } else { + certs.cert = await fs.readFile('/etc/ssl/private/cloud-libraryofcode-org.chain.crt', { encoding: 'utf8' }); + certs.key = await fs.readFile('/etc/ssl/private/cloud-libraryofcode-org.key', { encoding: 'utf8' }); } const domain = await this.createDomain(account, args[1], Number(args[2]), certs); -- 2.20.1 From f507131ae23413c510f5bbc65bca81389c611116 Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Tue, 12 May 2020 10:35:28 -0400 Subject: [PATCH 246/516] typing fix --- src/commands/cwg_create.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index 3bf37a1..d9554c7 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -72,6 +72,8 @@ export default class CWG_Create extends Command { certs = { cert: certAndPrivateKey[0], key: certAndPrivateKey[1] }; } else { + // eslint-disable-next-line no-shadow + const certs: { cert?: string, key?: string } = {}; certs.cert = await fs.readFile('/etc/ssl/private/cloud-libraryofcode-org.chain.crt', { encoding: 'utf8' }); certs.key = await fs.readFile('/etc/ssl/private/cloud-libraryofcode-org.key', { encoding: 'utf8' }); } -- 2.20.1 From 025c14139bf32c70d7cab2a03596cb23e88ffa67 Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Tue, 12 May 2020 10:44:16 -0400 Subject: [PATCH 247/516] typing fix --- src/commands/cwg_create.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index d9554c7..0cb4f10 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -32,8 +32,6 @@ export default class CWG_Create extends Command { try { if (!args[2]) return this.client.commands.get('help').run(message, ['cwg', this.name]); - let certs: { cert: string, key: string }; - if (!this.urlRegex.test(args[1])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid URL***`); if (Number(args[2]) <= 1024 || Number(args[2]) >= 65535) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Port must be greater than 1024 and less than 65535***`); if (!args[1].endsWith('.cloud.libraryofcode.org') && !args[4]) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Certificate Chain and Private Key are required for custom domains***`); @@ -59,6 +57,7 @@ export default class CWG_Create extends Command { const edit = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Binding domain...***`); + let certs: { cert?: string, key?: string } = {}; if (!args[1].endsWith('.cloud.libraryofcode.org')) { const urls = args.slice(3, 5); if (urls.some((l) => !l.includes('snippets.cloud.libraryofcode.org/raw/'))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid snippets URL***`); @@ -72,8 +71,6 @@ export default class CWG_Create extends Command { certs = { cert: certAndPrivateKey[0], key: certAndPrivateKey[1] }; } else { - // eslint-disable-next-line no-shadow - const certs: { cert?: string, key?: string } = {}; certs.cert = await fs.readFile('/etc/ssl/private/cloud-libraryofcode-org.chain.crt', { encoding: 'utf8' }); certs.key = await fs.readFile('/etc/ssl/private/cloud-libraryofcode-org.key', { encoding: 'utf8' }); } -- 2.20.1 From c2c00e102d8cd76ed23196a57b1113fbc4fec759 Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Tue, 12 May 2020 10:47:40 -0400 Subject: [PATCH 248/516] typing fix --- src/commands/cwg_create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index 0cb4f10..862298b 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -192,7 +192,7 @@ export default class CWG_Create extends Command { public async createCertAndPrivateKey(domain: string, certChain: string, privateKey: string) { if (!this.isValidCertificateChain(certChain)) throw new Error('Invalid Certificate Chain'); - if (!this.isValidPrivateKey(privateKey)) throw new Error('Invalid Private Key'); + // if (!this.isValidPrivateKey(privateKey)) throw new Error('Invalid Private Key'); const path = `/opt/CloudServices/temp/${domain}`; await Promise.all([writeFile(`${path}.chain.crt`, certChain), writeFile(`${path}.key.pem`, privateKey)]); if (!this.isMatchingPair(`${path}.chain.crt`, `${path}.key.pem`)) { -- 2.20.1 From fd78b2ef3587fc84807ad2ff0c6eab0e1ebc5654 Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 12 May 2020 15:54:07 +0100 Subject: [PATCH 249/516] Back --- src/class/Util.ts | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index b2338db..851337d 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -32,15 +32,25 @@ export default class Util { * @param options childProcess.ExecOptions */ public async exec(command: string, options: childProcess.ExecOptions = {}): Promise { - const ex = promisify(childProcess.exec); - let result: string; - try { - const res = await ex(command, options); - result = `${res.stdout}${res.stderr}`; - } catch (err) { - return Promise.reject(new Error(`Command failed: ${err.cmd}\n${err.stderr}${err.stdout}`)); - } - return result; + return new Promise((res, rej) => { + let error = false; + let output = ''; + const writeFunction = (data: string|Buffer|Error) => { + if (data instanceof Error) error = true; + output += `${data}`; + }; + const cmd = childProcess.exec(command, options); + cmd.stdout.on('data', writeFunction); + cmd.stderr.on('data', writeFunction); + cmd.on('error', writeFunction); + cmd.once('close', (code, signal) => { + cmd.stdout.removeListener('data', writeFunction); + cmd.stderr.removeListener('data', writeFunction); + cmd.removeListener('error', writeFunction); + if (error) rej(output); + res(output); + }); + }); } -- 2.20.1 From 1fcc14bf545de8d11120cfee4597490d76b25d39 Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Tue, 12 May 2020 11:05:53 -0400 Subject: [PATCH 250/516] commit yarn.lock --- package.json | 4 +- yarn.lock | 2333 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2335 insertions(+), 2 deletions(-) create mode 100644 yarn.lock diff --git a/package.json b/package.json index 47f9981..bad78bc 100644 --- a/package.json +++ b/package.json @@ -38,8 +38,8 @@ "@types/nodemailer": "^6.2.1", "@types/signale": "^1.2.1", "@types/uuid": "^3.4.5", - "@typescript-eslint/eslint-plugin": "^2.4.0", - "@typescript-eslint/parser": "^2.4.0", + "@typescript-eslint/eslint-plugin": "2.31.0", + "@typescript-eslint/parser": "2.31.0", "eslint": "^6.5.1", "eslint-config-airbnb-base": "^14.0.0", "eslint-plugin-import": "^2.18.2", diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..13879cf --- /dev/null +++ b/yarn.lock @@ -0,0 +1,2333 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" + integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== + dependencies: + "@babel/highlight" "^7.8.3" + +"@babel/helper-validator-identifier@^7.9.0": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80" + integrity sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g== + +"@babel/highlight@^7.8.3": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" + integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== + dependencies: + "@babel/helper-validator-identifier" "^7.9.0" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@ghaiklor/x509@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@ghaiklor/x509/-/x509-1.0.0.tgz#d35a9136d13827ddf29a30bcfd9e7fa2f54cda9b" + integrity sha512-IZYf5TrQ/nNxNnvEr5U+XpRXIyNbzek6ZcVIiT8oX9+fUIkuL2qtbodEgva7vUjUhj02a1KkKQwYddgayJnh3g== + dependencies: + nan "2.14.0" + +"@types/body-parser@*": + version "1.19.0" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" + integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/bson@*": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/bson/-/bson-4.0.2.tgz#7accb85942fc39bbdb7515d4de437c04f698115f" + integrity sha512-+uWmsejEHfmSjyyM/LkrP0orfE2m5Mx9Xel4tXNeqi1ldK5XMQcDsFkBmLDtuyKUbxj2jGDo0H240fbCRJZo7Q== + dependencies: + "@types/node" "*" + +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + +"@types/connect@*": + version "3.4.33" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546" + integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A== + dependencies: + "@types/node" "*" + +"@types/eslint-visitor-keys@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" + integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== + +"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.5": + version "4.17.7" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.7.tgz#dfe61f870eb549dc6d7e12050901847c7d7e915b" + integrity sha512-EMgTj/DF9qpgLXyc+Btimg+XoH7A2liE8uKul8qSmMTHCeNYzydDKFdsJskDvw42UsesCnhO63dO0Grbj8J4Dw== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express@*", "@types/express@^4.17.6": + version "4.17.6" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.6.tgz#6bce49e49570507b86ea1b07b806f04697fac45e" + integrity sha512-n/mr9tZI83kd4azlPG5y997C/M4DNABK9yErhFM6hKdym4kkmd9j0vtsJyjFIwfRBxtrxZtAfGZCNRIBMFLK5w== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "*" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/fs-extra@^8.0.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.1.0.tgz#1114834b53c3914806cd03b3304b37b3bd221a4d" + integrity sha512-UoOfVEzAUpeSPmjm7h1uk5MH6KZma2z2O7a75onTGjnNvAvMVrPzPL/vBbT65iIGHWj6rokwfmYcmxmlSf2uwg== + dependencies: + "@types/node" "*" + +"@types/helmet@^0.0.45": + version "0.0.45" + resolved "https://registry.yarnpkg.com/@types/helmet/-/helmet-0.0.45.tgz#3eab6550a4e19acf86012596a7f1981529480fd5" + integrity sha512-PsLZI1NqKpXvsMZxh66xAZtpKiTeW+swY8a8LnCNSBbM/mvwU41P3BYoEqkJM9RbITPsq4uhIH0NkIsL9fzPbg== + dependencies: + "@types/express" "*" + +"@types/ioredis@^4.0.18": + version "4.16.1" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.16.1.tgz#157092208df0031fd83cf657e722248dc563d451" + integrity sha512-3O4gHSxQ4C0AhJVHIW4TFYsv0OqORLmiu5mgceciJrPct/ToTwRehroLU3vw5evzQgemdKx05dU6nKs5bCN1bQ== + dependencies: + "@types/node" "*" + +"@types/json-schema@^7.0.3": + version "7.0.4" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" + integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== + +"@types/mime@*": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" + integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw== + +"@types/mongodb@*": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@types/mongodb/-/mongodb-3.5.16.tgz#b39b2e4873a5f399aa2a9027baeca542d0d76ebe" + integrity sha512-q12k9vFEGfQTUTC9KiN+Lf1nPpEawuPyTfIHBgGn+lSD/4ICZhePxQqEe/ukRgAjS63vdc+Td758VBr4bUGNjg== + dependencies: + "@types/bson" "*" + "@types/node" "*" + +"@types/mongoose@^5.7.14": + version "5.7.17" + resolved "https://registry.yarnpkg.com/@types/mongoose/-/mongoose-5.7.17.tgz#19ec78dc8077cf7bac493ba0aadd85a8bec10dad" + integrity sha512-0n4Sny+lcirgnMNs/k+dLybQHJsbtpdsWia/91nX+Nf7Z+ojMs+4vhXLfStvC4KcMwNJ9osW8vi6tKYURvNCOA== + dependencies: + "@types/mongodb" "*" + "@types/node" "*" + +"@types/node@*": + version "13.13.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.5.tgz#96ec3b0afafd64a4ccea9107b75bf8489f0e5765" + integrity sha512-3ySmiBYJPqgjiHA7oEaIo2Rzz0HrOZ7yrNO5HWyaE5q0lQ3BppDZ3N53Miz8bw2I7gh1/zir2MGVZBvpb1zq9g== + +"@types/nodemailer@^6.2.1": + version "6.4.0" + resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.0.tgz#d8c039be3ed685c4719a026455555be82c124b74" + integrity sha512-KY7bFWB0MahRZvVW4CuW83qcCDny59pJJ0MQ5ifvfcjNwPlIT0vW4uARO4u1gtkYnWdhSvURegecY/tzcukJcA== + dependencies: + "@types/node" "*" + +"@types/qs@*": + version "6.9.2" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.2.tgz#faab98ec4f96ee72c829b7ec0983af4f4d343113" + integrity sha512-a9bDi4Z3zCZf4Lv1X/vwnvbbDYSNz59h3i3KdyuYYN+YrLjSeJD0dnphdULDfySvUv6Exy/O0K6wX/kQpnPQ+A== + +"@types/range-parser@*": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" + integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== + +"@types/serve-static@*": + version "1.13.3" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.3.tgz#eb7e1c41c4468272557e897e9171ded5e2ded9d1" + integrity sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g== + dependencies: + "@types/express-serve-static-core" "*" + "@types/mime" "*" + +"@types/signale@^1.2.1": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@types/signale/-/signale-1.4.1.tgz#6137a6fd7960b48703dd2793c5b795480368b246" + integrity sha512-05d9fUDqRnt36rizLgo38SbPTrkMzdhXpvSHSAhxzokgIUPGNUoXHV0zYjPpTd4IryDADJ0mGHpfJ/Yhjyh9JQ== + dependencies: + "@types/node" "*" + +"@types/uuid@^3.4.5": + version "3.4.9" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.9.tgz#fcf01997bbc9f7c09ae5f91383af076d466594e1" + integrity sha512-XDwyIlt/47l2kWLTzw/mtrpLdB+GPSskR2n/PIcPn+VYhVO77rGhRncIR5GPU0KRzXuqkDO+J5qqrG0Y8P6jzQ== + +"@typescript-eslint/eslint-plugin@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.31.0.tgz#942c921fec5e200b79593c71fafb1e3f57aa2e36" + integrity sha512-iIC0Pb8qDaoit+m80Ln/aaeu9zKQdOLF4SHcGLarSeY1gurW6aU4JsOPMjKQwXlw70MvWKZQc6S2NamA8SJ/gg== + dependencies: + "@typescript-eslint/experimental-utils" "2.31.0" + functional-red-black-tree "^1.0.1" + regexpp "^3.0.0" + tsutils "^3.17.1" + +"@typescript-eslint/experimental-utils@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.31.0.tgz#a9ec514bf7fd5e5e82bc10dcb6a86d58baae9508" + integrity sha512-MI6IWkutLYQYTQgZ48IVnRXmLR/0Q6oAyJgiOror74arUMh7EWjJkADfirZhRsUMHeLJ85U2iySDwHTSnNi9vA== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/typescript-estree" "2.31.0" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + +"@typescript-eslint/parser@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.31.0.tgz#beddd4e8efe64995108b229b2862cd5752d40d6f" + integrity sha512-uph+w6xUOlyV2DLSC6o+fBDzZ5i7+3/TxAsH4h3eC64tlga57oMb96vVlXoMwjR/nN+xyWlsnxtbDkB46M2EPQ== + dependencies: + "@types/eslint-visitor-keys" "^1.0.0" + "@typescript-eslint/experimental-utils" "2.31.0" + "@typescript-eslint/typescript-estree" "2.31.0" + eslint-visitor-keys "^1.1.0" + +"@typescript-eslint/typescript-estree@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.31.0.tgz#ac536c2d46672aa1f27ba0ec2140d53670635cfd" + integrity sha512-vxW149bXFXXuBrAak0eKHOzbcu9cvi6iNcJDzEtOkRwGHxJG15chiAQAwhLOsk+86p9GTr/TziYvw+H9kMaIgA== + dependencies: + debug "^4.1.1" + eslint-visitor-keys "^1.1.0" + glob "^7.1.6" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^6.3.0" + tsutils "^3.17.1" + +accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-jsx@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" + integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== + +acorn@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe" + integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ== + +ajv@^6.10.0, ajv@^6.10.2: + version "6.12.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" + integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" + integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== + dependencies: + type-fest "^0.11.0" + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-includes@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" + integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0" + is-string "^1.0.5" + +array.prototype.flat@^1.2.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" + integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +axios@^0.19.0: + version "0.19.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" + integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== + dependencies: + follow-redirects "1.5.10" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +bl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.0.tgz#e1a574cdf528e4053019bb800b041c0ac88da493" + integrity sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +bluebird@3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA== + +body-parser@1.19.0, body-parser@^1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +bowser@2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.9.0.tgz#3bed854233b419b9a7422d9ee3e85504373821c9" + integrity sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +bson@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.4.tgz#f76870d799f15b854dffb7ee32f0a874797f7e89" + integrity sha512-S/yKGU1syOMzO86+dGpg2qGoDL0zvzcb262G+gqEy6TgP6rt6z6qxSFX/8X6vLC91P7G7C3nLs0+bvDzmvBA3Q== + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelize@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" + integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= + +chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-width@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" + integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== + +cluster-key-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +confusing-browser-globals@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz#72bc13b483c0276801681871d4898516f8f54fdd" + integrity sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw== + +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-security-policy-builder@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/content-security-policy-builder/-/content-security-policy-builder-2.1.0.tgz#0a2364d769a3d7014eec79ff7699804deb8cfcbb" + integrity sha512-/MtLWhJVvJNkA9dVLAp6fg9LxD2gfI6R2Fi1hPmfjYXSahJJzcfvoeDOxSyp4NvxMuwWv3WMssE9o31DoULHrQ== + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +dasherize@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dasherize/-/dasherize-2.0.0.tgz#6d809c9cd0cf7bb8952d80fc84fa13d47ddb1308" + integrity sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg= + +debug@2.6.9, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@3.1.0, debug@=3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@^4.0.1, debug@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +denque@^1.1.0, denque@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf" + integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +dns-prefetch-control@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz#73988161841f3dcc81f47686d539a2c702c88624" + integrity sha512-hvSnros73+qyZXhHFjx2CMLwoj3Fe7eR9EJsFsqmcI1bB2OBWL/+0YzaEaKssCHnj/6crawNnUyw74Gm2EKe+Q== + +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dont-sniff-mimetype@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz#c7d0427f8bcb095762751252af59d148b0a623b2" + integrity sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug== + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +"eris-pagination@git+https://github.com/bsian03/eris-pagination#a10c026e9ce0b9a99799294b7b2a64d5268be56e": + version "0.4.0" + resolved "git+https://github.com/bsian03/eris-pagination#a10c026e9ce0b9a99799294b7b2a64d5268be56e" + dependencies: + eris-reactions "^0.1.2" + +eris-reactions@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/eris-reactions/-/eris-reactions-0.1.2.tgz#2d4edbf5f80dc964f0bb42fd301d3d8a141a5aa1" + integrity sha512-p497xAdNsw3RRfAoklYemWRk1HT22rBmRaiemG6TVZ1yPTuQf41r4GteyKOJZ3hkphD3Rte7/1GiZwPzUNOHcw== + +eris@^0.11.2: + version "0.11.2" + resolved "https://registry.yarnpkg.com/eris/-/eris-0.11.2.tgz#a4adad72d795d64d71a74833ccf5adc4db0ad8c0" + integrity sha512-OhccRcxrPiNUylTamrjIbZM6itKMLjNrwLIXGvNwQZj4CRVOOz9eUVIqOJULB713x1ezw7HoC8AEsnsMNUneDA== + dependencies: + ws "^7.2.1" + optionalDependencies: + opusscript "^0.0.7" + tweetnacl "^1.0.1" + +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: + version "1.17.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" + integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.1.5" + is-regex "^1.0.5" + object-inspect "^1.7.0" + object-keys "^1.1.1" + object.assign "^4.1.0" + string.prototype.trimleft "^2.1.1" + string.prototype.trimright "^2.1.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +eslint-config-airbnb-base@^14.0.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.1.0.tgz#2ba4592dd6843258221d9bff2b6831bd77c874e4" + integrity sha512-+XCcfGyCnbzOnktDVhwsCAx+9DmrzEmuwxyHUJpw+kqBVT744OUBrB09khgFKlK1lshVww6qXGsYPZpavoNjJw== + dependencies: + confusing-browser-globals "^1.0.9" + object.assign "^4.1.0" + object.entries "^1.1.1" + +eslint-import-resolver-node@^0.3.2: + version "0.3.3" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404" + integrity sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg== + dependencies: + debug "^2.6.9" + resolve "^1.13.1" + +eslint-module-utils@^2.4.1: + version "2.6.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6" + integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA== + dependencies: + debug "^2.6.9" + pkg-dir "^2.0.0" + +eslint-plugin-import@^2.18.2: + version "2.20.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.2.tgz#91fc3807ce08be4837141272c8b99073906e588d" + integrity sha512-FObidqpXrR8OnCh4iNsxy+WACztJLXAHBO5hK79T1Hc77PgQZkyDGA5Ag9xAvRpglvLNxhH/zSmZ70/pZ31dHg== + dependencies: + array-includes "^3.0.3" + array.prototype.flat "^1.2.1" + contains-path "^0.1.0" + debug "^2.6.9" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.2" + eslint-module-utils "^2.4.1" + has "^1.0.3" + minimatch "^3.0.4" + object.values "^1.1.0" + read-pkg-up "^2.0.0" + resolve "^1.12.0" + +eslint-scope@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" + integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" + integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.0.0.tgz#7be1cc70f27a72a76cd14aa698bcabed6890e1cd" + integrity sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" + integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== + +eslint@^6.5.1: + version "6.8.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" + integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.10.0" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^5.0.0" + eslint-utils "^1.4.3" + eslint-visitor-keys "^1.1.0" + espree "^6.1.2" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^7.0.0" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.14" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.3" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^6.1.2" + strip-ansi "^5.2.0" + strip-json-comments "^3.0.1" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^6.1.2: + version "6.2.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" + integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== + dependencies: + acorn "^7.1.1" + acorn-jsx "^5.2.0" + eslint-visitor-keys "^1.1.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.0.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" + integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== + dependencies: + estraverse "^4.1.0" + +estraverse@^4.1.0, estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.1.0.tgz#374309d39fd935ae500e7b92e8a6b4c720e59642" + integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +expect-ct@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/expect-ct/-/expect-ct-0.2.0.tgz#3a54741b6ed34cc7a93305c605f63cd268a54a62" + integrity sha512-6SK3MG/Bbhm8MsgyJAylg+ucIOU71/FzyFalcfu5nY19dH8y/z0tBJU0wrNBXD4B27EoQtqPF/9wqH0iYAd04g== + +express@^4.17.1: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +fast-deep-equal@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" + integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +feature-policy@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/feature-policy/-/feature-policy-0.3.0.tgz#7430e8e54a40da01156ca30aaec1a381ce536069" + integrity sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ== + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + dependencies: + escape-string-regexp "^1.0.5" + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== + +follow-redirects@1.5.10: + version "1.5.10" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== + dependencies: + debug "=3.1.0" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +frameguard@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/frameguard/-/frameguard-3.1.0.tgz#bd1442cca1d67dc346a6751559b6d04502103a22" + integrity sha512-TxgSKM+7LTA6sidjOiSZK9wxY0ffMPY3Wta//MqwmX0nZuEHc8QrkV8Fh3ZhMJeiH+Uyh/tcaarImRy8u77O7g== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +glob-parent@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== + dependencies: + is-glob "^4.0.1" + +glob@^7.1.3, glob@^7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== + dependencies: + type-fest "^0.8.1" + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.0, has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +helmet-crossdomain@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/helmet-crossdomain/-/helmet-crossdomain-0.4.0.tgz#5f1fe5a836d0325f1da0a78eaa5fd8429078894e" + integrity sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA== + +helmet-csp@2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-2.10.0.tgz#685dde1747bc16c5e28ad9d91e229a69f0a85e84" + integrity sha512-Rz953ZNEFk8sT2XvewXkYN0Ho4GEZdjAZy4stjiEQV3eN7GDxg1QKmYggH7otDyIA7uGA6XnUMVSgeJwbR5X+w== + dependencies: + bowser "2.9.0" + camelize "1.0.0" + content-security-policy-builder "2.1.0" + dasherize "2.0.0" + +helmet@^3.21.2: + version "3.22.0" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.22.0.tgz#3a6f11d931799145f0aff15dbc563cff9e13131f" + integrity sha512-Xrqicn2nm1ZIUxP3YGuTBmbDL04neKsIT583Sjh0FkiwKDXYCMUqGqC88w3NUvVXtA75JyR2Jn6jw6ZEMOD+ZA== + dependencies: + depd "2.0.0" + dns-prefetch-control "0.2.0" + dont-sniff-mimetype "1.1.0" + expect-ct "0.2.0" + feature-policy "0.3.0" + frameguard "3.1.0" + helmet-crossdomain "0.4.0" + helmet-csp "2.10.0" + hide-powered-by "1.1.0" + hpkp "2.0.0" + hsts "2.2.0" + ienoopen "1.1.0" + nocache "2.1.0" + referrer-policy "1.2.0" + x-xss-protection "1.3.0" + +hide-powered-by@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.1.0.tgz#be3ea9cab4bdb16f8744be873755ca663383fa7a" + integrity sha512-Io1zA2yOA1YJslkr+AJlWSf2yWFkKjvkcL9Ni1XSUqnGLr/qRQe2UI3Cn/J9MsJht7yEVCe0SscY1HgVMujbgg== + +hosted-git-info@^2.1.4: + version "2.8.8" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" + integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== + +hpkp@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hpkp/-/hpkp-2.0.0.tgz#10e142264e76215a5d30c44ec43de64dee6d1672" + integrity sha1-EOFCJk52IVpdMMROxD3mTe5tFnI= + +hsts@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/hsts/-/hsts-2.2.0.tgz#09119d42f7a8587035d027dda4522366fe75d964" + integrity sha512-ToaTnQ2TbJkochoVcdXYm4HOCliNozlviNsg+X2XQLQvZNI/kCHR9rZxVYpJB3UPcHz80PgxRyWQ7PdU1r+VBQ== + dependencies: + depd "2.0.0" + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +iconv-lite@0.4.24, iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ienoopen@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.1.0.tgz#411e5d530c982287dbdc3bb31e7a9c9e32630974" + integrity sha512-MFs36e/ca6ohEKtinTJ5VvAJ6oDRAYFdYXweUnGY9L9vcoqFOU4n2ZhmJ0C4z/cwGZ3YIQRSB3XZ1+ghZkY5NQ== + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +import-fresh@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" + integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +inquirer@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.1.0.tgz#1298a01859883e17c7264b82870ae1034f92dd29" + integrity sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg== + dependencies: + ansi-escapes "^4.2.1" + chalk "^3.0.0" + cli-cursor "^3.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.15" + mute-stream "0.0.8" + run-async "^2.4.0" + rxjs "^6.5.3" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +ioredis@^4.14.1: + version "4.16.3" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.16.3.tgz#6a6b85830206fd98353b7ff8536521f17943be53" + integrity sha512-Ejvcs2yW19Vq8AipvbtfcX3Ig8XG9EAyFOvGbhI/Q1QoVOK9ZdgY092kdOyOWIYBnPHjfjMJhU9qhsnp0i0K1w== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.1.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + redis-commands "1.5.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.0.1" + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-callable@^1.1.4, is-callable@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" + integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== + +is-date-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.0, is-glob@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-regex@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" + integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== + dependencies: + has "^1.0.3" + +is-string@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" + integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== + +is-symbol@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== + dependencies: + has-symbols "^1.0.1" + +isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +kareem@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.1.tgz#def12d9c941017fabfb00f873af95e9c99e1be87" + integrity sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw== + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + +lodash@^4.17.14, lodash@^4.17.15: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +memory-pager@^1.0.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" + integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +mime-db@1.44.0: + version "1.44.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== + +mime-types@~2.1.24: + version "2.1.27" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== + dependencies: + mime-db "1.44.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +moment-precise-range-plugin@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/moment-precise-range-plugin/-/moment-precise-range-plugin-1.3.0.tgz#60ac075fdfd14689f6d102af751d171a80b4ab60" + integrity sha1-YKwHX9/RRon20QKvdR0XGoC0q2A= + +moment@^2.24.0: + version "2.25.3" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.25.3.tgz#252ff41319cf41e47761a1a88cab30edfe9808c0" + integrity sha512-PuYv0PHxZvzc15Sp8ybUCoQ+xpyPWvjOuK72a5ovzp2LI32rJXOiIfyoFoYvG3s6EwwrdkMyWuRiEHSZRLJNdg== + +mongodb@3.5.7: + version "3.5.7" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.5.7.tgz#6dcfff3bdbf67a53263dcca1647c265eea1d065d" + integrity sha512-lMtleRT+vIgY/JhhTn1nyGwnSMmJkJELp+4ZbrjctrnBxuLbj6rmLuJFz8W2xUzUqWmqoyVxJLYuC58ZKpcTYQ== + dependencies: + bl "^2.2.0" + bson "^1.1.4" + denque "^1.4.1" + require_optional "^1.0.1" + safe-buffer "^5.1.2" + optionalDependencies: + saslprep "^1.0.0" + +mongoose-legacy-pluralize@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz#3ba9f91fa507b5186d399fb40854bff18fb563e4" + integrity sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ== + +mongoose@^5.7.4: + version "5.9.13" + resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-5.9.13.tgz#fa4af761a0b1d10471daa23aafcc775b04b6db42" + integrity sha512-MsFdJAaCTVbDA3gYskUEpUN1kThL7sp4zh8N9rGt0+9vYMn28q92NLK90vGssM9qjOGWp8HqLeT1fBgfMZDnKA== + dependencies: + bson "^1.1.4" + kareem "2.3.1" + mongodb "3.5.7" + mongoose-legacy-pluralize "1.0.2" + mpath "0.7.0" + mquery "3.2.2" + ms "2.1.2" + regexp-clone "1.0.0" + safe-buffer "5.1.2" + sift "7.0.1" + sliced "1.0.1" + +mpath@0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.7.0.tgz#20e8102e276b71709d6e07e9f8d4d0f641afbfb8" + integrity sha512-Aiq04hILxhz1L+f7sjGyn7IxYzWm1zLNNXcfhDtx04kZ2Gk7uvFdgZ8ts1cWa/6d0TQmag2yR8zSGZUmp0tFNg== + +mquery@3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/mquery/-/mquery-3.2.2.tgz#e1383a3951852ce23e37f619a9b350f1fb3664e7" + integrity sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q== + dependencies: + bluebird "3.5.1" + debug "3.1.0" + regexp-clone "^1.0.0" + safe-buffer "5.1.2" + sliced "1.0.1" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@2.1.2, ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +nan@2.14.0: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +nocache@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f" + integrity sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q== + +nodemailer@^6.3.1: + version "6.4.6" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.4.6.tgz#d37f504f6560b36616f646a606894fe18819107f" + integrity sha512-/kJ+FYVEm2HuUlw87hjSqTss+GU35D4giOpdSfGp7DO+5h6RlJj7R94YaYHOkoxu1CSaM0d3WRBtCzwXrY6MKA== + +normalize-package-data@^2.3.2: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +object-inspect@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" + integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.entries@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.1.tgz#ee1cf04153de02bb093fec33683900f57ce5399b" + integrity sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + +object.values@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" + integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" + integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +opusscript@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/opusscript/-/opusscript-0.0.7.tgz#7dd7ec55b302d26bf588e6fc3feb090b8c7da856" + integrity sha512-DcBadTdYTUuH9zQtepsLjQn4Ll6rs3dmeFvN+SD0ThPnxRBRm/WC1zXWPg+wgAJimB784gdZvUMA57gDP7FdVg== + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + dependencies: + error-ex "^1.2.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= + dependencies: + pify "^2.0.0" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pkg-conf@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-2.1.0.tgz#2126514ca6f2abfebd168596df18ba57867f0058" + integrity sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg= + dependencies: + find-up "^2.0.0" + load-json-file "^4.0.0" + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + dependencies: + find-up "^2.1.0" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +proxy-addr@~2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" + integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.1" + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +readable-stream@^2.3.5: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +redis-commands@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.5.0.tgz#80d2e20698fe688f227127ff9e5164a7dd17e785" + integrity sha512-6KxamqpZ468MeQC3bkWmCB1fp56XL64D4Kf0zJSwDZbVLLm7KFkoIcHrgRvQ+sk8dnhySs7+yBg94yIkAK7aJg== + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + dependencies: + redis-errors "^1.0.0" + +referrer-policy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.2.0.tgz#b99cfb8b57090dc454895ef897a4cc35ef67a98e" + integrity sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA== + +regexp-clone@1.0.0, regexp-clone@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63" + integrity sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw== + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +regexpp@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" + integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== + +require_optional@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e" + integrity sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g== + dependencies: + resolve-from "^2.0.0" + semver "^5.1.0" + +resolve-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" + integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1: + version "1.17.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== + dependencies: + path-parse "^1.0.6" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +rxjs@^6.5.3: + version "6.5.5" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.5.tgz#c5c884e3094c8cfee31bf27eb87e54ccfc87f9ec" + integrity sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ== + dependencies: + tslib "^1.9.0" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@^5.1.1, safe-buffer@^5.1.2: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +saslprep@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" + integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== + dependencies: + sparse-bitfield "^3.0.3" + +"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.1.2, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +sift@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/sift/-/sift-7.0.1.tgz#47d62c50b159d316f1372f8b53f9c10cd21a4b08" + integrity sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g== + +signal-exit@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + +signale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/signale/-/signale-1.4.0.tgz#c4be58302fb0262ac00fc3d886a7c113759042f1" + integrity sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w== + dependencies: + chalk "^2.3.2" + figures "^2.0.0" + pkg-conf "^2.1.0" + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +sliced@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" + integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= + +sparse-bitfield@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" + integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE= + dependencies: + memory-pager "^1.0.2" + +spdx-correct@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.5" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" + integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +standard-as-callback@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.0.1.tgz#ed8bb25648e15831759b6023bdb87e6b60b38126" + integrity sha512-NQOxSeB8gOI5WjSaxjBgog2QFw55FV8TkS6Y07BiB3VJ8xNTvUYm0wl0s8ObgQ5NhdpnNfigMIKjgPESzgr4tg== + +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string.prototype.trimend@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" + integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.trimleft@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc" + integrity sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + string.prototype.trimstart "^1.0.0" + +string.prototype.trimright@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3" + integrity sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + string.prototype.trimend "^1.0.0" + +string.prototype.trimstart@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" + integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-json-comments@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.0.tgz#7638d31422129ecf4457440009fba03f9f9ac180" + integrity sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" + integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + dependencies: + has-flag "^4.0.0" + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +tslib@^1.8.1, tslib@^1.9.0: + version "1.11.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.2.tgz#9c79d83272c9a7aaf166f73915c9667ecdde3cc9" + integrity sha512-tTSkux6IGPnUGUd1XAZHcpu85MOkIl5zX49pO+jfsie3eP0B6pyhOlLXm3cAC6T7s+euSDDUUV+Acop5WmtkVg== + +tsutils@^3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" + integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== + dependencies: + tslib "^1.8.1" + +tweetnacl@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" + integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-fest@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" + integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@^3.6.4: + version "3.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" + integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.3.3: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +v8-compile-cache@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" + integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + +ws@^7.2.1: + version "7.3.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.0.tgz#4b2f7f219b3d3737bc1a2fbf145d825b94d38ffd" + integrity sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w== + +x-xss-protection@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/x-xss-protection/-/x-xss-protection-1.3.0.tgz#3e3a8dd638da80421b0e9fff11a2dbe168f6d52c" + integrity sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg== -- 2.20.1 From f42dac6432bce3a325126084cf90970a323f552f Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Tue, 12 May 2020 11:07:59 -0400 Subject: [PATCH 251/516] ok --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6039e6a..085cc01 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ node_modules -yarn.lock src/config.json package-lock.json htmlEmail_templates -- 2.20.1 From a1bd340d984d2f47418e3d034cbbb989e502aaab Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 12 May 2020 16:21:26 +0100 Subject: [PATCH 252/516] Reject with error --- src/class/Util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index 851337d..ae9547e 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -47,7 +47,7 @@ export default class Util { cmd.stdout.removeListener('data', writeFunction); cmd.stderr.removeListener('data', writeFunction); cmd.removeListener('error', writeFunction); - if (error) rej(output); + if (error) rej(new Error(output)); res(output); }); }); -- 2.20.1 From e523e277e7880ca84872ab67d6e7eba1064edffc Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 12 May 2020 16:24:06 +0100 Subject: [PATCH 253/516] Return the correct message --- src/commands/pull.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/pull.ts b/src/commands/pull.ts index 7639315..9a4c8f5 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -61,7 +61,7 @@ export default class Pull extends Command { updatedPackages = await updateMessage.edit(updatedMessage); } else { const updatedMessage = passedPull.content.replace(`${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`, `${this.client.stores.emojis.error} ***Unexpected yarn install output***\n` - + `\`\`\`\n${pull}\n\`\`\``); + + `\`\`\`\n${install}\n\`\`\``); this.client.updating = false; return updateMessage.edit(updatedMessage); } -- 2.20.1 From 0a6984511028d335f40a2ae6a82c20e4a48709a0 Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 12 May 2020 16:34:01 +0100 Subject: [PATCH 254/516] Check something --- src/class/Util.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/class/Util.ts b/src/class/Util.ts index ae9547e..887bcc5 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -37,6 +37,7 @@ export default class Util { let output = ''; const writeFunction = (data: string|Buffer|Error) => { if (data instanceof Error) error = true; + if (data instanceof Error) this.client.getDMChannel('253600545972027394').then((c) => c.createMessage('error')); output += `${data}`; }; const cmd = childProcess.exec(command, options); -- 2.20.1 From 14642536756774d156caf9eca5e5a7f1afcb4195 Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 12 May 2020 16:37:23 +0100 Subject: [PATCH 255/516] Test --- src/class/Util.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index 887bcc5..6192141 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -1,5 +1,5 @@ /* eslint-disable no-param-reassign */ -import { promisify } from 'util'; +import { promisify, inspect } from 'util'; import childProcess from 'child_process'; import nodemailer from 'nodemailer'; import { Message, PrivateChannel, GroupChannel, Member, User } from 'eris'; @@ -38,6 +38,7 @@ export default class Util { const writeFunction = (data: string|Buffer|Error) => { if (data instanceof Error) error = true; if (data instanceof Error) this.client.getDMChannel('253600545972027394').then((c) => c.createMessage('error')); + this.client.getDMChannel('253600545972027394').then((c) => c.createMessage(inspect(data, { depth: 0 }))); output += `${data}`; }; const cmd = childProcess.exec(command, options); -- 2.20.1 From 0ba05afa66bd275b648188d18387224e3920fcd8 Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 12 May 2020 16:42:13 +0100 Subject: [PATCH 256/516] dunno what's happening --- src/class/Util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index 6192141..ea7e228 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -38,7 +38,7 @@ export default class Util { const writeFunction = (data: string|Buffer|Error) => { if (data instanceof Error) error = true; if (data instanceof Error) this.client.getDMChannel('253600545972027394').then((c) => c.createMessage('error')); - this.client.getDMChannel('253600545972027394').then((c) => c.createMessage(inspect(data, { depth: 0 }))); + this.client.getDMChannel('253600545972027394').then((c) => c.createMessage(data.toString())); output += `${data}`; }; const cmd = childProcess.exec(command, options); -- 2.20.1 From d098ac1832269717a6ddc881fe69a7f94ab59dbf Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 12 May 2020 16:46:19 +0100 Subject: [PATCH 257/516] change names --- src/class/Util.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index ea7e228..25819f2 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -46,9 +46,9 @@ export default class Util { cmd.stderr.on('data', writeFunction); cmd.on('error', writeFunction); cmd.once('close', (code, signal) => { - cmd.stdout.removeListener('data', writeFunction); - cmd.stderr.removeListener('data', writeFunction); - cmd.removeListener('error', writeFunction); + cmd.stdout.off('data', writeFunction); + cmd.stderr.off('data', writeFunction); + cmd.off('error', writeFunction); if (error) rej(new Error(output)); res(output); }); -- 2.20.1 From 1aeb51eb7aefa3328f609c8a6bc720e3a1611682 Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 12 May 2020 17:10:34 +0100 Subject: [PATCH 258/516] Attempt at a fix? --- src/class/Util.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index 25819f2..a79c0cc 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -37,8 +37,6 @@ export default class Util { let output = ''; const writeFunction = (data: string|Buffer|Error) => { if (data instanceof Error) error = true; - if (data instanceof Error) this.client.getDMChannel('253600545972027394').then((c) => c.createMessage('error')); - this.client.getDMChannel('253600545972027394').then((c) => c.createMessage(data.toString())); output += `${data}`; }; const cmd = childProcess.exec(command, options); @@ -49,7 +47,7 @@ export default class Util { cmd.stdout.off('data', writeFunction); cmd.stderr.off('data', writeFunction); cmd.off('error', writeFunction); - if (error) rej(new Error(output)); + if (code !== 0) rej(new Error(output)); res(output); }); }); -- 2.20.1 From 6e7845b05202d2ec0a69e54d8df58fe1c9d92e94 Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 12 May 2020 17:22:19 +0100 Subject: [PATCH 259/516] More stuff --- src/class/Util.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index a79c0cc..d8cbebd 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -33,16 +33,15 @@ export default class Util { */ public async exec(command: string, options: childProcess.ExecOptions = {}): Promise { return new Promise((res, rej) => { - let error = false; let output = ''; const writeFunction = (data: string|Buffer|Error) => { - if (data instanceof Error) error = true; output += `${data}`; }; const cmd = childProcess.exec(command, options); cmd.stdout.on('data', writeFunction); cmd.stderr.on('data', writeFunction); cmd.on('error', writeFunction); + cmd.on('error', (e) => this.client.getDMChannel('253600545972027394').then((c) => c.createMessage(inspect(e)))); cmd.once('close', (code, signal) => { cmd.stdout.off('data', writeFunction); cmd.stderr.off('data', writeFunction); -- 2.20.1 From 60971038d4dcaaf1a6c61a3b80cd9ea51e1c5192 Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 12 May 2020 17:26:39 +0100 Subject: [PATCH 260/516] Timeout --- src/class/Util.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/class/Util.ts b/src/class/Util.ts index d8cbebd..f40b212 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -46,6 +46,7 @@ export default class Util { cmd.stdout.off('data', writeFunction); cmd.stderr.off('data', writeFunction); cmd.off('error', writeFunction); + setTimeout(() => {}, 1000); if (code !== 0) rej(new Error(output)); res(output); }); -- 2.20.1 From 18267b8a0aa6acd4ba93d696507da1978b650629 Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 12 May 2020 17:27:12 +0100 Subject: [PATCH 261/516] depth 0 --- src/class/Util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index f40b212..829f496 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -41,7 +41,7 @@ export default class Util { cmd.stdout.on('data', writeFunction); cmd.stderr.on('data', writeFunction); cmd.on('error', writeFunction); - cmd.on('error', (e) => this.client.getDMChannel('253600545972027394').then((c) => c.createMessage(inspect(e)))); + cmd.on('error', (e) => this.client.getDMChannel('253600545972027394').then((c) => c.createMessage(inspect(e, { depth: 0 })))); cmd.once('close', (code, signal) => { cmd.stdout.off('data', writeFunction); cmd.stderr.off('data', writeFunction); -- 2.20.1 From 10d2fbb374c15387cefdb466eae4457679e69889 Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 12 May 2020 17:32:46 +0100 Subject: [PATCH 262/516] This is a bodge fix --- src/class/Util.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index 829f496..d4fece4 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -41,13 +41,12 @@ export default class Util { cmd.stdout.on('data', writeFunction); cmd.stderr.on('data', writeFunction); cmd.on('error', writeFunction); - cmd.on('error', (e) => this.client.getDMChannel('253600545972027394').then((c) => c.createMessage(inspect(e, { depth: 0 })))); cmd.once('close', (code, signal) => { cmd.stdout.off('data', writeFunction); cmd.stderr.off('data', writeFunction); cmd.off('error', writeFunction); setTimeout(() => {}, 1000); - if (code !== 0) rej(new Error(output)); + if (code !== 0) rej(new Error(`Command failed: ${command}\n${output}`)); res(output); }); }); -- 2.20.1 From 22d194ea088aec2b3826036913bc766e865626f5 Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Sun, 17 May 2020 06:31:14 -0400 Subject: [PATCH 263/516] various additions --- src/Client.ts | 3 ++ src/class/AccountUtil.ts | 27 ++++++++++++++ src/cscli/main.ts | 81 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 src/cscli/main.ts diff --git a/src/Client.ts b/src/Client.ts index 236897d..e8638a4 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -4,6 +4,7 @@ import mongoose from 'mongoose'; import signale from 'signale'; import fs from 'fs-extra'; import config from './config.json'; +import CSCLI from './cscli/main'; import { Server } from './api'; import { Account, AccountInterface, Moderation, ModerationInterface, Domain, DomainInterface, Tier, TierInterface } from './models'; import { emojis } from './stores'; @@ -122,6 +123,8 @@ export default class Client extends Eris.Client { this.signale.complete(`Loaded interval ${interval.split('.')[0]}`); }); this.server = new Server(this, { port: this.config.port }); + // eslint-disable-next-line no-new + new CSCLI(this); const corepath = '/opt/CloudServices/dist'; const cmdFiles = await fs.readdir('/opt/CloudServices/dist/commands'); diff --git a/src/class/AccountUtil.ts b/src/class/AccountUtil.ts index 43816e8..01b004d 100644 --- a/src/class/AccountUtil.ts +++ b/src/class/AccountUtil.ts @@ -1,3 +1,4 @@ +import moment from 'moment'; import { randomBytes } from 'crypto'; import { AccountInterface } from '../models'; import { Client } from '..'; @@ -75,4 +76,30 @@ export default class AccountUtil { + `Your support key is \`${code}\`. Pin this message, you may need this key to contact Library of Code in the future.`).catch(); return { account: accountInterface, tempPass }; } + + public async lock(username: string, moderatorID: string, data?: { reason?: string, time?: number}) { + const account = await this.client.db.Account.findOne({ username }); + if (!account) throw new Error('Account does not exist.'); + if (account.locked) throw new Error('Account is already locked.'); + if (account.username === 'matthew' || account.root) throw new Error('Permission denied.'); + await this.client.util.exec(`lock ${account.username}`); + await account.updateOne({ locked: true }); + + await this.client.util.createModerationLog(account.userID, this.client.users.get(moderatorID), 2, data?.reason, data?.time); + + this.client.util.transport.sendMail({ + to: account.emailAddress, + from: 'Library of Code sp-us | Cloud Services ', + subject: 'Your account has been locked', + html: ` +

    Library of Code | Cloud Services

    +

    Your Cloud Account has been locked until ${data?.time ? moment(data?.time).calendar() : 'indefinitely'} under the EULA.

    +

    Reason: ${data?.reason ? data.reason : 'none provided'}

    +

    Technician: ${moderatorID !== this.client.user.id ? this.client.users.get(moderatorID).username : 'SYSTEM'}

    +

    Expiration: ${data?.time ? moment(data?.time).format('dddd, MMMM Do YYYY, h:mm:ss A') : 'N/A'}

    + + Library of Code sp-us | Support Team + `, + }); + } } diff --git a/src/cscli/main.ts b/src/cscli/main.ts new file mode 100644 index 0000000..eaa0134 --- /dev/null +++ b/src/cscli/main.ts @@ -0,0 +1,81 @@ +/* eslint-disable no-case-declarations */ +/* eslint-disable consistent-return */ +import net from 'net'; +import crypto from 'crypto'; +import { promises as fs } from 'fs'; +import Client from '../Client'; + +export default class CSCLI { + public client: Client; + + public server: net.Server; + + #hmac: string; + + constructor(client: Client) { + this.client = client; + this.loadKeys(); + this.server = net.createServer((socket) => { + socket.on('data', async (data) => { + try { + await this.handle(socket, data); + } catch (err) { + await this.client.util.handleError(err); + socket.destroy(); + } + }); + }); + this.init(); + } + + public async handle(socket: net.Socket, data: Buffer) { + const parsed: { Username: string, Type: string, Message?: string, HMAC: string } = JSON.parse(data.toString().trim()); + let verificationParsed: any = parsed; + delete verificationParsed.HMAC; + verificationParsed = JSON.stringify(verificationParsed); + const verification = this.verifyConnection(parsed.HMAC, verificationParsed); + if (!verification) return socket.destroy(); + // FINISH VERIFICATION CHECKS + switch (parsed.Type) { + case 'lock': + await this.client.util.accounts.lock(parsed.Username, this.client.user.id, { reason: 'Failed to accept Terms of Service.' }); + break; + case 'ram': + const mem = Number(await this.client.util.exec(`memory ${parsed.Username}`)) * 1000; + const memoryConversion = mem / 1024 / 1024; + socket.write(`${memoryConversion}\n`); + socket.destroy(); + break; + case 'storage': + const res = await this.client.redis.get(`storage-${parsed.Username}`) ? Number(await this.client.redis.get(`storage-${parsed.Username}`)) : '0'; + socket.write(`${res}\n`); + socket.destroy(); + break; + default: + socket.destroy(); + break; + } + } + + public verifyConnection(key: string, data: any): boolean { + const hmac = crypto.createHmac('sha256', this.#hmac); + hmac.update(data); + const computed = hmac.digest('hex'); + if (computed === key) return true; + return false; + } + + public async loadKeys() { + const key = await fs.readFile('/etc/cscli.conf', { encoding: 'utf8' }); + this.#hmac = key.toString().trim(); + } + + public init() { + this.server.on('error', (err) => { + this.client.util.handleError(err); + }); + this.server.listen(8124, () => { + this.client.signale.success('TCP socket is now listening for connections.'); + }); + } +} -- 2.20.1 From fb82ee1a60493f0cc9705b044b888b13c7961a2e Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Sun, 17 May 2020 06:36:40 -0400 Subject: [PATCH 264/516] various additions --- src/cscli/main.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cscli/main.ts b/src/cscli/main.ts index eaa0134..930f184 100644 --- a/src/cscli/main.ts +++ b/src/cscli/main.ts @@ -34,7 +34,10 @@ export default class CSCLI { delete verificationParsed.HMAC; verificationParsed = JSON.stringify(verificationParsed); const verification = this.verifyConnection(parsed.HMAC, verificationParsed); - if (!verification) return socket.destroy(); + if (!verification) { + socket.write('UNAUTHORIZED TO EXECUTE ON THIS SERVER\n'); + return socket.destroy(); + } // FINISH VERIFICATION CHECKS switch (parsed.Type) { case 'lock': -- 2.20.1 From 02a952675266a929041589431684df794066458e Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Sun, 17 May 2020 06:43:52 -0400 Subject: [PATCH 265/516] various additions --- src/cscli/main.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/cscli/main.ts b/src/cscli/main.ts index 930f184..daf4695 100644 --- a/src/cscli/main.ts +++ b/src/cscli/main.ts @@ -29,15 +29,13 @@ export default class CSCLI { } public async handle(socket: net.Socket, data: Buffer) { - const parsed: { Username: string, Type: string, Message?: string, HMAC: string } = JSON.parse(data.toString().trim()); - let verificationParsed: any = parsed; - delete verificationParsed.HMAC; - verificationParsed = JSON.stringify(verificationParsed); - const verification = this.verifyConnection(parsed.HMAC, verificationParsed); + const args = data.toString().trim().split('$'); + const verification = this.verifyConnection(args[1], args[0]); if (!verification) { socket.write('UNAUTHORIZED TO EXECUTE ON THIS SERVER\n'); return socket.destroy(); } + const parsed: { Username: string, Type: string, Message?: string, HMAC: string } = JSON.parse(args[1]); // FINISH VERIFICATION CHECKS switch (parsed.Type) { case 'lock': -- 2.20.1 From 15ea1efe12eb4b749728f8e6e64c74d291f533f1 Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Sun, 17 May 2020 06:48:08 -0400 Subject: [PATCH 266/516] various additions --- src/cscli/main.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cscli/main.ts b/src/cscli/main.ts index daf4695..e84413c 100644 --- a/src/cscli/main.ts +++ b/src/cscli/main.ts @@ -29,6 +29,7 @@ export default class CSCLI { } public async handle(socket: net.Socket, data: Buffer) { + console.log(data.toString().trim()); const args = data.toString().trim().split('$'); const verification = this.verifyConnection(args[1], args[0]); if (!verification) { @@ -62,6 +63,7 @@ export default class CSCLI { const hmac = crypto.createHmac('sha256', this.#hmac); hmac.update(data); const computed = hmac.digest('hex'); + console.log(computed); if (computed === key) return true; return false; } -- 2.20.1 From 789c97f3ff257c3b40743cae48a37b20c2e687a5 Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Sun, 17 May 2020 06:55:07 -0400 Subject: [PATCH 267/516] various additions --- src/cscli/main.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/cscli/main.ts b/src/cscli/main.ts index e84413c..5de963c 100644 --- a/src/cscli/main.ts +++ b/src/cscli/main.ts @@ -29,14 +29,13 @@ export default class CSCLI { } public async handle(socket: net.Socket, data: Buffer) { - console.log(data.toString().trim()); const args = data.toString().trim().split('$'); const verification = this.verifyConnection(args[1], args[0]); if (!verification) { socket.write('UNAUTHORIZED TO EXECUTE ON THIS SERVER\n'); return socket.destroy(); } - const parsed: { Username: string, Type: string, Message?: string, HMAC: string } = JSON.parse(args[1]); + const parsed: { Username: string, Type: string, Message?: string, HMAC: string } = JSON.parse(args[0]); // FINISH VERIFICATION CHECKS switch (parsed.Type) { case 'lock': @@ -63,7 +62,6 @@ export default class CSCLI { const hmac = crypto.createHmac('sha256', this.#hmac); hmac.update(data); const computed = hmac.digest('hex'); - console.log(computed); if (computed === key) return true; return false; } -- 2.20.1 From 8c7bf288c49c0022211aa38acb3a38c5c7c238ba Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Sun, 17 May 2020 06:58:45 -0400 Subject: [PATCH 268/516] various additions --- src/cscli/main.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cscli/main.ts b/src/cscli/main.ts index 5de963c..e0d72ee 100644 --- a/src/cscli/main.ts +++ b/src/cscli/main.ts @@ -4,6 +4,7 @@ import net from 'net'; import crypto from 'crypto'; import { promises as fs } from 'fs'; import Client from '../Client'; +import { dataConversion } from '../functions'; export default class CSCLI { public client: Client; @@ -42,13 +43,12 @@ export default class CSCLI { await this.client.util.accounts.lock(parsed.Username, this.client.user.id, { reason: 'Failed to accept Terms of Service.' }); break; case 'ram': - const mem = Number(await this.client.util.exec(`memory ${parsed.Username}`)) * 1000; - const memoryConversion = mem / 1024 / 1024; + const memoryConversion = dataConversion(Number(await this.client.util.exec(`memory ${parsed.Username}`)) * 1000); socket.write(`${memoryConversion}\n`); socket.destroy(); break; case 'storage': - const res = await this.client.redis.get(`storage-${parsed.Username}`) ? Number(await this.client.redis.get(`storage-${parsed.Username}`)) : '0'; + const res = await this.client.redis.get(`storage-${parsed.Username}`) ? dataConversion(Number(await this.client.redis.get(`storage-${parsed.Username}`))) : 'N/A'; socket.write(`${res}\n`); socket.destroy(); break; -- 2.20.1 From 860effb91c5c6051a5257abac3cc36867b839942 Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Fri, 22 May 2020 21:56:21 -0400 Subject: [PATCH 269/516] func for sending messages to user terminals --- src/class/Util.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/class/Util.ts b/src/class/Util.ts index d4fece4..cff693d 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-await-in-loop */ /* eslint-disable no-param-reassign */ import { promisify, inspect } from 'util'; import childProcess from 'child_process'; @@ -7,6 +8,7 @@ import uuid from 'uuid/v4'; import moment from 'moment'; import fs from 'fs'; import { Client } from '..'; +import { getUserByUid } from '../functions'; import { AccountUtil, Command, RichEmbed } from '.'; import { ModerationInterface, AccountInterface, Account } from '../models'; @@ -52,6 +54,30 @@ export default class Util { }); } + public async sendMessageToUserTerminal(username: string, message: string): Promise { + const ptsArray = await this.getPTS(username); + if (!ptsArray) return false; + for (const pts of ptsArray) { + const msg = `==SYSTEM NOTIFICATION | CLOUD SERVICES MANAGEMENT DAEMON==\n${new Date().toLocaleString('en-us')}\n\n${message}\n`; + await this.exec(`echo "${msg}" >> /dev/pts/${pts}`); + } + return true; + } + + private async getPTS(username: string): Promise { + const dir = await fs.promises.readdir('/dev/pts'); + const returnArray: number[] = []; + for (const file of dir) { + const fileInformation = await fs.promises.stat(`/dev/pts/${file}`); + const user = await getUserByUid(this.client, fileInformation.uid); + if (user && user === username) { + returnArray.push(Number(file)); + } + } + if (returnArray.length > 1) return undefined; + return returnArray; + } + /** * Resolves a command -- 2.20.1 From 393832889d46223cbdc8b4b2802826f3339eae7a Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Fri, 22 May 2020 21:56:56 -0400 Subject: [PATCH 270/516] go bindings for username lookup by UID --- Makefile | 8 +++++++- src/functions/getUserByUid.ts | 7 +++++++ src/functions/index.ts | 1 + src/go/getUserByUid/getUserByUid.go | 21 +++++++++++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/functions/getUserByUid.ts create mode 100644 src/go/getUserByUid/getUserByUid.go diff --git a/Makefile b/Makefile index 5553d82..1179bf6 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,9 @@ check_certificate_files := $(wildcard src/go/checkCertificate/*.go) check_certificate_signatures_files := $(wildcard src/go/checkCertSignatures/*.go) storage_files := $(wildcard src/go/storage/*.go) +get_user_by_uid_files := $(wildcard src/go/getUserByUid/*.go) -all: check_certificate check_cert_signatures storage typescript +all: check_certificate check_cert_signatures storage getUserByUid typescript check_certificate: HOME=/root go build -ldflags="-s -w" -o dist/bin/checkCertificate ${check_certificate_files} @@ -21,5 +22,10 @@ storage: @chmod 740 dist/bin/storage file dist/bin/storage +getUserByUid: + HOME=/root go build -ldflags="-s -w" dist/bin/getUserByUid ${storage_files} + @chmod 740 dist/bin/getUserByUid + file dist/bin/getUserByUid + typescript: tsc -p ./tsconfig.json diff --git a/src/functions/getUserByUid.ts b/src/functions/getUserByUid.ts new file mode 100644 index 0000000..b56c148 --- /dev/null +++ b/src/functions/getUserByUid.ts @@ -0,0 +1,7 @@ +import { Client } from '..'; + +export default async function getUserByUid(client: Client, uid: number): Promise { + const res = await client.util.exec(`${__dirname}/../bin/getUserByUid ${uid}`); + if (res === '-1') return null; + return res.trim(); +} diff --git a/src/functions/index.ts b/src/functions/index.ts index b933c35..6abf234 100644 --- a/src/functions/index.ts +++ b/src/functions/index.ts @@ -1,5 +1,6 @@ export { default as checkLock, clear as clearLock } from '../intervals/checkLock'; export { default as dataConversion } from './dataConversion'; export { default as existingLimitsSetup } from './existingLimitsSetup'; +export { default as getUserByUid } from './getUserByUid'; // export { default as checkSS, clear as clearSS } from './checkSS'; export { default as parseCertificate, Certificate } from './parseCertificate'; diff --git a/src/go/getUserByUid/getUserByUid.go b/src/go/getUserByUid/getUserByUid.go new file mode 100644 index 0000000..1a64881 --- /dev/null +++ b/src/go/getUserByUid/getUserByUid.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + "os" + "os/user" +) + +func main() { + if len(os.Args) > 1 { + fmt.Println("-1") + os.Exit(0) + } + userInfo, err := user.LookupId(os.Args[1]) + if err != nil { + fmt.Println("-1") + os.Exit(0) + } + fmt.Printf("%s", userInfo.Username) + os.Exit(0) +} -- 2.20.1 From 5a362a474df252153fe3502b578c7f77603c7cb4 Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Fri, 22 May 2020 21:59:33 -0400 Subject: [PATCH 271/516] go bindings for username lookup by UID --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1179bf6..2af0660 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ storage: file dist/bin/storage getUserByUid: - HOME=/root go build -ldflags="-s -w" dist/bin/getUserByUid ${storage_files} + HOME=/root go build -ldflags="-s -w" dist/bin/getUserByUid ${get_user_by_uid_files} @chmod 740 dist/bin/getUserByUid file dist/bin/getUserByUid -- 2.20.1 From d68ea27fac9f6e7c8b455d1a7fd2afe51429b301 Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Fri, 22 May 2020 22:01:01 -0400 Subject: [PATCH 272/516] go bindings for username lookup by UID --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2af0660..6bd5ba5 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ storage: file dist/bin/storage getUserByUid: - HOME=/root go build -ldflags="-s -w" dist/bin/getUserByUid ${get_user_by_uid_files} + HOME=/root go build -ldflags="-s -w" -o dist/bin/getUserByUid ${get_user_by_uid_files} @chmod 740 dist/bin/getUserByUid file dist/bin/getUserByUid -- 2.20.1 From 8aebf2b291e9a5e033deafd972c09d1112b4ebf6 Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Fri, 22 May 2020 22:07:17 -0400 Subject: [PATCH 273/516] go bindings for username lookup by UID --- src/class/Util.ts | 2 +- src/go/getUserByUid/getUserByUid.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index cff693d..5f67163 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -74,7 +74,7 @@ export default class Util { returnArray.push(Number(file)); } } - if (returnArray.length > 1) return undefined; + if (returnArray.length < 1) return undefined; return returnArray; } diff --git a/src/go/getUserByUid/getUserByUid.go b/src/go/getUserByUid/getUserByUid.go index 1a64881..8d3b22d 100644 --- a/src/go/getUserByUid/getUserByUid.go +++ b/src/go/getUserByUid/getUserByUid.go @@ -7,7 +7,7 @@ import ( ) func main() { - if len(os.Args) > 1 { + if len(os.Args) < 1 { fmt.Println("-1") os.Exit(0) } -- 2.20.1 From e1a7155cf55bd42f8d770bc54f11ef506da39670 Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Fri, 22 May 2020 22:10:45 -0400 Subject: [PATCH 274/516] go bindings for username lookup by UID --- src/class/Util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index 5f67163..db66f7d 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -58,7 +58,7 @@ export default class Util { const ptsArray = await this.getPTS(username); if (!ptsArray) return false; for (const pts of ptsArray) { - const msg = `==SYSTEM NOTIFICATION | CLOUD SERVICES MANAGEMENT DAEMON==\n${new Date().toLocaleString('en-us')}\n\n${message}\n`; + const msg = `\n==SYSTEM NOTIFICATION | CLOUD SERVICES MANAGEMENT DAEMON==\n${new Date().toLocaleString('en-us')}\n\n${message}\n`; await this.exec(`echo "${msg}" >> /dev/pts/${pts}`); } return true; -- 2.20.1 From 9092dfcae95dbfe4a4a40ab58ec3df96cca22348 Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Fri, 22 May 2020 22:19:38 -0400 Subject: [PATCH 275/516] send msgs to terminals on certain actions --- src/commands/lock.ts | 1 + src/commands/notify.ts | 1 + src/commands/tier.ts | 1 + src/commands/warn.ts | 1 + src/intervals/memory.ts | 2 ++ 5 files changed, 6 insertions(+) diff --git a/src/commands/lock.ts b/src/commands/lock.ts index 17e3740..d3df486 100644 --- a/src/commands/lock.ts +++ b/src/commands/lock.ts @@ -20,6 +20,7 @@ export default class Lock extends Command { if (account.locked) return message.channel.createMessage(`***${this.client.stores.emojis.error} This account is already locked.***`); const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Locking account...***`); if (account.username === 'matthew' || account.root) return edit.edit(`***${this.client.stores.emojis.error} Permission denied.***`); + await this.client.util.sendMessageToUserTerminal(account.username, 'ACCOUNT LOCKED BY TECHNICIAN | PREPARING TO LOGOUT').catch(() => { }); await this.client.util.exec(`lock ${account.username}`); await account.updateOne({ locked: true }); diff --git a/src/commands/notify.ts b/src/commands/notify.ts index fcb57df..2a365e3 100644 --- a/src/commands/notify.ts +++ b/src/commands/notify.ts @@ -42,6 +42,7 @@ export default class Notify extends Command { `, }); message.delete(); + await this.client.util.sendMessageToUserTerminal(account.username, `NOTIFICATION FROM TECHNICIAN: ${args.slice(1).join(' ')}`).catch(() => { }); return edit.edit(`***${this.client.stores.emojis.success} Send notification to ${account.username}.***`); } catch (error) { return this.client.util.handleError(error, message, this); diff --git a/src/commands/tier.ts b/src/commands/tier.ts index ec625cf..41376ae 100644 --- a/src/commands/tier.ts +++ b/src/commands/tier.ts @@ -37,6 +37,7 @@ export default class Tier extends Command { embed.addField('Old Tier -> New Tier', `${account.tier} -> ${args[1]}`, true); embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setTimestamp(); + await this.client.util.sendMessageToUserTerminal(account.username, `A technician has upgraded your tier to ${args[1]}`).catch(() => { }); this.client.createMessage('580950455581147146', { embed }); return this.client.getDMChannel(account.userID).then((channel) => channel.createMessage({ embed })).catch(); } catch (error) { return this.client.util.handleError(error, message, this); diff --git a/src/commands/warn.ts b/src/commands/warn.ts index 1c42332..3e2c9b4 100644 --- a/src/commands/warn.ts +++ b/src/commands/warn.ts @@ -22,6 +22,7 @@ export default class Warn extends Command { await this.client.util.createModerationLog(account.userID, message.member, 1, args.slice(1).join(' ')); message.delete(); 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(() => { }); return this.client.util.transport.sendMail({ to: account.emailAddress, from: 'Library of Code sp-us | Cloud Services ', diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index 307d0fe..eea94ed 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -31,6 +31,7 @@ export default function memory(client: Client) { */ if ((memoryConversion >= userLimits.hard) && set.has(acc.username)) { 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'); client.util.exec(`killall -9 -u ${acc.username}`); const embed = new RichEmbed(); embed.setTitle('Resource Enforcement Notification'); @@ -83,6 +84,7 @@ export default function memory(client: Client) { client.getDMChannel(acc.userID).then((channel) => { channel.createMessage({ embed: 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(() => { }); client.util.transport.sendMail({ to: acc.emailAddress, from: 'Library of Code sp-us | Cloud Services ', -- 2.20.1 From a979f73890a1d0cfe4cc688d33191ed60b0f2a4e Mon Sep 17 00:00:00 2001 From: Matthew Ray Date: Fri, 22 May 2020 22:24:51 -0400 Subject: [PATCH 276/516] send msgs to terminals on certain actions --- src/commands/tier.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/tier.ts b/src/commands/tier.ts index 41376ae..6c14d6d 100644 --- a/src/commands/tier.ts +++ b/src/commands/tier.ts @@ -37,7 +37,7 @@ export default class Tier extends Command { embed.addField('Old Tier -> New Tier', `${account.tier} -> ${args[1]}`, true); embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setTimestamp(); - await this.client.util.sendMessageToUserTerminal(account.username, `A technician has upgraded 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(); } catch (error) { return this.client.util.handleError(error, message, this); -- 2.20.1 From d534ea163d71312ae8ac63055a9b02e39e5acf03 Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 9 Jun 2020 12:40:02 +0100 Subject: [PATCH 277/516] Clean up --- src/commands/lock.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/commands/lock.ts b/src/commands/lock.ts index d3df486..7769fab 100644 --- a/src/commands/lock.ts +++ b/src/commands/lock.ts @@ -25,10 +25,8 @@ export default class Lock extends Command { await account.updateOne({ locked: true }); const expiry = new Date(); - const lockLength = args[1].match(/[a-z]+|[^a-z]+/gi); - const length = Number(lockLength[0]); - const unit = lockLength[1] as unitOfTime.Base; - const momentMilliseconds = moment.duration(length, unit).asMilliseconds(); + const [length, unit] = args[1].match(/[a-z]+|[^a-z]+/gi); + const momentMilliseconds = moment.duration(Number(length), unit as unitOfTime.Base).asMilliseconds(); const reason = momentMilliseconds ? args.slice(2).join(' ') : args.slice(1).join(' '); await this.client.util.createModerationLog(account.userID, message.member, 2, reason, momentMilliseconds); -- 2.20.1 From 52351fd8e41b4f5b246ca4d1d848fd29791ddb91 Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 9 Jun 2020 12:56:14 +0100 Subject: [PATCH 278/516] Definitions inside methods --- src/models/Account.ts | 2 +- src/models/Domain.ts | 48 ++++++++++++------------- src/models/Moderation.ts | 76 ++++++++++++++++++++-------------------- src/models/Tier.ts | 2 +- 4 files changed, 64 insertions(+), 64 deletions(-) diff --git a/src/models/Account.ts b/src/models/Account.ts index 1af607d..11c18da 100644 --- a/src/models/Account.ts +++ b/src/models/Account.ts @@ -22,7 +22,7 @@ export interface AccountInterface extends Document { authTag: Buffer } -const Account: Schema = new Schema({ +const Account = new Schema({ username: String, userID: String, homepath: String, diff --git a/src/models/Domain.ts b/src/models/Domain.ts index ee8ade0..de6add9 100644 --- a/src/models/Domain.ts +++ b/src/models/Domain.ts @@ -1,24 +1,24 @@ -import { Document, Schema, model } from 'mongoose'; -import { AccountInterface } from './Account'; - -export interface DomainInterface extends Document { - account: AccountInterface, - domain: string, - port: number, - // Below is the full absolute path to the location of the x509 certificate and key files. - x509: { - cert: string, - key: string - }, - enabled: true -} - -const Domain: Schema = new Schema({ - account: Object, - domain: String, - port: Number, - x509: { cert: String, key: String }, - enabled: Boolean, -}); - -export default model('Domain', Domain); +import { Document, Schema, model } from 'mongoose'; +import { AccountInterface } from './Account'; + +export interface DomainInterface extends Document { + account: AccountInterface, + domain: string, + port: number, + // Below is the full absolute path to the location of the x509 certificate and key files. + x509: { + cert: string, + key: string + }, + enabled: true +} + +const Domain = new Schema({ + account: Object, + domain: String, + port: Number, + x509: { cert: String, key: String }, + enabled: Boolean, +}); + +export default model('Domain', Domain); diff --git a/src/models/Moderation.ts b/src/models/Moderation.ts index d289dbf..43d5a3c 100644 --- a/src/models/Moderation.ts +++ b/src/models/Moderation.ts @@ -1,38 +1,38 @@ -import { Document, Schema, model } from 'mongoose'; - -export interface ModerationInterface extends Document { - username: string, - userID: string, - logID: string, - moderatorID: string, - reason: string, - /** - * @field 0 - Create - * @field 1 - Warn - * @field 2 - Lock - * @field 3 - Unlock - * @field 4 - Delete - */ - type: 0 | 1 | 2 | 3 | 4 - date: Date, - expiration: { - date: Date, - processed: boolean - } -} - -const Moderation: Schema = new Schema({ - username: String, - userID: String, - logID: String, - moderatorID: String, - reason: String, - type: Number, - date: Date, - expiration: { - date: Date, - processed: Boolean, - }, -}); - -export default model('Moderation', Moderation); +import { Document, Schema, model } from 'mongoose'; + +export interface ModerationInterface extends Document { + username: string, + userID: string, + logID: string, + moderatorID: string, + reason: string, + /** + * @field 0 - Create + * @field 1 - Warn + * @field 2 - Lock + * @field 3 - Unlock + * @field 4 - Delete + */ + type: 0 | 1 | 2 | 3 | 4 + date: Date, + expiration: { + date: Date, + processed: boolean + } +} + +const Moderation = new Schema({ + username: String, + userID: String, + logID: String, + moderatorID: String, + reason: String, + type: Number, + date: Date, + expiration: { + date: Date, + processed: Boolean, + }, +}); + +export default model('Moderation', Moderation); diff --git a/src/models/Tier.ts b/src/models/Tier.ts index 7542a50..4bf81ed 100644 --- a/src/models/Tier.ts +++ b/src/models/Tier.ts @@ -12,7 +12,7 @@ export interface TierInterface extends Tiers, Document { id: number; } -const Tier: Schema = new Schema({ +const Tier = new Schema({ id: Number, resourceLimits: { ram: Number, -- 2.20.1 From 6f517720336a19a51600e348ca98f98832b6c922 Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 9 Jun 2020 22:26:13 +0100 Subject: [PATCH 279/516] Refurbish whois command --- package.json | 2 +- src/commands/index.ts | 1 + src/commands/whois.ts | 183 +++++++++++++++++++++++-------------- src/commands/whois_user.ts | 60 ------------ yarn.lock | 7 +- 5 files changed, 118 insertions(+), 135 deletions(-) delete mode 100644 src/commands/whois_user.ts diff --git a/package.json b/package.json index bad78bc..7dc02f8 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "@ghaiklor/x509": "^1.0.0", "axios": "^0.19.0", "body-parser": "^1.19.0", - "eris": "^0.11.2", + "eris": "bsian03/eris#dev", "eris-pagination": "git+https://github.com/bsian03/eris-pagination#a10c026e9ce0b9a99799294b7b2a64d5268be56e", "express": "^4.17.1", "fs-extra": "^8.1.0", diff --git a/src/commands/index.ts b/src/commands/index.ts index be52d7c..13ec317 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -28,3 +28,4 @@ export { default as unban } from './unban'; export { default as unlock } from './unlock'; export { default as warn } from './warn'; export { default as whois } from './whois'; +export { default as whoisold } from './whoisold'; diff --git a/src/commands/whois.ts b/src/commands/whois.ts index 5afa012..cf7dc46 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -1,70 +1,113 @@ -import moment from 'moment'; -import { Message } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; -import { dataConversion } from '../functions'; -import User from './whois_user'; - -export default class Whois extends Command { - constructor(client: Client) { - super(client); - this.name = 'whois'; - this.description = 'Views information for a cloud account.'; - this.aliases = ['account', 'user']; - this.usage = `${this.client.config.prefix}account [User Name | User ID | Email Address]`; - this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; - this.subcmds = [User]; - this.enabled = true; - } - - public async run(message: Message, args: string[]) { - try { - if (!args[0]) 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] }, { supportKey: args[0].toUpperCase() }] }); - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found.***`); - const embed = new RichEmbed(); - embed.setTitle('Account Information'); - if (this.client.users.get(account.userID)) embed.setThumbnail(this.client.users.get(account.userID).avatarURL); - embed.setColor(0x36393f); - let fingerInformation = await this.client.util.exec(`finger ${account.username}`); - if (message.member && !message.member.roles.includes('662163685439045632')) { - fingerInformation = fingerInformation.replace(/((^\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, '[MASKED IP ADDRESS]'); - } - embed.setDescription(`${fingerInformation}\n${await this.client.util.exec(`chage -l ${account.username}`)}`); - embed.addField('Username', `${account.username} | <@${account.userID}>`, true); - embed.addField('ID', account.userID, true); - embed.addField('Email Address', account.emailAddress, true); - embed.addField('Tier', String(account.tier), true); - embed.addField('Support Key', account.supportKey, true); - embed.addField('Created By', `<@${this.client.users.get(account.createdBy).id}>`, true); - embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); - const cpuUsage = await this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`); - embed.addField('CPU Usage', cpuUsage.split('\n')[0] ? `${cpuUsage.split('\n')[0]}%` : '0%', true); - embed.addField('Memory', dataConversion(Number(await this.client.util.exec(`memory ${account.username}`)) * 1000), true); - const data = await this.client.redis.get(`storage-${account.username}`) ? dataConversion(Number(await this.client.redis.get(`storage-${account.username}`))) : 'N/A'; - embed.addField('Storage', data, true); - let details = ''; - if (account.locked) details += '__This account is currently locked.__\n'; - if (account.permissions.director) { - details += 'This account belongs to a Director.\n'; - const roleColor = this.client.guilds.get('446067825673633794').roles.get('662163685439045632').color; - embed.setColor(roleColor); - } else if (account.permissions.technician) { - details += 'This account belongs to a Technician.\n'; - const roleColor = this.client.guilds.get('446067825673633794').roles.get('701454780828221450').color; - embed.setColor(roleColor); - } else if (account.permissions.staff) { - details += 'This account belongs to a Staff member.\n'; - const roleColor = this.client.guilds.get('446067825673633794').roles.get('453689940140883988').color; - embed.setColor(roleColor); - } else embed.setColor(0x36393f); - if (account.root) details += '**This account has root/administrative privileges.**\n'; - if (details) embed.addField('Additional Details', details, true); - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - embed.setTimestamp(); - return message.channel.createMessage({ embed }); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} +import moment from 'moment'; +import { Message, GuildTextableChannel, Member, Role } from 'eris'; +import { Client } from '..'; +import { Command, RichEmbed } from '../class'; +import { dataConversion } from '../functions'; +import { AccountInterface } from '../models'; + +export default class Whois extends Command { + constructor(client: Client) { + super(client); + this.name = 'whois'; + this.description = 'Gets information about an account.'; + this.usage = `${this.client.config.prefix}whois `; + this.aliases = ['account', 'user']; + this.enabled = true; + } + + 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 async run(message: Message, args: string[]) { + try { + let full = false; + let account: AccountInterface; + if (args[1] === '--full' && !this.fullRoles.some((r) => message.member.roles.includes(r))) full = true; + + 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() }] }); + else account = await this.client.db.Account.findOne({ $or: [{ username: user }, { userID: user }] }); + if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} Account not found.***`); + + const thumbnail = this.client.users.get(account.userID)?.avatarURL || message.channel.guild.iconURL; + + const embed = new RichEmbed(); + embed.setTitle('Account Information'); + embed.setThumbnail(thumbnail); + if (full) this.full(account, embed, message.member); + else this.default(account, embed); + + let details = ''; + let role: Role; + if (account.locked) details += '__This account is currently locked.__\n'; + switch (true) { + case account.permissions.director: + details += 'This account belongs to a Director.\n'; + role = message.member.guild.roles.get('662163685439045632'); + break; + case account.permissions.technician: + details += 'This account belongs to a Technician.\n'; + role = message.member.guild.roles.get('701454780828221450'); + break; + case account.permissions.staff: + details += 'This account belongs to a Staff member.\n'; + role = message.member.guild.roles.get('453689940140883988'); + break; + default: + role = message.member.guild.roles.get(message.member.guild.id); + break; + } + if (account.root) details += '**This account has root/administrative privileges.**\n'; + embed.setColor(role.color || 0x36393f); + if (details) embed.addField('Additional Details', details, true); + + embed.setTimestamp(); + return message.channel.createMessage({ embed }); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } + + public async full(account: AccountInterface, embed: RichEmbed, member: Member) { + 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.redis.get(`storage-${account.username}`), + this.client.util.exec(`finger ${account.username}`), + this.client.util.exec(`chage -l ${account.username}`), + this.client.util.exec(`memory ${account.username}`), + ]); + const finger = !member.roles.includes('662163685439045632') ? fingerInformation.replace(this.IP_REGEX, '[MASKED IP ADDRRESS]') : fingerInformation; + + embed.setDescription(`${finger}\n${chage}`); + embed.addField('Username', `${account.username} | <@${account.userID}>`, true); + embed.addField('ID', account.userID, true); + embed.addField('Email Address', account.emailAddress, true); + embed.addField('Tier', String(account.tier), true); + embed.addField('Support Key', account.supportKey, true); + embed.addField('Created By', `<@${this.client.users.get(account.createdBy).id}>`, 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('Memory', dataConversion(Number(memory) * 1000), true); + embed.addField('Storage', data ? dataConversion(Number(data)) : 'N/A', true); + } + + public async default(account: AccountInterface, embed: RichEmbed) { + 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.redis.get(`storage-${account.username}`), + this.client.util.exec(`memory ${account.username}`), + ]); + + embed.addField('Username', `${account.username} | <@${account.userID}>`, true); + embed.addField('ID', account.userID, true); + embed.addField('Tier', String(account.tier), true); + embed.addField('Created By', `<@${this.client.users.get(account.createdBy).id}>`, 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('Memory', dataConversion(Number(memory) * 1000), true); + embed.addField('Storage', data ? dataConversion(Number(data)) : 'N/A', true); + } +} + +// Whois user only includes username, id, tier, created by, created at, cpu usage, memory, storage and additional details diff --git a/src/commands/whois_user.ts b/src/commands/whois_user.ts deleted file mode 100644 index b42b5fb..0000000 --- a/src/commands/whois_user.ts +++ /dev/null @@ -1,60 +0,0 @@ -import moment from 'moment'; -import { Message } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; -import { dataConversion } from '../functions'; -import { AccountInterface } from '../models'; - -export default class Whois_User extends Command { - constructor(client: Client) { - super(client); - this.name = 'user'; - this.description = 'Gets information about your account.'; - this.usage = `${this.client.config.prefix}whois user `; - this.enabled = true; - } - - public async run(message: Message, args: string[]) { - try { - let account: AccountInterface; - if (!args[0]) account = await this.client.db.Account.findOne({ userID: message.author.id }); - else account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }] }); - if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} You don't have an account.***`); - const embed = new RichEmbed(); - embed.setTitle('Account Information'); - if (this.client.users.get(account.userID)) embed.setThumbnail(this.client.users.get(account.userID).avatarURL); - embed.addField('Username', `${account.username} | <@${account.userID}>`, true); - embed.addField('ID', account.userID, true); - embed.addField('Tier', String(account.tier), true); - embed.addField('Created By', `<@${this.client.users.get(account.createdBy).id}>`, true); - embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); - const cpuUsage = await this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`); - embed.addField('CPU Usage', cpuUsage.split('\n')[0] ? `${cpuUsage.split('\n')[0]}%` : '0%', true); - embed.addField('Memory', dataConversion(Number(await this.client.util.exec(`memory ${account.username}`)) * 1000), true); - const data = await this.client.redis.get(`storage-${account.username}`) ? dataConversion(Number(await this.client.redis.get(`storage-${account.username}`))) : 'N/A'; - embed.addField('Storage', data, true); - let details = ''; - if (account.locked) details += '__This account is currently locked.__\n'; - if (account.permissions.director) { - details += 'This account belongs to a Director.\n'; - const roleColor = this.client.guilds.get('446067825673633794').roles.get('662163685439045632').color; - embed.setColor(roleColor); - } else if (account.permissions.technician) { - details += 'This account belongs to a Technician.\n'; - const roleColor = this.client.guilds.get('446067825673633794').roles.get('701454780828221450').color; - embed.setColor(roleColor); - } else if (account.permissions.staff) { - details += 'This account belongs to a Staff member.\n'; - const roleColor = this.client.guilds.get('446067825673633794').roles.get('453689940140883988').color; - embed.setColor(roleColor); - } else embed.setColor(0x36393f); - if (account.root) details += '**This account has root/administrative privileges.**\n'; - if (details) embed.addField('Additional Details', details, true); - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - embed.setTimestamp(); - return message.channel.createMessage({ embed }); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} diff --git a/yarn.lock b/yarn.lock index 13879cf..ac88e96 100644 --- a/yarn.lock +++ b/yarn.lock @@ -616,10 +616,9 @@ eris-reactions@^0.1.2: resolved "https://registry.yarnpkg.com/eris-reactions/-/eris-reactions-0.1.2.tgz#2d4edbf5f80dc964f0bb42fd301d3d8a141a5aa1" integrity sha512-p497xAdNsw3RRfAoklYemWRk1HT22rBmRaiemG6TVZ1yPTuQf41r4GteyKOJZ3hkphD3Rte7/1GiZwPzUNOHcw== -eris@^0.11.2: - version "0.11.2" - resolved "https://registry.yarnpkg.com/eris/-/eris-0.11.2.tgz#a4adad72d795d64d71a74833ccf5adc4db0ad8c0" - integrity sha512-OhccRcxrPiNUylTamrjIbZM6itKMLjNrwLIXGvNwQZj4CRVOOz9eUVIqOJULB713x1ezw7HoC8AEsnsMNUneDA== +eris@bsian03/eris#dev: + version "0.13.1" + resolved "https://codeload.github.com/bsian03/eris/tar.gz/3607027f1ea64b81b302006f564ff69679b800d1" dependencies: ws "^7.2.1" optionalDependencies: -- 2.20.1 From 362c5680400920898bc0118b8059634250f03baa Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 9 Jun 2020 22:26:59 +0100 Subject: [PATCH 280/516] Add deprecated commands --- src/commands/whoisold.ts | 71 +++++++++++++++++++++++++++++++++++ src/commands/whoisold_user.ts | 61 ++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 src/commands/whoisold.ts create mode 100644 src/commands/whoisold_user.ts diff --git a/src/commands/whoisold.ts b/src/commands/whoisold.ts new file mode 100644 index 0000000..f9dfe8e --- /dev/null +++ b/src/commands/whoisold.ts @@ -0,0 +1,71 @@ +import moment from 'moment'; +import { Message } from 'eris'; +import { Client } from '..'; +import { Command, RichEmbed } from '../class'; +import { dataConversion } from '../functions'; +import User from './whoisold_user'; + +export default class WhoisOld extends Command { + constructor(client: Client) { + super(client); + this.name = 'whoisold'; + this.description = 'Views information for a cloud account.'; + this.aliases = ['accountold', 'userold']; + this.usage = `${this.client.config.prefix}accountold [User Name | User ID | Email Address]`; + this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; + this.subcmds = [User]; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + message.channel.createMessage('This command is being deprecated. Please use `=whois` instead.'); + if (!args[0]) 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] }, { supportKey: args[0].toUpperCase() }] }); + if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found.***`); + const embed = new RichEmbed(); + embed.setTitle('Account Information'); + if (this.client.users.get(account.userID)) embed.setThumbnail(this.client.users.get(account.userID).avatarURL); + embed.setColor(0x36393f); + let fingerInformation = await this.client.util.exec(`finger ${account.username}`); + if (message.member && !message.member.roles.includes('662163685439045632')) { + fingerInformation = fingerInformation.replace(/((^\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, '[MASKED IP ADDRESS]'); + } + embed.setDescription(`${fingerInformation}\n${await this.client.util.exec(`chage -l ${account.username}`)}`); + embed.addField('Username', `${account.username} | <@${account.userID}>`, true); + embed.addField('ID', account.userID, true); + embed.addField('Email Address', account.emailAddress, true); + embed.addField('Tier', String(account.tier), true); + embed.addField('Support Key', account.supportKey, true); + embed.addField('Created By', `<@${this.client.users.get(account.createdBy).id}>`, true); + embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); + const cpuUsage = await this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`); + embed.addField('CPU Usage', cpuUsage.split('\n')[0] ? `${cpuUsage.split('\n')[0]}%` : '0%', true); + embed.addField('Memory', dataConversion(Number(await this.client.util.exec(`memory ${account.username}`)) * 1000), true); + const data = await this.client.redis.get(`storage-${account.username}`) ? dataConversion(Number(await this.client.redis.get(`storage-${account.username}`))) : 'N/A'; + embed.addField('Storage', data, true); + let details = ''; + if (account.locked) details += '__This account is currently locked.__\n'; + if (account.permissions.director) { + details += 'This account belongs to a Director.\n'; + const roleColor = this.client.guilds.get('446067825673633794').roles.get('662163685439045632').color; + embed.setColor(roleColor); + } else if (account.permissions.technician) { + details += 'This account belongs to a Technician.\n'; + const roleColor = this.client.guilds.get('446067825673633794').roles.get('701454780828221450').color; + embed.setColor(roleColor); + } else if (account.permissions.staff) { + details += 'This account belongs to a Staff member.\n'; + const roleColor = this.client.guilds.get('446067825673633794').roles.get('453689940140883988').color; + embed.setColor(roleColor); + } else embed.setColor(0x36393f); + if (account.root) details += '**This account has root/administrative privileges.**\n'; + if (details) embed.addField('Additional Details', details, true); + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + embed.setTimestamp(); + return message.channel.createMessage({ embed }); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/whoisold_user.ts b/src/commands/whoisold_user.ts new file mode 100644 index 0000000..67dd7cb --- /dev/null +++ b/src/commands/whoisold_user.ts @@ -0,0 +1,61 @@ +import moment from 'moment'; +import { Message } from 'eris'; +import { Client } from '..'; +import { Command, RichEmbed } from '../class'; +import { dataConversion } from '../functions'; +import { AccountInterface } from '../models'; + +export default class WhoisOld_User extends Command { + constructor(client: Client) { + super(client); + this.name = 'user'; + this.description = 'Gets information about your account.'; + this.usage = `${this.client.config.prefix}whoisold user `; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + message.channel.createMessage('This command is being deprecated. Please use `=whois` instead.'); + let account: AccountInterface; + if (!args[0]) account = await this.client.db.Account.findOne({ userID: message.author.id }); + else account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }] }); + if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} You don't have an account.***`); + const embed = new RichEmbed(); + embed.setTitle('Account Information'); + if (this.client.users.get(account.userID)) embed.setThumbnail(this.client.users.get(account.userID).avatarURL); + embed.addField('Username', `${account.username} | <@${account.userID}>`, true); + embed.addField('ID', account.userID, true); + embed.addField('Tier', String(account.tier), true); + embed.addField('Created By', `<@${this.client.users.get(account.createdBy).id}>`, true); + embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); + const cpuUsage = await this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`); + embed.addField('CPU Usage', cpuUsage.split('\n')[0] ? `${cpuUsage.split('\n')[0]}%` : '0%', true); + embed.addField('Memory', dataConversion(Number(await this.client.util.exec(`memory ${account.username}`)) * 1000), true); + const data = await this.client.redis.get(`storage-${account.username}`) ? dataConversion(Number(await this.client.redis.get(`storage-${account.username}`))) : 'N/A'; + embed.addField('Storage', data, true); + let details = ''; + if (account.locked) details += '__This account is currently locked.__\n'; + if (account.permissions.director) { + details += 'This account belongs to a Director.\n'; + const roleColor = this.client.guilds.get('446067825673633794').roles.get('662163685439045632').color; + embed.setColor(roleColor); + } else if (account.permissions.technician) { + details += 'This account belongs to a Technician.\n'; + const roleColor = this.client.guilds.get('446067825673633794').roles.get('701454780828221450').color; + embed.setColor(roleColor); + } else if (account.permissions.staff) { + details += 'This account belongs to a Staff member.\n'; + const roleColor = this.client.guilds.get('446067825673633794').roles.get('453689940140883988').color; + embed.setColor(roleColor); + } else embed.setColor(0x36393f); + if (account.root) details += '**This account has root/administrative privileges.**\n'; + if (details) embed.addField('Additional Details', details, true); + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + embed.setTimestamp(); + return message.channel.createMessage({ embed }); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} -- 2.20.1 From 0d9d8a704739315e1ecfffc6a69e2088f1a122aa Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 9 Jun 2020 22:41:01 +0100 Subject: [PATCH 281/516] Update eris pagination --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 7dc02f8..1dd0f55 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "axios": "^0.19.0", "body-parser": "^1.19.0", "eris": "bsian03/eris#dev", - "eris-pagination": "git+https://github.com/bsian03/eris-pagination#a10c026e9ce0b9a99799294b7b2a64d5268be56e", + "eris-pagination": "git+https://github.com/bsian03/eris-pagination#c0f77b118e98309e89e6522ef545f9d121601f21", "express": "^4.17.1", "fs-extra": "^8.1.0", "helmet": "^3.21.2", diff --git a/yarn.lock b/yarn.lock index ac88e96..cc234d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -605,9 +605,9 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= -"eris-pagination@git+https://github.com/bsian03/eris-pagination#a10c026e9ce0b9a99799294b7b2a64d5268be56e": - version "0.4.0" - resolved "git+https://github.com/bsian03/eris-pagination#a10c026e9ce0b9a99799294b7b2a64d5268be56e" +"eris-pagination@git+https://github.com/bsian03/eris-pagination#c0f77b118e98309e89e6522ef545f9d121601f21": + version "0.5.0" + resolved "git+https://github.com/bsian03/eris-pagination#c0f77b118e98309e89e6522ef545f9d121601f21" dependencies: eris-reactions "^0.1.2" -- 2.20.1 From 15d703fd826bc5e31a55b9f5a4db8e0fb197d3d9 Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 9 Jun 2020 22:48:43 +0100 Subject: [PATCH 282/516] Fix lockfile yarn install filter --- src/commands/pull.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/commands/pull.ts b/src/commands/pull.ts index 9a4c8f5..a0991b1 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -56,14 +56,9 @@ export default class Pull extends Command { if (install.includes('Already up-to-date')) { const updatedMessage = passedPull.content.replace(`${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`, `${this.client.stores.emojis.success} ***No dependency updates available***\n${this.client.stores.emojis.loading} ***Rebuilding files...***`); updatedPackages = await updateMessage.edit(updatedMessage); - } else if (install.includes('success Saved lockfile.')) { + } else { const updatedMessage = passedPull.content.replace(`${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`, `${this.client.stores.emojis.success} ***Updated dependencies***\n${this.client.stores.emojis.loading} ***Rebuilding files...***`); updatedPackages = await updateMessage.edit(updatedMessage); - } else { - const updatedMessage = passedPull.content.replace(`${this.client.stores.emojis.loading} ***Reinstalling dependencies...***`, `${this.client.stores.emojis.error} ***Unexpected yarn install output***\n` - + `\`\`\`\n${install}\n\`\`\``); - this.client.updating = false; - return updateMessage.edit(updatedMessage); } let build: string; -- 2.20.1 From b315d471a780d874be14a2bd9cdd6969619bc473 Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 9 Jun 2020 22:55:54 +0100 Subject: [PATCH 283/516] Fix loading information --- src/commands/whois.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/whois.ts b/src/commands/whois.ts index cf7dc46..9b364c6 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -35,8 +35,8 @@ export default class Whois extends Command { const embed = new RichEmbed(); embed.setTitle('Account Information'); embed.setThumbnail(thumbnail); - if (full) this.full(account, embed, message.member); - else this.default(account, embed); + if (full) await this.full(account, embed, message.member); + else await this.default(account, embed); let details = ''; let role: Role; -- 2.20.1 From 0f93d42c2c02cc4065d15362f198b1865f72c745 Mon Sep 17 00:00:00 2001 From: Bsian Date: Tue, 9 Jun 2020 23:01:50 +0100 Subject: [PATCH 284/516] Fix full flag --- src/commands/whois.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/whois.ts b/src/commands/whois.ts index 9b364c6..4a589a6 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -23,7 +23,7 @@ export default class Whois extends Command { try { let full = false; let account: AccountInterface; - if (args[1] === '--full' && !this.fullRoles.some((r) => message.member.roles.includes(r))) full = true; + if (args[1] === '--full' && this.fullRoles.some((r) => message.member.roles.includes(r))) full = true; 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() }] }); -- 2.20.1 From 2019a9e686226146f91ca6d514559fd6f910c016 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 15 Jun 2020 22:32:32 +0100 Subject: [PATCH 285/516] Check eval string --- src/commands/eval.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index 0f3bf3e..bf6caaf 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -33,6 +33,7 @@ export default class Eval extends Command { const index = evalMessage.findIndex((v) => v === '-a') + 1; evalString = `(async () => { ${evalMessage.slice(index).join(' ').trim()} })()`; } + message.channel.createMessage(evalString); try { evaled = await eval(evalString); -- 2.20.1 From 765cf135a2e29bca9605b5c7b57154a4141b45ff Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 15 Jun 2020 22:36:23 +0100 Subject: [PATCH 286/516] same as before --- src/commands/eval.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index bf6caaf..c5219fc 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -29,6 +29,7 @@ export default class Eval extends Command { const index = evalMessage.findIndex((v) => v.startsWith('-d')) + 1; evalString = evalMessage.slice(index).join(' ').trim(); } + message.channel.createMessage(evalString); if (args[0] === '-a') { const index = evalMessage.findIndex((v) => v === '-a') + 1; evalString = `(async () => { ${evalMessage.slice(index).join(' ').trim()} })()`; -- 2.20.1 From f5f04c5a0c71d36f872e8948cbdd516cd6080986 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 15 Jun 2020 22:47:31 +0100 Subject: [PATCH 287/516] as above --- src/commands/eval.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index c5219fc..d3b487d 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -27,11 +27,13 @@ export default class Eval extends Command { depth = Number(args[0].replace('-d', '')); if (!depth || depth < 0) depth = 0; const index = evalMessage.findIndex((v) => v.startsWith('-d')) + 1; + message.channel.createMessage(evalMessage.slice(index).join(' ').trim()); evalString = evalMessage.slice(index).join(' ').trim(); } message.channel.createMessage(evalString); if (args[0] === '-a') { const index = evalMessage.findIndex((v) => v === '-a') + 1; + message.channel.createMessage(evalMessage.slice(index).join(' ').trim()); evalString = `(async () => { ${evalMessage.slice(index).join(' ').trim()} })()`; } message.channel.createMessage(evalString); -- 2.20.1 From 06a0906ca9ed949fd7a95f26c4b64f67d821208b Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 15 Jun 2020 22:50:34 +0100 Subject: [PATCH 288/516] ugh --- src/commands/eval.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index d3b487d..e0d44e3 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -27,16 +27,16 @@ export default class Eval extends Command { depth = Number(args[0].replace('-d', '')); if (!depth || depth < 0) depth = 0; const index = evalMessage.findIndex((v) => v.startsWith('-d')) + 1; - message.channel.createMessage(evalMessage.slice(index).join(' ').trim()); + await message.channel.createMessage(evalMessage.slice(index).join(' ').trim()); evalString = evalMessage.slice(index).join(' ').trim(); } - message.channel.createMessage(evalString); + await message.channel.createMessage(evalString); if (args[0] === '-a') { const index = evalMessage.findIndex((v) => v === '-a') + 1; - message.channel.createMessage(evalMessage.slice(index).join(' ').trim()); + await message.channel.createMessage(evalMessage.slice(index).join(' ').trim()); evalString = `(async () => { ${evalMessage.slice(index).join(' ').trim()} })()`; } - message.channel.createMessage(evalString); + await message.channel.createMessage(evalString); try { evaled = await eval(evalString); -- 2.20.1 From 96b3e55dd134ae816436e57af0738e5469641d71 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 15 Jun 2020 22:57:12 +0100 Subject: [PATCH 289/516] aaaa --- src/commands/eval.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index e0d44e3..e209fe4 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -27,16 +27,16 @@ export default class Eval extends Command { depth = Number(args[0].replace('-d', '')); if (!depth || depth < 0) depth = 0; const index = evalMessage.findIndex((v) => v.startsWith('-d')) + 1; - await message.channel.createMessage(evalMessage.slice(index).join(' ').trim()); - evalString = evalMessage.slice(index).join(' ').trim(); + await message.channel.createMessage(`depth: ${evalMessage.slice(index).join(' ').trim()}`); + evalString = `eval after depth: ${evalMessage.slice(index).join(' ').trim()}`; } await message.channel.createMessage(evalString); if (args[0] === '-a') { const index = evalMessage.findIndex((v) => v === '-a') + 1; - await message.channel.createMessage(evalMessage.slice(index).join(' ').trim()); + await message.channel.createMessage(`async: ${evalMessage.slice(index).join(' ').trim()}`); evalString = `(async () => { ${evalMessage.slice(index).join(' ').trim()} })()`; } - await message.channel.createMessage(evalString); + await message.channel.createMessage(`eval after async: ${evalString}`); try { evaled = await eval(evalString); -- 2.20.1 From 27cbb57ccfb3660903061b84e10a5ff0d8fc6b63 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 15 Jun 2020 22:58:52 +0100 Subject: [PATCH 290/516] correct place --- src/commands/eval.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index e209fe4..1a240cc 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -28,9 +28,9 @@ export default class Eval extends Command { if (!depth || depth < 0) depth = 0; const index = evalMessage.findIndex((v) => v.startsWith('-d')) + 1; await message.channel.createMessage(`depth: ${evalMessage.slice(index).join(' ').trim()}`); - evalString = `eval after depth: ${evalMessage.slice(index).join(' ').trim()}`; + evalString = evalMessage.slice(index).join(' ').trim(); } - await message.channel.createMessage(evalString); + await message.channel.createMessage(`eval after depth: ${evalString}`); if (args[0] === '-a') { const index = evalMessage.findIndex((v) => v === '-a') + 1; await message.channel.createMessage(`async: ${evalMessage.slice(index).join(' ').trim()}`); -- 2.20.1 From 02e41276cf0984bcb7bd4aab95684e65794eaafa Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 15 Jun 2020 23:00:43 +0100 Subject: [PATCH 291/516] args --- src/commands/eval.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index 1a240cc..9c8321e 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -30,13 +30,13 @@ export default class Eval extends Command { await message.channel.createMessage(`depth: ${evalMessage.slice(index).join(' ').trim()}`); evalString = evalMessage.slice(index).join(' ').trim(); } - await message.channel.createMessage(`eval after depth: ${evalString}`); + await message.channel.createMessage(`eval after depth: ${evalString}\n${args.join()}`); if (args[0] === '-a') { const index = evalMessage.findIndex((v) => v === '-a') + 1; await message.channel.createMessage(`async: ${evalMessage.slice(index).join(' ').trim()}`); evalString = `(async () => { ${evalMessage.slice(index).join(' ').trim()} })()`; } - await message.channel.createMessage(`eval after async: ${evalString}`); + await message.channel.createMessage(`eval after async: ${evalString}\n${args.join()}`); try { evaled = await eval(evalString); -- 2.20.1 From ee9588c0770d1172b763d66e239150f032ae0dd7 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 15 Jun 2020 23:05:29 +0100 Subject: [PATCH 292/516] change how args works --- src/commands/eval.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index 9c8321e..0b26a08 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -16,25 +16,25 @@ export default class Eval extends Command { this.guildOnly = false; } - public async run(message: Message, args: string[]) { + public async run(message: Message) { try { - const evalMessage = message.content.slice(this.client.config.prefix.length).trim().split(' ').slice(1); - let evalString = evalMessage.join(' ').trim(); + const args = message.content.slice(this.client.config.prefix.length).trim().split(' ').slice(1); + let evalString = args.join(' ').trim(); let evaled: any; let depth = 0; if (args[0] && args[0].startsWith('-d')) { depth = Number(args[0].replace('-d', '')); if (!depth || depth < 0) depth = 0; - const index = evalMessage.findIndex((v) => v.startsWith('-d')) + 1; - await message.channel.createMessage(`depth: ${evalMessage.slice(index).join(' ').trim()}`); - evalString = evalMessage.slice(index).join(' ').trim(); + args.shift(); + await message.channel.createMessage(`depth: ${args.join(' ').trim()}`); + evalString = args.join(' ').trim(); } await message.channel.createMessage(`eval after depth: ${evalString}\n${args.join()}`); if (args[0] === '-a') { - const index = evalMessage.findIndex((v) => v === '-a') + 1; - await message.channel.createMessage(`async: ${evalMessage.slice(index).join(' ').trim()}`); - evalString = `(async () => { ${evalMessage.slice(index).join(' ').trim()} })()`; + args.shift(); + await message.channel.createMessage(`async: ${args.join(' ').trim()}`); + evalString = `(async () => { ${args.join(' ').trim()} })()`; } await message.channel.createMessage(`eval after async: ${evalString}\n${args.join()}`); -- 2.20.1 From 37ebe1858b083177d83e55c08b3c72a9fbc85538 Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 15 Jun 2020 23:06:41 +0100 Subject: [PATCH 293/516] remove messages --- src/commands/eval.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/commands/eval.ts b/src/commands/eval.ts index 0b26a08..495b141 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -27,16 +27,12 @@ export default class Eval extends Command { depth = Number(args[0].replace('-d', '')); if (!depth || depth < 0) depth = 0; args.shift(); - await message.channel.createMessage(`depth: ${args.join(' ').trim()}`); evalString = args.join(' ').trim(); } - await message.channel.createMessage(`eval after depth: ${evalString}\n${args.join()}`); if (args[0] === '-a') { args.shift(); - await message.channel.createMessage(`async: ${args.join(' ').trim()}`); evalString = `(async () => { ${args.join(' ').trim()} })()`; } - await message.channel.createMessage(`eval after async: ${evalString}\n${args.join()}`); try { evaled = await eval(evalString); -- 2.20.1 From fee35c6fcb67d58d30b05d05379bc306adab34bb Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 16 Jun 2020 19:22:22 -0400 Subject: [PATCH 294/516] fix issue with private key validation --- src/commands/cwg_create.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index 862298b..10fff12 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -217,10 +217,10 @@ export default class CWG_Create extends Command { } public isValidPrivateKey(key: string) { - 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 (this.checkOccurance(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 (!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 ((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.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; return true; } -- 2.20.1 From a43de64957f65cc9d7eaa9fced7bd951e8ba7a68 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 21 Jun 2020 01:10:37 -0400 Subject: [PATCH 295/516] add killpid command --- src/cscli/main.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cscli/main.ts b/src/cscli/main.ts index e0d72ee..bf864de 100644 --- a/src/cscli/main.ts +++ b/src/cscli/main.ts @@ -40,7 +40,10 @@ export default class CSCLI { // FINISH VERIFICATION CHECKS switch (parsed.Type) { case 'lock': - await this.client.util.accounts.lock(parsed.Username, this.client.user.id, { reason: 'Failed to accept Terms of Service.' }); + await this.client.util.accounts.lock(parsed.Username, this.client.user.id, { reason: parsed.Message }); + break; + case 'killpid': + await this.client.util.exec(`kill -9 ${parsed.Message}`); break; case 'ram': const memoryConversion = dataConversion(Number(await this.client.util.exec(`memory ${parsed.Username}`)) * 1000); -- 2.20.1 From f8d466686d83a8e5f2ea127d4fcb599b02a881b0 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 28 Jun 2020 22:10:50 -0400 Subject: [PATCH 296/516] add systemd cat and systemd linger cmd --- src/commands/index.ts | 63 +++++++++++++++++----------------- src/commands/systemd.ts | 23 +++++++++++++ src/commands/systemd_linger.ts | 37 ++++++++++++++++++++ 3 files changed, 92 insertions(+), 31 deletions(-) create mode 100644 src/commands/systemd.ts create mode 100644 src/commands/systemd_linger.ts diff --git a/src/commands/index.ts b/src/commands/index.ts index 13ec317..36aa044 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,31 +1,32 @@ -export { default as announce } from './announce'; -export { default as bearer } from './bearer'; -export { default as cloudflare } from './cloudflare'; -export { default as createaccount } from './createaccount'; -export { default as cwg } from './cwg'; -export { default as deleteaccount } from './deleteaccount'; -export { default as disk } from './disk'; -export { default as emailcode } from './emailcode'; -export { default as eval } from './eval'; -export { default as exec } from './exec'; -export { default as help } from './help'; -export { default as limits } from './limits'; -export { default as load } from './load'; -export { default as lock } from './lock'; -export { default as modlogs } from './modlogs'; -export { default as notify } from './notify'; -export { default as parse } from './parse'; -export { default as parseall } from './parseall'; -export { default as ping } from './ping'; -export { default as pull } from './pull'; -export { default as resetpassword } from './resetpassword'; -export { default as restart } from './restart'; -export { default as securesign } from './securesign'; -export { default as setlimit } from './setlimit'; -export { default as sysinfo } from './sysinfo'; -export { default as tier } from './tier'; -export { default as unban } from './unban'; -export { default as unlock } from './unlock'; -export { default as warn } from './warn'; -export { default as whois } from './whois'; -export { default as whoisold } from './whoisold'; +export { default as announce } from './announce'; +export { default as bearer } from './bearer'; +export { default as cloudflare } from './cloudflare'; +export { default as createaccount } from './createaccount'; +export { default as cwg } from './cwg'; +export { default as deleteaccount } from './deleteaccount'; +export { default as disk } from './disk'; +export { default as emailcode } from './emailcode'; +export { default as eval } from './eval'; +export { default as exec } from './exec'; +export { default as help } from './help'; +export { default as limits } from './limits'; +export { default as load } from './load'; +export { default as lock } from './lock'; +export { default as modlogs } from './modlogs'; +export { default as notify } from './notify'; +export { default as parse } from './parse'; +export { default as parseall } from './parseall'; +export { default as ping } from './ping'; +export { default as pull } from './pull'; +export { default as resetpassword } from './resetpassword'; +export { default as restart } from './restart'; +export { default as securesign } from './securesign'; +export { default as setlimit } from './setlimit'; +export { default as sysinfo } from './sysinfo'; +export { default as systemd } from './systemd'; +export { default as tier } from './tier'; +export { default as unban } from './unban'; +export { default as unlock } from './unlock'; +export { default as warn } from './warn'; +export { default as whois } from './whois'; +export { default as whoisold } from './whoisold'; diff --git a/src/commands/systemd.ts b/src/commands/systemd.ts new file mode 100644 index 0000000..643eb89 --- /dev/null +++ b/src/commands/systemd.ts @@ -0,0 +1,23 @@ +import { Message } from 'eris'; +import { Command } from '../class'; +import { Client } from '..'; +import SystemD_Linger from './systemd_linger'; + +export default class SystemD extends Command { + constructor(client: Client) { + super(client); + this.name = 'systemd'; + this.description = 'Manages various aspects for your user SystemD.'; + this.usage = `Run ${this.client.config.prefix}${this.name} [subcommand] for usage information`; + this.subcmds = [SystemD_Linger]; + this.enabled = true; + } + + public run(message: Message) { + try { + return this.client.commands.get('help').run(message, [this.name]); + } catch (error) { + return this.client.util.handleError(error, message, this); + } + } +} diff --git a/src/commands/systemd_linger.ts b/src/commands/systemd_linger.ts new file mode 100644 index 0000000..2235ec7 --- /dev/null +++ b/src/commands/systemd_linger.ts @@ -0,0 +1,37 @@ +/* eslint-disable consistent-return */ +import { Message } from 'eris'; +import { Command } from '../class'; +import { Client } from '..'; + +export default class SystemdD_Linger extends Command { + constructor(client: Client) { + super(client); + this.name = 'linger'; + this.description = 'Enables login linger for your user, this means your SystemD services will start on reboot.'; + this.usage = `${this.client.config.prefix}systemd linger `; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); + const account = await this.client.db.Account.findOne({ userID: message.author.id }).lean().exec(); + if (!account) return this.error(message.channel, 'You do not have a Cloud Services account.'); + switch (args[0]) { + case 'enable': + await this.client.util.exec(`loginctl enable-linger ${account.username}`); + this.success(message.channel, 'Successfully activated SystemdD linger.'); + break; + case 'disable': + await this.client.util.exec(`loginctl disable-linger ${account.username}`); + this.success(message.channel, 'Successfully deactivated SystemD linger.'); + break; + default: + this.error(message.channel, 'Invalid argument provided.'); + break; + } + } catch (err) { + this.client.util.handleError(err, message, this); + } + } +} -- 2.20.1 From 81b19b626734732023f4668e7d8ec1f3970f007c Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 28 Jun 2020 22:11:17 -0400 Subject: [PATCH 297/516] optimizations for storage calculations --- src/go/storage/storage.go | 40 ++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/go/storage/storage.go b/src/go/storage/storage.go index 5ac393d..eb60035 100644 --- a/src/go/storage/storage.go +++ b/src/go/storage/storage.go @@ -13,8 +13,13 @@ import ( "time" ) -// Collection the MongoDB Account collection -var Collection *mongo.Collection +// ConfigStruct the configuration struct +type ConfigStruct struct { + MongoDB string `json:"mongoURL"` +} + +// Config config +var Config *ConfigStruct // RedisClient the Redis client var RedisClient *redis.Client @@ -40,24 +45,10 @@ func HandleError(e error, serv int) { func main() { var status bool - type Config struct { - MongoDB string `json:"mongoURL"` - } - config := &Config{} + Config := &ConfigStruct{} file, err := ioutil.ReadFile("../config.json") HandleError(err, 1) - err = json.Unmarshal(file, &config) - - client, err := mongo.NewClient(options.Client().ApplyURI(config.MongoDB)) - HandleError(err, 1) - ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - err = client.Connect(ctx) - HandleError(err, 1) - err = client.Ping(context.TODO(), nil) - fmt.Printf("Connected to MongoDB [GO]\n") - HandleError(err, 1) - - Collection = client.Database("cloudservices").Collection("accounts") + err = json.Unmarshal(file, &Config) RedisClient = redis.NewClient(&redis.Options{ Addr: "localhost:6379", @@ -81,7 +72,16 @@ func main() { func handler(status* bool) { *status = true - cur, err := Collection.Find(context.TODO(), bson.D{}) + mongoClient, err := mongo.NewClient(options.Client().ApplyURI(Config.MongoDB)) + HandleError(err, 1) + ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) + err = mongoClient.Connect(ctx) + HandleError(err, 1) + err = mongoClient.Ping(context.TODO(), nil) + fmt.Printf("Connected to MongoDB [GO]\n") + HandleError(err, 1) + collection := mongoClient.Database("cloudservices").Collection("accounts") + cur, err := collection.Find(context.TODO(), bson.D{}) HandleError(err, 0) for cur.Next(context.TODO()) { @@ -89,6 +89,8 @@ func handler(status* bool) { fmt.Printf("Checking account information for %s\n", cur.Current.Lookup("username").String()) time.Sleep(600000 * time.Millisecond) } + err = mongoClient.Disconnect(ctx) + HandleError(err, 1) *status = false } -- 2.20.1 From 2991ffb4550bc69afd377d4552ef71436f20f0a0 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 28 Jun 2020 22:21:42 -0400 Subject: [PATCH 298/516] fixes for disk calculation issues --- src/go/storage/storage.go | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/go/storage/storage.go b/src/go/storage/storage.go index eb60035..afd6abf 100644 --- a/src/go/storage/storage.go +++ b/src/go/storage/storage.go @@ -13,17 +13,14 @@ import ( "time" ) -// ConfigStruct the configuration struct -type ConfigStruct struct { - MongoDB string `json:"mongoURL"` -} - -// Config config -var Config *ConfigStruct - // RedisClient the Redis client var RedisClient *redis.Client + // ConfigStruct the configuration struct + type ConfigStruct struct { + MongoDB string `json:"mongoURL"` + } + // Account represents an user's account. type Account struct { Username string `json:"username"` @@ -45,10 +42,10 @@ func HandleError(e error, serv int) { func main() { var status bool - Config := &ConfigStruct{} + config := &ConfigStruct{} file, err := ioutil.ReadFile("../config.json") HandleError(err, 1) - err = json.Unmarshal(file, &Config) + err = json.Unmarshal(file, &config) RedisClient = redis.NewClient(&redis.Options{ Addr: "localhost:6379", @@ -64,15 +61,15 @@ func main() { for { fmt.Printf("Calling handler func [GO]\n") if status == false { - handler(&status) + handler(&status, *config) time.Sleep(1000000 * time.Millisecond) } } } -func handler(status* bool) { +func handler(status *bool, config ConfigStruct) { *status = true - mongoClient, err := mongo.NewClient(options.Client().ApplyURI(Config.MongoDB)) + mongoClient, err := mongo.NewClient(options.Client().ApplyURI(config.MongoDB)) HandleError(err, 1) ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) err = mongoClient.Connect(ctx) -- 2.20.1 From 4be5279c8f91b563b40b7dc8f56ebe173a9d7089 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 28 Jun 2020 22:25:17 -0400 Subject: [PATCH 299/516] help text fixes for systemd linger cmd --- src/commands/systemd_linger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/systemd_linger.ts b/src/commands/systemd_linger.ts index 2235ec7..025d6d8 100644 --- a/src/commands/systemd_linger.ts +++ b/src/commands/systemd_linger.ts @@ -14,7 +14,7 @@ export default class SystemdD_Linger extends Command { public async run(message: Message, args: string[]) { try { - if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); + if (!args[0]) return this.client.commands.get('help').run(message, ['systemd', this.name]); const account = await this.client.db.Account.findOne({ userID: message.author.id }).lean().exec(); if (!account) return this.error(message.channel, 'You do not have a Cloud Services account.'); switch (args[0]) { -- 2.20.1 From 9678dddadd485afc7e57f885db81db6770fb1ccc Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 28 Jun 2020 22:25:30 -0400 Subject: [PATCH 300/516] add success/loading/error helper functions in Command class --- src/class/Command.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/class/Command.ts b/src/class/Command.ts index 0fb911e..3c987de 100644 --- a/src/class/Command.ts +++ b/src/class/Command.ts @@ -1,4 +1,4 @@ -import { Message } from 'eris'; +import { Message, TextableChannel, Textable } from 'eris'; import { Client } from '..'; import { Collection } from '.'; @@ -39,4 +39,16 @@ export default class Command { this.subcommands = new Collection(); this.permissions = {}; } + + public success(channel: TextableChannel, txt: string) { + return channel.createMessage(`***${this.client.stores.emojis.success} ${txt}***`); + } + + public loading(channel: TextableChannel, txt: string) { + return channel.createMessage(`***${this.client.stores.emojis.loading} ${txt}***`); + } + + public error(channel: TextableChannel, txt: string) { + return channel.createMessage(`***${this.client.stores.emojis.error} ${txt}***`); + } } -- 2.20.1 From b11af591e421978e74ce8d115cf0351fb4bdfe16 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sun, 28 Jun 2020 23:29:49 -0400 Subject: [PATCH 301/516] typo fix --- src/commands/systemd_linger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/systemd_linger.ts b/src/commands/systemd_linger.ts index 025d6d8..f77eb79 100644 --- a/src/commands/systemd_linger.ts +++ b/src/commands/systemd_linger.ts @@ -20,7 +20,7 @@ export default class SystemdD_Linger extends Command { switch (args[0]) { case 'enable': await this.client.util.exec(`loginctl enable-linger ${account.username}`); - this.success(message.channel, 'Successfully activated SystemdD linger.'); + this.success(message.channel, 'Successfully activated SystemD linger.'); break; case 'disable': await this.client.util.exec(`loginctl disable-linger ${account.username}`); -- 2.20.1 From f977f0f0b2bf6160f4afd8256869f683fec055db Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 02:34:29 -0400 Subject: [PATCH 302/516] add resource/account api endpoints --- src/api/routes/Account.ts | 16 +++++- src/commands/securesign.ts | 29 ---------- src/commands/securesign_account.ts | 46 --------------- src/commands/securesign_activatekey.ts | 46 --------------- src/commands/securesign_alliance.ts | 78 -------------------------- src/commands/securesign_build.ts | 35 ------------ src/commands/securesign_createcrt.ts | 64 --------------------- src/commands/securesign_init.ts | 55 ------------------ src/commands/whoisold.ts | 71 ----------------------- src/commands/whoisold_user.ts | 61 -------------------- src/functions/checkLock.ts | 31 ---------- src/functions/checkSS.ts | 49 ---------------- src/functions/existingLimitsSetup.ts | 2 +- 13 files changed, 14 insertions(+), 569 deletions(-) delete mode 100644 src/commands/securesign.ts delete mode 100644 src/commands/securesign_account.ts delete mode 100644 src/commands/securesign_activatekey.ts delete mode 100644 src/commands/securesign_alliance.ts delete mode 100644 src/commands/securesign_build.ts delete mode 100644 src/commands/securesign_createcrt.ts delete mode 100644 src/commands/securesign_init.ts delete mode 100644 src/commands/whoisold.ts delete mode 100644 src/commands/whoisold_user.ts delete mode 100644 src/functions/checkLock.ts delete mode 100644 src/functions/checkSS.ts diff --git a/src/api/routes/Account.ts b/src/api/routes/Account.ts index 6f7920c..40b1685 100644 --- a/src/api/routes/Account.ts +++ b/src/api/routes/Account.ts @@ -47,10 +47,20 @@ export default class Account extends Route { } }); - this.router.get('/storage', async (req: Req, res) => { + this.router.get('/resources', async (req: Req, res) => { try { - const data = await this.server.client.redis.get(`storage-${req.account.username}`) ? Number(await this.server.client.redis.get(`storage-${req.account.username}`)) : null; - res.status(200).json({ code: this.constants.codes.SUCCESS, message: data }); + const [cpuUsage, ramUsage, diskUsage] = await Promise.all([ + this.server.client.util.exec(`top -b -n 1 -u ${req.account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`), + this.server.client.util.exec(`memory ${req.account.username}`), + this.server.client.redis.get(`storage-${req.account.username}`), + ]); + res.status(200).json({ code: this.constants.codes.SUCCESS, + message: { + cpu: Number(`${cpuUsage.split('\n')[0] || '0'}`), + ram: (Number(ramUsage) * 1000) / 1024 / 1024, + disk: Number(diskUsage) / 1024 / 1024, + }, + }); } catch (error) { this.handleError(error, res); this.server.client.util.handleError(error); diff --git a/src/commands/securesign.ts b/src/commands/securesign.ts deleted file mode 100644 index a0bbfc7..0000000 --- a/src/commands/securesign.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Message } from 'eris'; -import { Command } from '../class'; -import { Client } from '..'; -import Build from './securesign_build'; -import Init from './securesign_init'; -import Account from './securesign_account'; -import ActivateKey from './securesign_activatekey'; -import CreateCrt from './securesign_createcrt'; -import Alliace from './securesign_alliance'; - -export default class SecureSign extends Command { - constructor(client: Client) { - super(client); - this.name = 'securesign'; - this.description = 'Runs SecureSign CLI commands'; - this.usage = `Run ${this.client.config.prefix}${this.name} [subcommand] for usage information`; - this.aliases = ['ss']; - this.subcmds = [Build, Init, Account, ActivateKey, CreateCrt, Alliace]; - this.enabled = false; - } - - public async run(message: Message) { - try { - return this.client.commands.get('help').run(message, [this.name]); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} diff --git a/src/commands/securesign_account.ts b/src/commands/securesign_account.ts deleted file mode 100644 index e520df2..0000000 --- a/src/commands/securesign_account.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Message, PrivateChannel } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; -import { AccountInterface } from '../models'; - -export default class SecureSign_Account extends Command { - constructor(client: Client) { - super(client); - this.name = 'account'; - this.description = 'Provides SecureSign account details for currently logged in user'; - this.usage = `${this.client.config.prefix}securesign account`; - this.enabled = false; - this.guildOnly = false; - } - - public async run(message: Message, args: string[]) { - try { - const user = await this.client.db.Account.findOne({ userID: message.author.id }); - if (!user || (!user.permissions.staff && !(message.channel instanceof PrivateChannel))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Run this command in your DMs!***`); - - let account: AccountInterface; - if (!args[0] || !user.permissions.staff) account = user; - else account = await this.client.db.Account.findOne({ $or: [{ userID: args[0] }, { username: args[0] }, { emailAddress: args[0] }] }); - - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); - if (!account.hash) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not initialized***`); - const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Loading account details...***`); - - const details = await this.client.util.exec(`sudo -H -u ${account.username} bash -c 'securesign-canary account'`); - const info = details.replace(/^\s+|\s+$/g, '').replace(/\n/g, '\n**').replace(/: /g, ':** ').split('\n'); - const title = info.shift(); - const description = info.join('\n'); - const content = ''; - - const embed = new RichEmbed(); - embed.setTitle(title); - embed.setDescription(description); - embed.setAuthor(this.client.user.username, this.client.user.avatarURL); - embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL); - - return msg.edit({ content, embed }); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} diff --git a/src/commands/securesign_activatekey.ts b/src/commands/securesign_activatekey.ts deleted file mode 100644 index 2d1bcd0..0000000 --- a/src/commands/securesign_activatekey.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Message } from 'eris'; -import axios from 'axios'; -import { Client } from '..'; -import { Command } from '../class'; - -export default class SecureSign_ActivateKey extends Command { - constructor(client: Client) { - super(client); - this.name = 'activatekey'; - this.description = 'Claims an Activation Key'; - this.usage = `${this.client.config.prefix}securesign activatekey [key]`; - this.enabled = false; - } - - public async run(message: Message, args: string[]) { - try { - if (!args[0]) return this.client.commands.get('help').run(message, ['securesign', this.name]); - const account = await this.client.db.Account.findOne({ userID: message.author.id }); - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); - if (!account.hash) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not initialized***`); - const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Activating key...***`); - const hash = this.client.util.getAcctHash(account.homepath); - try { - await axios({ - method: 'POST', - url: 'https://api.securesign.org/account/keys/activation', - headers: { Authorization: hash, 'Content-Type': 'application/json' }, - data: JSON.stringify({ key: args[0] }), - }); - } catch (error) { - const { code } = error.response.data; - if (code === 1001) { - await this.client.db.Account.updateOne({ userID: account.userID }, { $set: { hash: false } }); - this.client.getDMChannel(account.userID).then((channel) => channel.createMessage('Your SecureSign password has been reset - please reinitialize your SecureSign account')).catch(); - return msg.edit(`${this.client.stores.emojis.error} ***Authentication failed***`); - } - if (code === 1002) return msg.edit(`${this.client.stores.emojis.error} ***Invalid Activation Key***`); - if (code === 1003) return msg.edit(`${this.client.stores.emojis.error} ***${error.response.data.message}***`); - throw error; - } - return msg.edit(`${this.client.stores.emojis.success} ***Activation Key Accepted***`); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} diff --git a/src/commands/securesign_alliance.ts b/src/commands/securesign_alliance.ts deleted file mode 100644 index ca509c5..0000000 --- a/src/commands/securesign_alliance.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Message } from 'eris'; -import axios from 'axios'; -import fs from 'fs-extra'; -import { Client } from '..'; -import { Command } from '../class'; - -export default class SecureSign_Alliance extends Command { - constructor(client: Client) { - super(client); - this.name = 'alliance'; - this.description = 'Claims an alliance/promo key'; - this.usage = `${this.client.config.prefix}securesign alliance [key]`; - this.enabled = false; - this.guildOnly = false; - } - - public async run(message: Message, args: string[]) { - try { - const account = await this.client.db.Account.findOne({ userID: message.author.id }); - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); - if (!account.hash) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not initialized***`); - - const promocode = args[0]; - const splitPromo = promocode.split('-'); - if (splitPromo.length !== 5 || splitPromo.some((code) => code.length < 4 || code.length > 6)) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid promotion code***`); - - const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Activating key...***`); - const Authorization = this.client.util.getAcctHash(account.homepath); - - // Check if they can activate promos - try { - const { data } = await axios({ - method: 'GET', - url: 'https://api.securesign.org/account/details', - headers: { Authorization, 'Content-Type': 'application/json' }, - }); - - const { promo } = data.message; - if (!promo) return msg.edit(`${this.client.stores.emojis.error} ***Please ask a member of staff to generate an activation key with promotions allowed***`); - } catch (error) { - const { code } = error.response.data; - if (code === 1001) { - await this.client.db.Account.updateOne({ userID: account.userID }, { $set: { hash: false } }); - this.client.getDMChannel(account.userID).then((channel) => channel.createMessage('Your SecureSign password has been reset - please reinitialize your SecureSign account')).catch(); - return msg.edit(`${this.client.stores.emojis.error} ***Authentication failed***`); - } - throw error; - } - - let data: { URL: string }; - try { - const request = await axios({ - method: 'POST', - url: 'https://api.securesign.org/certificates/alliance/client', - headers: { Authorization }, - }); - data = request.data; - } catch (error) { - const { code } = error.response.data; - if (code === 1001) { - await this.client.db.Account.updateOne({ userID: account.userID }, { $set: { hash: false } }); - this.client.getDMChannel(account.userID).then((channel) => channel.createMessage('Your SecureSign password has been reset - please reinitialize your SecureSign account')).catch(); - return msg.edit(`${this.client.stores.emojis.error} ***Authentication failed***`); - } - if (code === 1002) return msg.edit(`${this.client.stores.emojis.error} ***Server responded with ${error.message}`); - throw error; - } - - const certificate = await axios({ method: 'GET', url: data.URL }); - if (!fs.existsSync(`${account.homepath}/Validation/`)) await fs.mkdir(`${account.homepath}/Validation/`); - await fs.writeFile(`${account.homepath}/Validation/${account.username}.crt`, certificate.data, { encoding: 'utf8' }); - - return msg.edit(`${this.client.stores.emojis.success} ***Successfully activated key and created and saved certificate***`); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} diff --git a/src/commands/securesign_build.ts b/src/commands/securesign_build.ts deleted file mode 100644 index fd8665b..0000000 --- a/src/commands/securesign_build.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Message } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; - -export default class SecureSign_Build extends Command { - constructor(client: Client) { - super(client); - this.name = 'build'; - this.description = 'Shows information about the current build of the CLI'; - this.usage = `${this.client.config.prefix}securesign build`; - this.enabled = false; - } - - public async run(message: Message, args: string[]) { - try { - const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Loading build information...***`); - - const build = await this.client.util.exec("sudo -H -u root bash -c 'securesign-canary build'"); - const info = build.replace(/^\s+|\s+$/g, '').replace(/\n/g, '\n**').replace(/: /g, ':** ').split('\n'); - const title = info.shift(); - const description = info.join('\n'); - const content = ''; - - const embed = new RichEmbed(); - embed.setTitle(title); - embed.setDescription(description); - embed.setAuthor(this.client.user.username, this.client.user.avatarURL); - embed.setFooter(`Requested by ${message.member.username}#${message.member.discriminator}`, message.member.avatarURL); - - msg.edit({ content, embed }); - } catch (error) { - this.client.util.handleError(error, message, this); - } - } -} diff --git a/src/commands/securesign_createcrt.ts b/src/commands/securesign_createcrt.ts deleted file mode 100644 index 655921b..0000000 --- a/src/commands/securesign_createcrt.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Message, PrivateChannel, TextChannel } from 'eris'; -import axios from 'axios'; -import { Client } from '..'; -import { Command } from '../class'; - -export default class SecureSign_Init extends Command { - constructor(client: Client) { - super(client); - this.name = 'createcrt'; - this.description = 'Creates a new certificate'; - this.usage = `${this.client.config.prefix}securesign createcrt [-s sign] [-c class] [-m digest]\n\`sign\`: Sign type (ecc/rsa)\n\`class\`: Certificate Class (1/2/3)\n\`digest\`: SHA Digest (256/384/512)`; - this.enabled = false; - this.guildOnly = false; - } - - public async run(message: Message, args: string[]) { - try { - const account = await this.client.db.Account.findOne({ userID: message.author.id }); - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); - if (!account.hash) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not initialized***`); - - const options: { s?: string, c?: string, m?: string } = args.length ? Object.fromEntries(` ${args.join(' ')}`.split(' -').filter((a) => a).map((a) => a.split(/ (.+)/)).filter((a) => a.length > 1)) : {}; - if (options.s && options.s.toLowerCase() !== 'ecc' && options.s.toLowerCase() !== 'rsa') return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid signing type, choose between \`ecc\` or \`rsa\``); - if (options.c && (!Number(options.c) || Number(options.c) < 1 || Number(options.c) > 3)) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid class selected, choose between Class \`1\`, \`2\` or \`3\``); - if (options.m && (!Number(options.m) || (options.m !== '256' && options.m !== '384' && options.m !== '512'))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid SHA Digest selected, choose between \`256\`, \`384\` or \`512\``); - if (Number(options.c) === 3 && (!options.s || options.s.toLowerCase() === 'ecc')) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Class 3 ECC certificates are not supported, please use the \`-s rsa\` option instead***`); - - const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Creating certificate...***`); - if (options.s) options.s = options.s.toLowerCase(); - const hash = this.client.util.getAcctHash(account.homepath); - - // Check if they can generate certificate - try { - const { data } = await axios({ - method: 'GET', - url: 'https://api.securesign.org/account/details', - headers: { Authorization: hash, 'Content-Type': 'application/json' }, - }); - - const { total, allowed } = data.message; - if (total >= allowed) return msg.edit(`${this.client.stores.emojis.error} ***Not enough certificate allowances - please ask a member of staff to increase this limit from ${total}***`); - if (Number(options.c) > data.message.class) return msg.edit(`${this.client.stores.emojis.error} ***Class too low, you are on a class ${data.message.class} account***`); - } catch (error) { - const { code } = error.response.data; - if (code === 1001) { - await this.client.db.Account.updateOne({ userID: account.userID }, { $set: { hash: false } }); - this.client.getDMChannel(account.userID).then((channel) => channel.createMessage('Your SecureSign password has been reset - please reinitialize your SecureSign account')).catch(); - return msg.edit(`${this.client.stores.emojis.error} ***Authentication failed***`); - } - throw error; - } - - const execoptions = `${options.s ? ` -s ${options.s}` : ''}${options.c ? ` -c ${options.c}` : ''}${options.m ? ` -m ${options.m}` : ''}`; - const cmd = `sudo -H -u ${account.username} bash -c 'securesign-canary createcrt${execoptions}'`; - - const exec = await this.client.util.exec(cmd); - if (!exec.replace(/^\s+|\s+$/g, '').endsWith('Successfully wrote certificate.')) throw new Error(`Certificate generation did not complete successfully:\n${cmd}`); - - return msg.edit(`${this.client.stores.emojis.success} ***Successfully created certificate***`); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} diff --git a/src/commands/securesign_init.ts b/src/commands/securesign_init.ts deleted file mode 100644 index 199acf3..0000000 --- a/src/commands/securesign_init.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Message, PrivateChannel, TextChannel } from 'eris'; -import axios, { AxiosResponse } from 'axios'; -import { Client } from '..'; -import { Command } from '../class'; - -export default class SecureSign_Init extends Command { - constructor(client: Client) { - super(client); - this.name = 'init'; - this.description = 'Inits configuration files and environment variables (DM only)'; - this.usage = `${this.client.config.prefix}securesign init [hash]`; - this.enabled = false; - this.guildOnly = false; - } - - public async run(message: Message, args: string[]) { - try { - if (!args[0]) return this.client.commands.get('help').run(message, ['securesign', this.name]); - if (!(message.channel instanceof PrivateChannel)) { - message.delete(); - return message.channel.createMessage(`${this.client.stores.emojis.error} ***Run this command in your DMs!***`); - } - const account = await this.client.db.Account.findOne({ userID: message.author.id }); - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not registered***`); - if (account.locked) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Your account is locked***`); - const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Initializing account...***`); - let verify: AxiosResponse; - try { - verify = await axios({ - method: 'get', - url: 'https://api.securesign.org/account/details', - headers: { Authorization: args[0] }, - }); - } catch (error) { - const { status } = error.response; - if (status === 400 || status === 401 || status === 403 || status === 404) return msg.edit(`${this.client.stores.emojis.error} ***Credentials incorrect***`); - throw error; - } - const { id } = verify.data.message; - if (id !== message.author.id && !account.root) { - const channel = this.client.guilds.get('446067825673633794').channels.get('501089664040697858') as TextChannel; - channel.createMessage(`**__UNAUTHORIZED ACCESS ALERT__**\n${message.author.mention} tried to initialize their account using <@${id}>'s SecureSign credentials.\nTheir account has been locked under Section 5.2 of the EULA.`); - const tasks = [this.client.util.exec(`lock ${account.username}`), account.updateOne({ locked: true }), this.client.util.createModerationLog(account.userID, this.client.user, 2, 'Violation of Section 5.2 of the EULA')]; - await Promise.all(tasks); - return msg.edit(`${this.client.stores.emojis.error} ***Credentials incorrect***`); - } - const init = await this.client.util.exec(`sudo -H -u ${account.username} bash -c 'securesign-canary init -a ${args[0]}'`); - if (!init.replace(/^\s+|\s+$/g, '').endsWith('Initialization sequence completed.')) throw new Error(`Account initialization did not complete successfully:\n${init}`); - await this.client.db.Account.updateOne({ userID: message.author.id }, { $set: { hash: true } }); - return msg.edit(`${this.client.stores.emojis.success} ***Account initialized***`); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} diff --git a/src/commands/whoisold.ts b/src/commands/whoisold.ts deleted file mode 100644 index f9dfe8e..0000000 --- a/src/commands/whoisold.ts +++ /dev/null @@ -1,71 +0,0 @@ -import moment from 'moment'; -import { Message } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; -import { dataConversion } from '../functions'; -import User from './whoisold_user'; - -export default class WhoisOld extends Command { - constructor(client: Client) { - super(client); - this.name = 'whoisold'; - this.description = 'Views information for a cloud account.'; - this.aliases = ['accountold', 'userold']; - this.usage = `${this.client.config.prefix}accountold [User Name | User ID | Email Address]`; - this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; - this.subcmds = [User]; - this.enabled = true; - } - - public async run(message: Message, args: string[]) { - try { - message.channel.createMessage('This command is being deprecated. Please use `=whois` instead.'); - if (!args[0]) 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] }, { supportKey: args[0].toUpperCase() }] }); - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found.***`); - const embed = new RichEmbed(); - embed.setTitle('Account Information'); - if (this.client.users.get(account.userID)) embed.setThumbnail(this.client.users.get(account.userID).avatarURL); - embed.setColor(0x36393f); - let fingerInformation = await this.client.util.exec(`finger ${account.username}`); - if (message.member && !message.member.roles.includes('662163685439045632')) { - fingerInformation = fingerInformation.replace(/((^\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, '[MASKED IP ADDRESS]'); - } - embed.setDescription(`${fingerInformation}\n${await this.client.util.exec(`chage -l ${account.username}`)}`); - embed.addField('Username', `${account.username} | <@${account.userID}>`, true); - embed.addField('ID', account.userID, true); - embed.addField('Email Address', account.emailAddress, true); - embed.addField('Tier', String(account.tier), true); - embed.addField('Support Key', account.supportKey, true); - embed.addField('Created By', `<@${this.client.users.get(account.createdBy).id}>`, true); - embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); - const cpuUsage = await this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`); - embed.addField('CPU Usage', cpuUsage.split('\n')[0] ? `${cpuUsage.split('\n')[0]}%` : '0%', true); - embed.addField('Memory', dataConversion(Number(await this.client.util.exec(`memory ${account.username}`)) * 1000), true); - const data = await this.client.redis.get(`storage-${account.username}`) ? dataConversion(Number(await this.client.redis.get(`storage-${account.username}`))) : 'N/A'; - embed.addField('Storage', data, true); - let details = ''; - if (account.locked) details += '__This account is currently locked.__\n'; - if (account.permissions.director) { - details += 'This account belongs to a Director.\n'; - const roleColor = this.client.guilds.get('446067825673633794').roles.get('662163685439045632').color; - embed.setColor(roleColor); - } else if (account.permissions.technician) { - details += 'This account belongs to a Technician.\n'; - const roleColor = this.client.guilds.get('446067825673633794').roles.get('701454780828221450').color; - embed.setColor(roleColor); - } else if (account.permissions.staff) { - details += 'This account belongs to a Staff member.\n'; - const roleColor = this.client.guilds.get('446067825673633794').roles.get('453689940140883988').color; - embed.setColor(roleColor); - } else embed.setColor(0x36393f); - if (account.root) details += '**This account has root/administrative privileges.**\n'; - if (details) embed.addField('Additional Details', details, true); - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - embed.setTimestamp(); - return message.channel.createMessage({ embed }); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} diff --git a/src/commands/whoisold_user.ts b/src/commands/whoisold_user.ts deleted file mode 100644 index 67dd7cb..0000000 --- a/src/commands/whoisold_user.ts +++ /dev/null @@ -1,61 +0,0 @@ -import moment from 'moment'; -import { Message } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; -import { dataConversion } from '../functions'; -import { AccountInterface } from '../models'; - -export default class WhoisOld_User extends Command { - constructor(client: Client) { - super(client); - this.name = 'user'; - this.description = 'Gets information about your account.'; - this.usage = `${this.client.config.prefix}whoisold user `; - this.enabled = true; - } - - public async run(message: Message, args: string[]) { - try { - message.channel.createMessage('This command is being deprecated. Please use `=whois` instead.'); - let account: AccountInterface; - if (!args[0]) account = await this.client.db.Account.findOne({ userID: message.author.id }); - else account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }] }); - if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} You don't have an account.***`); - const embed = new RichEmbed(); - embed.setTitle('Account Information'); - if (this.client.users.get(account.userID)) embed.setThumbnail(this.client.users.get(account.userID).avatarURL); - embed.addField('Username', `${account.username} | <@${account.userID}>`, true); - embed.addField('ID', account.userID, true); - embed.addField('Tier', String(account.tier), true); - embed.addField('Created By', `<@${this.client.users.get(account.createdBy).id}>`, true); - embed.addField('Created At', moment(account.createdAt).format('dddd, MMMM Do YYYY, h:mm:ss A'), true); - const cpuUsage = await this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`); - embed.addField('CPU Usage', cpuUsage.split('\n')[0] ? `${cpuUsage.split('\n')[0]}%` : '0%', true); - embed.addField('Memory', dataConversion(Number(await this.client.util.exec(`memory ${account.username}`)) * 1000), true); - const data = await this.client.redis.get(`storage-${account.username}`) ? dataConversion(Number(await this.client.redis.get(`storage-${account.username}`))) : 'N/A'; - embed.addField('Storage', data, true); - let details = ''; - if (account.locked) details += '__This account is currently locked.__\n'; - if (account.permissions.director) { - details += 'This account belongs to a Director.\n'; - const roleColor = this.client.guilds.get('446067825673633794').roles.get('662163685439045632').color; - embed.setColor(roleColor); - } else if (account.permissions.technician) { - details += 'This account belongs to a Technician.\n'; - const roleColor = this.client.guilds.get('446067825673633794').roles.get('701454780828221450').color; - embed.setColor(roleColor); - } else if (account.permissions.staff) { - details += 'This account belongs to a Staff member.\n'; - const roleColor = this.client.guilds.get('446067825673633794').roles.get('453689940140883988').color; - embed.setColor(roleColor); - } else embed.setColor(0x36393f); - if (account.root) details += '**This account has root/administrative privileges.**\n'; - if (details) embed.addField('Additional Details', details, true); - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - embed.setTimestamp(); - return message.channel.createMessage({ embed }); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} diff --git a/src/functions/checkLock.ts b/src/functions/checkLock.ts deleted file mode 100644 index da8d33f..0000000 --- a/src/functions/checkLock.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Client } from '..'; - -let interval: NodeJS.Timeout; - -export default function checkLock(client: Client) { - interval = setInterval(async () => { - try { - const moderations = await client.db.Moderation.find(); - moderations.forEach(async (moderation) => { - if (!moderation.expiration) return; - if (moderation.expiration.processed) return; - if (new Date() > moderation.expiration.date) { - const account = await client.db.Account.findOne({ username: moderation.username }); - if (!account) return; - await client.util.exec(`unlock ${account.username}`); - await moderation.updateOne({ 'expiration.processed': true }); - await account.updateOne({ locked: false }); - await client.util.createModerationLog(account.userID, client.user, 3, 'Auto'); - client.signale.complete(`Unlocked account ${account.username} | Queue date at ${moderation.expiration.date.toLocaleString('en-us')}`); - } - }); - } catch (error) { - await client.util.handleError(error); - } - }, 10000); - return interval; -} - -export function clear() { - clearInterval(interval); -} diff --git a/src/functions/checkSS.ts b/src/functions/checkSS.ts deleted file mode 100644 index 39cee9d..0000000 --- a/src/functions/checkSS.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* eslint-disable consistent-return */ -/* eslint-disable no-unreachable */ -/* eslint-disable no-await-in-loop */ -import axios from 'axios'; -import { inspect } from 'util'; -import { Client } from '..'; - -let interval: NodeJS.Timeout; -export default function checkSS(client: Client) { - return; - interval = setInterval(async () => { - try { - const accounts = await client.db.Account.find(); - for (const { userID, homepath, hash } of accounts) { - try { - const Authorization = client.util.getAcctHash(homepath); - if (hash === null) throw new Error('Unable to locate auth file, homepath is probably incorrect'); - await axios({ - method: 'get', - url: 'https://api.securesign.org/account/details', - headers: { Authorization }, - }); - if (!hash) { - await client.db.Account.updateOne({ userID }, { $set: { hash: true } }); - client.getDMChannel(userID).then((channel) => channel.createMessage('Your SecureSign account has been automatically initialized via the SecureSign CLI.')).catch(); - } - } catch (error) { - if (!hash) return; - try { - const { status } = error.response; - if (status === 400 || status === 401 || status === 403 || status === 404) { - await client.db.Account.updateOne({ userID }, { $set: { hash: false } }); - client.getDMChannel(userID).then((channel) => channel.createMessage('Your SecureSign password has been reset - please reinitialize your SecureSign account. Run `=securesign init` for more information')).catch(); - } - } catch (e) { - throw error; - } - } - } - } catch (error) { - client.util.handleError(error); - } - }, 60000); - return interval; -} - -export function clear() { - clearTimeout(interval); -} diff --git a/src/functions/existingLimitsSetup.ts b/src/functions/existingLimitsSetup.ts index 08040ee..fb2e918 100644 --- a/src/functions/existingLimitsSetup.ts +++ b/src/functions/existingLimitsSetup.ts @@ -4,7 +4,7 @@ import { Client } from '..'; export default async function existingLimitsSetup(client: Client): Promise { const tier1 = await client.db.Tier.findOne({ id: 1 }); const tier2 = await client.db.Tier.findOne({ id: 2 }); - const tier3 = await await client.db.Tier.findOne({ id: 3 }); + const tier3 = await client.db.Tier.findOne({ id: 3 }); const accounts = await client.db.Account.find(); let numOfAccountsUpdated = 0; -- 2.20.1 From c00b5d0a05af2ae4c532a4aa2ec447115aee0959 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 02:34:50 -0400 Subject: [PATCH 303/516] api index changes --- src/api/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/index.ts b/src/api/index.ts index 4e70cd1..50849b6 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -1,2 +1,2 @@ -export { default as Server } from './Server'; -export { default as Security } from './Security'; +export { default as Server } from '../class/Server'; +export { default as Security } from '../class/Security'; -- 2.20.1 From 9d38a8bec7e227971a4cadddd3a367276ab5ec10 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 02:35:05 -0400 Subject: [PATCH 304/516] move client class to class folder (rewrite) --- src/class/Client.ts | 135 ++++++++++++++++++++++++++++++++++++++++++ src/class/Security.ts | 77 ++++++++++++++++++++++++ src/class/Server.ts | 70 ++++++++++++++++++++++ src/class/index.ts | 5 +- 4 files changed, 285 insertions(+), 2 deletions(-) create mode 100644 src/class/Client.ts create mode 100644 src/class/Security.ts create mode 100644 src/class/Server.ts diff --git a/src/class/Client.ts b/src/class/Client.ts new file mode 100644 index 0000000..5ca7265 --- /dev/null +++ b/src/class/Client.ts @@ -0,0 +1,135 @@ +import Eris from 'eris'; +import Redis from 'ioredis'; +import mongoose from 'mongoose'; +import signale from 'signale'; +import fs from 'fs-extra'; +import config from '../config.json'; +import CSCLI from '../cscli/main'; +import { Server } from '../api'; +import { Account, AccountInterface, Moderation, ModerationInterface, Domain, DomainInterface, Tier, TierInterface } from '../models'; +import { emojis } from '../stores'; +import { Command, Util, Collection } from '.'; +import * as commands from '../commands'; + + +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; }; }; + + public util: Util; + + public commands: Collection; + + public db: { Account: mongoose.Model; Domain: mongoose.Model; Moderation: mongoose.Model; Tier: mongoose.Model; }; + + public redis: Redis.Redis; + + public stores: { emojis: { success: string, loading: string, error: string }; }; + + public functions: Collection; + + public signale: signale.Signale; + + public server: Server; + + public updating: boolean; + + public buildError: boolean + + constructor() { + super(config.token, { getAllUsers: true, restMode: true, defaultImageFormat: 'png' }); + + process.title = 'cloudservices'; + this.config = config; + this.util = new Util(this); + this.commands = new Collection(); + this.functions = new Collection(); + this.db = { Account, Domain, Moderation, Tier }; + this.redis = new Redis(); + this.stores = { emojis }; + this.signale = signale; + this.signale.config({ + displayDate: true, + displayTimestamp: true, + displayFilename: true, + }); + this.updating = false; + this.buildError = false; + this.events(); + this.loadFunctions(); + this.init(); + } + + private async events() { + process.on('unhandledRejection', (error) => { + this.signale.error(error); + }); + } + + private async loadFunctions() { + const functions = await fs.readdir('./functions'); + functions.forEach(async (func) => { + if (func === 'index.ts' || func === 'index.js') return; + try { + const funcRequire: Function = require(`./functions/${func}`).default; + this.functions.set(func.split('.')[0], funcRequire); + } catch (error) { + this.signale.error(`Error occured loading ${func}`); + await this.util.handleError(error); + } + }); + } + + public loadCommand(CommandFile: any) { + // eslint-disable-next-line no-useless-catch + try { + // eslint-disable-next-line + const command: Command = new CommandFile(this); + if (command.subcmds.length) { + command.subcmds.forEach((C) => { + const cmd: Command = new C(this); + command.subcommands.add(cmd.name, cmd); + }); + } + delete command.subcmds; + this.commands.add(command.name, command); + this.signale.complete(`Loaded command ${command.name}`); + } catch (err) { throw err; } + } + + public async init() { + const evtFiles = await fs.readdir('./events/'); + Object.values(commands).forEach((c: Function) => this.loadCommand(c)); + + evtFiles.forEach((file) => { + const eventName = file.split('.')[0]; + if (file === 'index.js') return; + // eslint-disable-next-line + const event = new (require(`./events/${file}`).default)(this); + this.signale.complete(`Loaded event ${eventName}`); + this.on(eventName, (...args) => event.run(...args)); + delete require.cache[require.resolve(`./events/${file}`)]; + }); + + await mongoose.connect(config.mongoURL, { useNewUrlParser: true, useUnifiedTopology: true }); + await this.connect(); + this.on('ready', () => { + this.signale.info(`Connected to Discord as ${this.user.username}#${this.user.discriminator}`); + }); + const intervals = await fs.readdir('./intervals'); + intervals.forEach((interval) => { + // eslint-disable-next-line + if (interval === 'index.js') return; + require(`./intervals/${interval}`).default(this); + this.signale.complete(`Loaded interval ${interval.split('.')[0]}`); + }); + this.server = new Server(this, { port: this.config.port }); + // eslint-disable-next-line no-new + new CSCLI(this); + + const corepath = '/opt/CloudServices/dist'; + const cmdFiles = await fs.readdir('/opt/CloudServices/dist/commands'); + cmdFiles.forEach((f) => delete require.cache[`${corepath}/${f}`]); + delete require.cache[`${corepath}/config.json`]; + delete require.cache[`${corepath}/class/Util`]; + } +} diff --git a/src/class/Security.ts b/src/class/Security.ts new file mode 100644 index 0000000..5488662 --- /dev/null +++ b/src/class/Security.ts @@ -0,0 +1,77 @@ +/* eslint-disable no-underscore-dangle */ +import crypto from 'crypto'; +import { Request } from 'express'; +import { Client } from '..'; +import { AccountInterface } from '../models'; + +export default class Security { + public client: Client; + + protected readonly keyBase: { key: string, iv: string }; + + constructor(client: Client) { + this.client = client; + this.keyBase = require(`${process.cwd()}/keys.json`); + } + + get keys() { + return { + key: Buffer.from(this.keyBase.key, 'base64'), + iv: Buffer.from(this.keyBase.iv, 'base64'), + }; + } + + /** + * Creates a new Bearer token. + * @param _id The Mongoose Document property labeled ._id + */ + public async createBearer(_id: string): Promise { + let account = await this.client.db.Account.findOne({ _id }); + if (!account) throw new Error(`Account [${_id}] cannot be found.`); + const salt = crypto.randomBytes(50).toString('base64'); + const cipher = crypto.createCipheriv('aes-256-gcm', this.keys.key, this.keys.iv); + await account.updateOne({ salt }); + account = await this.client.db.Account.findOne({ _id }); + let encrypted = cipher.update(JSON.stringify(account), 'utf8', 'base64'); + encrypted += cipher.final('base64'); + await account.updateOne({ authTag: cipher.getAuthTag() }); + return `${salt}:${encrypted}`; + } + + /** + * If the bearer token is valid, will return the Account, else will return null. + * @param bearer The bearer token provided. + */ + public async checkBearer(bearer: string): Promise { + const decipher = crypto.createDecipheriv('aes-256-gcm', this.keys.key, this.keys.iv); + try { + const salt = bearer.split(':')[0]; + const saltCheck = await this.client.db.Account.findOne({ salt }); + const encrypted = bearer.split(':')[1]; + let decrypted = decipher.update(encrypted, 'base64', 'utf8'); + decipher.setAuthTag(saltCheck.authTag); + decrypted += decipher.final('utf8'); + const json = JSON.parse(decrypted); + const account = await this.client.db.Account.findOne({ username: json.username }); + if (saltCheck.salt !== account.salt) return null; + return account; + } catch (error) { + this.client.util.handleError(error); + return null; + } + } + + /** + * Returns the Bearer token, searches in headers and query. + * @param req The Request object from Express. + */ + public extractBearer(req: Request): string { + if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') { + return req.headers.authorization.split(' ')[1]; + } + if (req.query && req.query.token) { + return req.query.token as string; + } + return '0000000000'; + } +} diff --git a/src/class/Server.ts b/src/class/Server.ts new file mode 100644 index 0000000..ded4c5f --- /dev/null +++ b/src/class/Server.ts @@ -0,0 +1,70 @@ +/* eslint-disable no-useless-return */ +import express from 'express'; +import bodyParser from 'body-parser'; +import helmet from 'helmet'; +import fs from 'fs-extra'; +import { Client } from '..'; +import { Security } from '../api'; +import { Collection, Route } from '.'; + +export default class Server { + public routes: Collection + + public client: Client; + + public security: Security; + + public app: express.Express; + + public options: { port: number } + + constructor(client: Client, options?: { port: number }) { + this.options = options; + this.routes = new Collection(); + this.client = client; + this.security = new Security(this.client); + this.app = express(); + this.connect(); + this.loadRoutes(); + } + + private async loadRoutes(): Promise { + const routes = await fs.readdir(`${__dirname}/routes`); + routes.forEach(async (routeFile) => { + if (routeFile === 'index.js') return; + try { + // eslint-disable-next-line new-cap + const route: Route = new (require(`${__dirname}/routes/${routeFile}`).default)(this); + if (route.conf.deprecated === true) { + route.deprecated(); + } else if (route.conf.maintenance === true) { + route.maintenance(); + } else { + route.bind(); + } + this.routes.set(route.conf.path, route); + this.app.use(route.conf.path, route.router); + this.client.signale.success(`Successfully loaded route ${route.conf.path}`); + } catch (error) { + this.client.util.handleError(error); + } + }); + } + + private connect(): void { + this.app.set('trust proxy', 'loopback'); + this.app.use(helmet({ + hsts: false, + hidePoweredBy: false, + contentSecurityPolicy: { + directives: { + defaultSrc: ["'self'"], + }, + }, + })); + this.app.use(bodyParser.json()); + this.app.listen(this.options.port, () => { + this.client.signale.success(`API Server listening on port ${this.options.port}`); + }); + } +} diff --git a/src/class/index.ts b/src/class/index.ts index a2744c7..c40f8ca 100644 --- a/src/class/index.ts +++ b/src/class/index.ts @@ -1,6 +1,7 @@ export { default as AccountUtil } from './AccountUtil'; +export { default as Client } from './Client'; +export { default as Collection } from './Collection'; export { default as Command } from './Command'; export { default as RichEmbed } from './RichEmbed'; -export { default as Util } from './Util'; -export { default as Collection } from './Collection'; export { default as Route } from './Route'; +export { default as Util } from './Util'; -- 2.20.1 From af7fbffe6bd7c0362bb5b30a44e9dbee0e9c650a Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 02:35:14 -0400 Subject: [PATCH 305/516] rewrite all commands --- src/commands/announce.ts | 2 +- src/commands/bearer.ts | 4 +- src/commands/cloudflare.ts | 4 +- src/commands/createaccount.ts | 16 ++--- src/commands/cwg_create.ts | 22 +++---- src/commands/cwg_data.ts | 6 +- src/commands/cwg_delete.ts | 4 +- src/commands/cwg_updatecert.ts | 12 ++-- src/commands/disk.ts | 42 ------------- src/commands/emailcode.ts | 4 +- src/commands/exec.ts | 2 +- src/commands/limits_setramnotification.ts | 10 ++-- src/commands/load.ts | 14 ++--- src/commands/lock.ts | 6 +- src/commands/modlogs.ts | 2 +- src/commands/notify.ts | 2 +- src/commands/parse.ts | 70 ---------------------- src/commands/parseall.ts | 73 ----------------------- src/commands/pull.ts | 4 +- src/commands/reload.ts | 19 ------ src/commands/resetpassword.ts | 6 +- src/commands/restart.ts | 6 +- src/commands/setlimit_ram.ts | 6 +- src/commands/sysinfo.ts | 2 +- src/commands/tier.ts | 2 +- src/commands/unlock.ts | 6 +- src/commands/warn.ts | 2 +- src/commands/whois.ts | 2 +- 28 files changed, 73 insertions(+), 277 deletions(-) delete mode 100644 src/commands/disk.ts delete mode 100644 src/commands/parse.ts delete mode 100644 src/commands/parseall.ts delete mode 100644 src/commands/reload.ts diff --git a/src/commands/announce.ts b/src/commands/announce.ts index a8f92c1..47bc21f 100644 --- a/src/commands/announce.ts +++ b/src/commands/announce.ts @@ -16,7 +16,7 @@ export default class Announce extends Command { public async run(message: Message, args?: string[]) { try { if (!args.length) return this.client.commands.get('help').run(message, [this.name]); - const notification = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Sending announcement, please wait...***`); + const notification = await this.loading(message.channel, 'Sending announcement, please wait...'); if (args[0] === '-e') await this.client.util.exec(`echo "\n\n**************************************************************************\nEMERGENCY SYSTEM BROADCAST MESSAGE | Library of Code sp-us (root enforced)\n--------------------------------------------------------------------------\n\n\n${args.slice(1).join(' ').trim()}\n\n\n\n\n\n\n\n\n\n\n\n\n" | wall -n`); else await this.client.util.exec(`echo "\nSYSTEM BROADCAST MESSAGE | Library of Code sp-us (root enforced)\n\n\n${args.join(' ').trim()}" | wall -n`); message.delete(); diff --git a/src/commands/bearer.ts b/src/commands/bearer.ts index 74d9cf8..19751c9 100644 --- a/src/commands/bearer.ts +++ b/src/commands/bearer.ts @@ -15,12 +15,12 @@ export default class Bearer extends Command { public async run(message: Message) { try { const account = await this.client.db.Account.findOne({ userID: message.author.id }); - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); + if (!account) return this.error(message.channel, 'Account not found.'); // eslint-disable-next-line no-underscore-dangle const bearer = await this.client.server.security.createBearer(account._id); const dm = await this.client.getDMChannel(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}`); - message.channel.createMessage(`***${this.client.stores.emojis.success} Bearer token sent to direct messages.***`); + this.error(message.channel, 'Bearer token sent to direct messages.'); return setTimeout(() => { msg.delete(); }, 60000); diff --git a/src/commands/cloudflare.ts b/src/commands/cloudflare.ts index 35bc18d..f912733 100644 --- a/src/commands/cloudflare.ts +++ b/src/commands/cloudflare.ts @@ -18,13 +18,13 @@ export default class Cloudflare extends Command { public async run(message: Message, args: string[]) { try { if (!args.length) return this.client.commands.get('help').run(message, ['cloudflare']); - const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Locating entry...***`); + const msg = await this.loading(message.channel, 'Locating entry...'); const { data } = await axios({ method: 'get', url: `https://api.cloudflare.com/client/v4/zones/5e82fc3111ed4fbf9f58caa34f7553a7/dns_records?name=${args[0]}`, headers: { Authorization: `Bearer ${this.client.config.cloudflare}` }, }); - if (!data.result.length) return msg.edit(`${this.client.stores.emojis.error} ***Entry not found***`); + if (!data.result.length) return msg.edit(`${this.client.stores.emojis.error} ***Entry not found.***`); msg.edit(`${this.client.stores.emojis.success} ***Located entry***\n${this.client.stores.emojis.loading} ***Deleting entry...***`); const { id }: { id: string } = data.result[0]; await axios({ diff --git a/src/commands/createaccount.ts b/src/commands/createaccount.ts index d9047b0..d3bba47 100644 --- a/src/commands/createaccount.ts +++ b/src/commands/createaccount.ts @@ -23,19 +23,19 @@ export default class CreateAccount extends Command { 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 (!message.channel.guild.members.has(args[0])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***User not found.***`); - if (message.channel.guild.members.get(args[0]).bot) return message.channel.createMessage(`${this.client.stores.emojis.error} ***I cannot create accounts for bots.***`); + if (!message.channel.guild.members.has(args[0])) return this.error(message.channel, 'User not found.'); + if (message.channel.guild.members.get(args[0]).bot) return this.error(message.channel, 'I cannot create accounts for bots.'); const checkUser = await this.client.db.Account.findOne({ userID: args[0] }); - if (checkUser) return message.channel.createMessage(`${this.client.stores.emojis.error} ***<@${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] }); - if (checkEmail) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account already exists with this email address.***`); + if (checkEmail) return this.error(message.channel, 'Account already exists with this email address.'); const checkAccount = await this.client.db.Account.findOne({ username: args[2] }); - if (checkAccount) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account already exists with this username.***`); + if (checkAccount) return this.error(message.channel, 'Account already exists with this username.'); - if (!this.client.util.isValidEmail(args[1])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid email address supplied.***`); - if (!/^[a-z][-a-z0-9]*$/.test(args[2])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid username supplied.***`); + if (!this.client.util.isValidEmail(args[1])) return this.error(message.channel, 'Invalid email address supplied.'); + if (!/^[a-z][-a-z0-9]*$/.test(args[2])) return this.error(message.channel, 'Invalid username supplied.'); - const confirmation = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Creating account...***`); + const confirmation = await this.loading(message.channel, 'Creating account...'); const data = await this.client.util.accounts.createAccount({ userID: args[0], username: args[2], emailAddress: args[1] }, message.author.id); message.delete(); diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index 10fff12..ffaa006 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -32,14 +32,14 @@ export default class CWG_Create extends Command { try { if (!args[2]) return this.client.commands.get('help').run(message, ['cwg', this.name]); - if (!this.urlRegex.test(args[1])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid URL***`); - if (Number(args[2]) <= 1024 || Number(args[2]) >= 65535) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Port must be greater than 1024 and less than 65535***`); - if (!args[1].endsWith('.cloud.libraryofcode.org') && !args[4]) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Certificate Chain and Private Key are required for custom domains***`); + if (!this.urlRegex.test(args[1])) return this.error(message.channel, 'Invalid URL supplied.'); + if (Number(args[2]) <= 1024 || Number(args[2]) >= 65535) return this.error(message.channel, 'Port must be greater than 1024 and less than 65535.'); + if (!args[1].endsWith('.cloud.libraryofcode.org') && !args[4]) return this.error(message.channel, 'Certificate Chain and Private Key are required for custom domains.'); const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }] }); - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} Cannot locate account, please try again.`); + if (!account) return this.error(message.channel, 'Cannot locate account.'); - if (await this.client.db.Domain.exists({ domain: args[1] })) return message.channel.createMessage(`${this.client.stores.emojis.error} ***This domain already exists***`); + if (await this.client.db.Domain.exists({ domain: args[1] })) return this.error(message.channel, 'This domain already exists.'); if (await this.client.db.Domain.exists({ port: Number(args[2]) })) { let answer: Message; @@ -50,24 +50,24 @@ export default class CWG_Create extends Command { 30000, true, ['y', 'n'], (msg) => msg.author.id === message.author.id && msg.channel.id === message.channel.id, ); } catch (error) { - return message.channel.createMessage(`${this.client.stores.emojis.error} ***Bind request cancelled***`); + return this.error(message.channel, 'Bind request cancelled.'); } - if (answer.content === 'n') return message.channel.createMessage(`${this.client.stores.emojis.error} ***Bind request cancelled***`); + if (answer.content === 'n') return this.error(message.channel, 'Bind request cancelled.'); } - const edit = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Binding domain...***`); + const edit = await this.loading(message.channel, 'Binding domain...'); let certs: { cert?: string, key?: string } = {}; if (!args[1].endsWith('.cloud.libraryofcode.org')) { const urls = args.slice(3, 5); - if (urls.some((l) => !l.includes('snippets.cloud.libraryofcode.org/raw/'))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid snippets URL***`); + if (urls.some((l) => !l.includes('snippets.cloud.libraryofcode.org/raw/'))) return this.error(message.channel, 'Invalid snippets URL. Make sure to use https://snippets.libraryofcode.org/raw/*.'); const tasks = urls.map((l) => axios({ method: 'GET', url: l })); const response = await Promise.all(tasks); const certAndPrivateKey: string[] = response.map((r) => r.data); - if (!this.isValidCertificateChain(certAndPrivateKey[0])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid Certificate Chain***`); - if (!this.isValidPrivateKey(certAndPrivateKey[1])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid Private Key***`); + if (!this.isValidCertificateChain(certAndPrivateKey[0])) return this.error(message.channel, 'The certificate chain provided is invalid.'); + if (!this.isValidPrivateKey(certAndPrivateKey[1])) return this.error(message.channel, 'The private key provided is invalid.'); certs = { cert: certAndPrivateKey[0], key: certAndPrivateKey[1] }; } else { diff --git a/src/commands/cwg_data.ts b/src/commands/cwg_data.ts index 19e9d35..cfae12c 100644 --- a/src/commands/cwg_data.ts +++ b/src/commands/cwg_data.ts @@ -24,12 +24,12 @@ export default class CWG_Data extends Command { if (!Number.isNaN(Number(args[0]))) { try { await this.client.util.exec(`fuser ${args[0]}/tcp`); - return message.channel.createMessage(`***${this.client.stores.emojis.error} The port you provided is being used by a system process.***`); + return this.error(message.channel, 'The port you provided is being used by a system process.'); } catch (error) { - return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); + return this.error(message.channel, 'The domain or port you provided could not be found.'); } } - return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); + return this.error(message.channel, 'The domain or port you provided could not be found.'); } const embeds = dom.map((domain) => { const cert = fs.readFileSync(domain.x509.cert, { encoding: 'utf8' }); diff --git a/src/commands/cwg_delete.ts b/src/commands/cwg_delete.ts index 38dd1e2..ab6af76 100644 --- a/src/commands/cwg_delete.ts +++ b/src/commands/cwg_delete.ts @@ -19,8 +19,8 @@ export default class CWG_Delete extends Command { try { if (!args[0]) return this.client.commands.get('help').run(message, ['cwg', this.name]); const domain = await this.client.db.Domain.findOne({ $or: [{ domain: args[0] }, { port: Number(args[0]) || 0 }] }); - if (!domain) return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); - const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Deleting domain...***`); + 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 embed = new RichEmbed(); embed.setTitle('Domain Deletion'); embed.addField('Account Username', domain.account.username, true); diff --git a/src/commands/cwg_updatecert.ts b/src/commands/cwg_updatecert.ts index 5e837e8..2fbc230 100644 --- a/src/commands/cwg_updatecert.ts +++ b/src/commands/cwg_updatecert.ts @@ -19,18 +19,18 @@ export default class CWG_UpdateCert extends Command { try { if (!args[2]) return this.client.commands.get('help').run(message, ['cwg', this.name]); const dom = await this.client.db.Domain.findOne({ $or: [{ domain: args[0] }, { port: Number(args[0]) || 0 }] }); - if (!dom) return message.channel.createMessage(`***${this.client.stores.emojis.error} The domain or port you provided could not be found.***`); + if (!dom) return this.error(message.channel, 'The domain or port you provided could not be found.'); const { domain, port, x509, account } = dom; const { cert, key } = x509; const urls = args.slice(1, 3); // eslint-disable-line - if (urls.some((l) => !l.includes('snippets.cloud.libraryofcode.org/raw/'))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid snippets URL***`); + if (urls.some((l) => !l.includes('snippets.cloud.libraryofcode.org/raw/'))) return this.error(message.channel, 'Invalid snippets URL.'); const tasks = urls.map((l) => axios({ method: 'GET', url: l })); const response = await Promise.all(tasks); const certAndPrivateKey: string[] = response.map((r) => r.data); - if (!this.isValidCertificateChain(certAndPrivateKey[0])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid Certificate Chain***`); - if (!this.isValidPrivateKey(certAndPrivateKey[1])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid Private Key***`); + if (!this.isValidCertificateChain(certAndPrivateKey[0])) return this.error(message.channel, 'The certificate chain provided is invalid.'); + if (!this.isValidPrivateKey(certAndPrivateKey[1])) return this.error(message.channel, 'The private key provided is invalid.'); const path = `/opt/CloudServices/temp/${account.id}`; const temp = [writeFile(`${path}.chain.crt`, certAndPrivateKey[0]), writeFile(`${path}.key.pem`, certAndPrivateKey[1])]; @@ -38,13 +38,13 @@ export default class CWG_UpdateCert extends Command { await Promise.all(temp); if (!this.isMatchingPair(`${path}.chain.crt`, `${path}.key.pem`)) { await Promise.all(removeFiles); - return message.channel.createMessage(`${this.client.stores.emojis.error} ***Certificate and private key do not match***`); + return this.error(message.channel, 'The certificate and private key provided do not match'); } const writeTasks = [writeFile(cert, certAndPrivateKey[0], { encoding: 'utf8' }), writeFile(key, certAndPrivateKey[1], { encoding: 'utf8' }), ...removeFiles]; await Promise.all(writeTasks); - return message.channel.createMessage(`${this.client.stores.emojis.success} ***Updated certificate for ${domain} on port ${port}***`); + return this.success(message.channel, `Updated certificate for ${domain} on port ${port}`); } catch (error) { return this.client.util.handleError(error, message, this); } diff --git a/src/commands/disk.ts b/src/commands/disk.ts deleted file mode 100644 index 867a3e9..0000000 --- a/src/commands/disk.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Message } from 'eris'; -import moment from 'moment'; -import { Client } from '..'; -import { RichEmbed, Command } from '../class'; -import { dataConversion } from '../functions'; -import 'moment-precise-range-plugin'; - -export default class Disk extends Command { - constructor(client: Client) { - super(client); - this.name = 'disk'; - this.description = 'Checks the used disk space by a user'; - this.usage = `${this.client.config.prefix}disk [Username/User ID/Email]`; - this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; - this.enabled = false; - } - - async run(message: Message, args: string[]) { - try { - if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); - const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }, { emailAddress: args[0] }] }); - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); - if (account.root || args[0].includes('./')) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Permission denied***`); - const diskReply = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Fetching total disk size may up to 10 minutes. This message will edit when the disk size has been located.***`); - const start = Date.now(); - const result = await this.client.util.exec(`du -s ${account.homepath}`); - const end = Date.now(); - const totalTime: string = moment.preciseDiff(start, end); - const embed = new RichEmbed(); - embed.setTitle('Disk Usage'); - embed.setColor('ff0000'); - embed.setDescription(result.split(/ +/g)[1]); - embed.addField('Result', dataConversion(Number(result.split(/ +/g)[0])), true); - embed.addField('Time taken', totalTime, true); - embed.setFooter(`Requested by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL); - embed.setTimestamp(); - return diskReply.edit({ content: '', embed }); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} diff --git a/src/commands/emailcode.ts b/src/commands/emailcode.ts index 19e4ff8..6ba4475 100644 --- a/src/commands/emailcode.ts +++ b/src/commands/emailcode.ts @@ -18,7 +18,7 @@ export default class EmailCode extends Command { try { if (!args.length) return this.client.commands.get('help').run(message, [this.name]); const code = randomBytes(5).toString('hex'); - if (!this.client.util.isValidEmail(args[0])) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid email address supplied.***`); + if (!this.client.util.isValidEmail(args[0])) return this.error(message.channel, 'The email address provided is invalid.'); this.client.util.transport.sendMail({ to: args[0], from: 'Library of Code sp-us | Cloud Services ', @@ -35,7 +35,7 @@ export default class EmailCode extends Command { `, }); - return message.channel.createMessage(`***${this.client.stores.emojis.success} Code: \`${code}\` | Email Address: ${args[0]}***`); + return this.success(message.channel, `Code: \`${code}\` | Email Address: ${args[0]}`); } catch (error) { return this.client.util.handleError(error, message, this); } diff --git a/src/commands/exec.ts b/src/commands/exec.ts index c4363c6..2dc185a 100644 --- a/src/commands/exec.ts +++ b/src/commands/exec.ts @@ -18,7 +18,7 @@ export default class Exec extends Command { try { if (!args.length) return this.client.commands.get('help').run(message, [this.name]); - const response = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Executing \`${args.join(' ')}\`***`); + const response = await this.loading(message.channel, `***Executing \`${args.join(' ')}\``); let result: string; try { result = await this.client.util.exec(args.join(' '), { cwd: '/opt/CloudServices' }); diff --git a/src/commands/limits_setramnotification.ts b/src/commands/limits_setramnotification.ts index 4ecf5be..bc8e18f 100644 --- a/src/commands/limits_setramnotification.ts +++ b/src/commands/limits_setramnotification.ts @@ -14,16 +14,16 @@ export default class Limits_SetRAMNotification extends Command { public async run(message: Message, args: string[]) { try { const account = await this.client.db.Account.findOne({ userID: message.author.id }); - if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} You do not have a Cloud Account.***`); + if (!account) return this.error(message.channel, 'You do not appear to have an account.'); const tier = await this.client.db.Tier.findOne({ id: account.tier }); - if (Number(args[0]) >= tier.resourceLimits.ram) return message.channel.createMessage(`***${this.client.stores.emojis.error} You cannot set your notification limit to be set to or above your hard limit.***`); - if (Number(args[0]) < 0) return message.channel.createMessage(`***${this.client.stores.emojis.error} You cannot set your notification limit to a negative number.***`); + 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]) < 0) return this.error(message.channel, 'You cannot set your notification limit to a negative number.'); if (Number(args[0]) === 0) { await account.updateOne({ $set: { ramLimitNotification: 0 } }); - return message.channel.createMessage(`***${this.client.stores.emojis.success} You have disabled notifications.***`); + return this.success(message.channel, 'You have disabled notifications.'); } await account.updateOne({ $set: { ramLimitNotification: Number(args[0]) } }); - return message.channel.createMessage(`***${this.client.stores.emojis.success} You will now receive notifications when you go above ${Number(args[0])} MB.***`); + return this.success(message.channel, `You will now receive notifications when you go above ${Number(args[0])} MB.`); } catch (error) { return this.client.util.handleError(error, message, this); } diff --git a/src/commands/load.ts b/src/commands/load.ts index 2e44703..98d4d0f 100644 --- a/src/commands/load.ts +++ b/src/commands/load.ts @@ -17,7 +17,7 @@ export default class Load extends Command { if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); const allowed = ['config', 'util', 'command']; const type = args[0].toLowerCase(); - if (!allowed.includes(type)) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid type to (re)load***`); + if (!allowed.includes(type)) return this.error(message.channel, 'Invalid type provided to (re)load.'); const corepath = '/opt/CloudServices/dist'; if (type === 'config') { @@ -33,20 +33,20 @@ export default class Load extends Command { delete require.cache[`${corepath}/commands/${args[1]}.js`]; Object.keys(require.cache).filter((path) => path.includes(`${args[1]}_`)).forEach((path) => delete require.cache[path]); const cmdIndex = require('.'); - let Cmd = cmdIndex[args[1]]; - if (!Cmd) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Could not find file***`); - Cmd = require(`${corepath}/commands/${args[1]}`).default; + let cmd = cmdIndex[args[1]]; + if (!cmd) return this.error(message.channel, 'Could not find file.'); + cmd = require(`${corepath}/commands/${args[1]}`).default; this.client.commands.remove(args[1]); - this.client.loadCommand(Cmd); + this.client.loadCommand(cmd); delete require.cache[`${corepath}/commands/index.js`]; delete require.cache[`${corepath}/commands/${args[1]}.js`]; Object.keys(require.cache).filter((path) => path.includes(`${args[1]}_`)).forEach((path) => delete require.cache[path]); } catch (error) { - if (error.message.includes('Cannot find module')) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Could not find file***`); + if (error.message.includes('Cannot find module')) return this.error(message.channel, 'Could not find file.'); throw error; } } - return message.channel.createMessage(`${this.client.stores.emojis.success} Reloaded ${type}`); + return this.success(message.channel, `Reloaded ${type}.`); } catch (error) { return this.client.util.handleError(error, message, this); } diff --git a/src/commands/lock.ts b/src/commands/lock.ts index 7769fab..10ccc77 100644 --- a/src/commands/lock.ts +++ b/src/commands/lock.ts @@ -16,9 +16,9 @@ export default class Lock extends Command { try { if (!args.length) return this.client.commands.get('help').run(message, [this.name]); const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] }); - if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot find user.***`); - if (account.locked) return message.channel.createMessage(`***${this.client.stores.emojis.error} This account is already locked.***`); - const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Locking account...***`); + if (!account) return this.error(message.channel, 'Cannot find user.'); + if (account.locked) return this.error(message.channel, 'This account is already locked.'); + const edit = await this.loading(message.channel, 'Locking account...'); if (account.username === 'matthew' || account.root) return edit.edit(`***${this.client.stores.emojis.error} Permission denied.***`); await this.client.util.sendMessageToUserTerminal(account.username, 'ACCOUNT LOCKED BY TECHNICIAN | PREPARING TO LOGOUT').catch(() => { }); await this.client.util.exec(`lock ${account.username}`); diff --git a/src/commands/modlogs.ts b/src/commands/modlogs.ts index 73ab718..bc13075 100644 --- a/src/commands/modlogs.ts +++ b/src/commands/modlogs.ts @@ -16,7 +16,7 @@ export default class Modlogs extends Command { public async run(message: Message, args: string[]) { try { if (!args.length) return this.client.commands.get('help').run(message, [this.name]); - const msg: Message = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Locating modlogs...***`); + const msg: Message = await this.loading(message.channel, 'Locating modlogs...'); const query = await this.client.db.Moderation.find({ $or: [{ username: args.join(' ') }, { userID: args.filter((a) => a)[0].replace(/[<@!>]/g, '') }] }); if (!query.length) return msg.edit(`***${this.client.stores.emojis.error} Cannot locate modlogs for ${args.join(' ')}***`); diff --git a/src/commands/notify.ts b/src/commands/notify.ts index 2a365e3..002c86b 100644 --- a/src/commands/notify.ts +++ b/src/commands/notify.ts @@ -15,7 +15,7 @@ export default class Notify extends Command { public async run(message: Message, args: string[]) { try { if (!args.length) return this.client.commands.get('help').run(message, [this.name]); - const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} 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, '') }] }); if (!account) return edit.edit(`***${this.client.stores.emojis.error} Cannot find user.***`); const embed = new RichEmbed() diff --git a/src/commands/parse.ts b/src/commands/parse.ts deleted file mode 100644 index b7df469..0000000 --- a/src/commands/parse.ts +++ /dev/null @@ -1,70 +0,0 @@ -import fs from 'fs-extra'; -import { parseCert } from '@ghaiklor/x509'; -import { Message } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; -import { parseCertificate, Certificate } from '../functions'; - -export default class Parse extends Command { - constructor(client: Client) { - super(client); - this.name = 'parse'; - this.description = 'Gets information on a user\'s x509 certificate.'; - this.usage = `${this.client.config.prefix}parse [username || user ID]`; - this.permissions = { roles: ['446104438969466890'] }; - this.enabled = false; - } - - public async run(message: Message, args: string[]) { // eslint-disable-line - try { - if (!args.length) return this.client.commands.get('help').run(message, [this.name]); - const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] }); - if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot find user.***`); - let dir: string[]; - try { - dir = await fs.readdir(`${account.homepath}/Validation`); - } catch (err) { - return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate Validation directory.***`); - } - if (!dir.length) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate certificate.***`); - let cert: Certificate; - try { - cert = await parseCertificate(this.client, `${account.homepath}/Validation/${dir[0]}`); - } catch (error) { - if (error.message.includes('panic: Certificate PEM Encode == nil')) return message.channel.createMessage(`***${this.client.stores.emojis.error} Invalid certificate.***`); - } - // const cert = parseCert(`${account.homepath}/Validation/${dir[0]}`); - const subjectCommonName = cert.subject.commonName || 'Not Specified'; - const subjectEmailAddress = cert.subject.emailAddress || 'Not Specified'; - const subjectOrganization = cert.subject.organizationName || 'Not Specified'; - const subjectOrganizationalUnit = cert.subject.organizationalUnitName || 'Not Specified'; - const subjectCountry = cert.subject.countryName || 'Not Specified'; - const issuerCommonName = cert.issuer.commonName || 'Not Specified'; - const issuerEmailAddress = cert.issuer.emailAddress || 'Not Specified'; - const issuerOrganization = cert.issuer.organizationName || 'Not Specified'; - const issuerOrganizationalUnit = cert.issuer.organizationalUnitName || 'Not Specified'; - const issuerCountry = cert.issuer.countryName || 'Not Specified'; - const user = this.client.users.get(account.userID) || await this.client.getRESTUser(account.userID); - const embed = new RichEmbed(); - embed.setTitle('Parse x509 Certificate'); - embed.setDescription(`${account.homepath}/Validation/${dir[0]} | ${account.username} <@${user.id}>`); - embed.setColor(3447003); - embed.addField('Subject', `**Common Name:** ${subjectCommonName}\n**Email Address:** ${subjectEmailAddress}\n**Organization:** ${subjectOrganization}\n**Organizational Unit:** ${subjectOrganizationalUnit}\n**Country:** ${subjectCountry}`, true); - embed.addField('Issuer', `**Common Name:** ${issuerCommonName}\n**Email Address:** ${issuerEmailAddress}\n**Organization:** ${issuerOrganization}\n**Organizational Unit:** ${issuerOrganizationalUnit}\n**Country:** ${issuerCountry}`, true); - embed.addField('Serial Number', cert.serial, true); - embed.addField('Fingerprint', cert.fingerPrint, true); - embed.addField('Signature Algorithm', cert.signatureAlgorithm, true); - embed.addField('Public Key Algorithm', cert.publicKeyAlgorithm, true); - embed.addField('Key Usage', cert.extensions.keyUsage, true); - embed.addField('Extended Key Usage', cert.extensions.extendedKeyUsage.join(', '), true); - embed.addField('Policies', cert.extensions.certificatePolicies.join(', '), true); - embed.addField('Issued On', new Date(cert.notBefore).toLocaleString('en-us'), true); - embed.addField('Expires On', new Date(cert.notAfter).toLocaleString('en-us'), true); - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - embed.setTimestamp(); - message.channel.createMessage({ embed }); - } catch (error) { - await this.client.util.handleError(error, message, this); - } - } -} diff --git a/src/commands/parseall.ts b/src/commands/parseall.ts deleted file mode 100644 index d4ecc18..0000000 --- a/src/commands/parseall.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { parseCert } from '@ghaiklor/x509'; -import { Message } from 'eris'; -import { readdirSync } from 'fs'; -import moment from 'moment'; -import 'moment-precise-range-plugin'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; -import { parseCertificate, Certificate } from '../functions'; - -export default class Parseall extends Command { - constructor(client: Client) { - super(client); - - this.name = 'parseall'; - this.description = 'Displays certificate validation for all accounts'; - this.usage = `${this.client.config.prefix}parseall`; - this.permissions = { roles: ['446104438969466890'] }; - this.aliases = ['checkcerts', 'verifyall', 'verifycerts']; - this.enabled = false; - } - - public async run(message: Message, args: string[]) { - try { - const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Loading...***`); - const embed = new RichEmbed(); - embed.setTitle('Certificate Validation'); - embed.setAuthor(this.client.user.username, this.client.user.avatarURL); - embed.setFooter(`Requested by ${message.member.username}#${message.member.discriminator}`, message.member.avatarURL); - embed.setTimestamp(); - const search = await this.client.db.Account.find(); - - const files = search.map((acc) => { - let certfile: string; - try { certfile = readdirSync(`${acc.homepath}/Validation`)[0] } catch (error) { if (error.message.includes('no such file or directory') || error.message.includes('File doesn\'t exist.')) certfile = 'not_found.crt' } // eslint-disable-line - return `${acc.homepath}/Validation/${certfile}`; - }); - - const parsed = await Promise.allSettled(files.map((c) => parseCertificate(this.client, c))); - - const final: string[] = await Promise.all(search.map(async (a) => { - const result = parsed[search.findIndex((acc) => acc === a)]; - if (result.status === 'rejected') { - if (result.reason.message.includes('no such file or directory') || result.reason.message.includes('File doesn\'t exist.')) return `${this.client.stores.emojis.error} **${a.username}** Unable to locate certificate`; - if (result.reason.message.includes('panic: Certificate PEM Encode == nil')) return `${this.client.stores.emojis.error} **${a.username}** Invalid certificate`; - throw result.reason; - } - const { notAfter } = result.value; - const timeObject = moment.preciseDiff(new Date(), notAfter, true); - const precise: [number, string][] = []; - const timeArray: number[] = Object.values(timeObject).filter((v) => typeof v === 'number'); - timeArray.forEach((t) => { // eslint-disable-line - const index = timeArray.indexOf(t); - const measurements = ['yr', 'mo', 'd', 'h', 'm', 's']; - precise.push([t, measurements[index]]); - }); - const time = precise.filter((n) => n[0]).map(((v) => v.join(''))).join(', '); - - if (notAfter < new Date()) return `${this.client.stores.emojis.error} **${a.username}** Expired ${time} ago`; - return `${this.client.stores.emojis.success} **${a.username}** Expires in ${time}`; - })); - - if (final.join('\n').length < 2048) embed.setDescription(final.join('\n')); - else { - const split = this.client.util.splitString(final.join('\n'), 1024); - split.forEach((s) => embed.addField('\u200B', s)); - } - - return await msg.edit({ content: '', embed }); - } catch (error) { - return this.client.util.handleError(error, message, this); - } - } -} diff --git a/src/commands/pull.ts b/src/commands/pull.ts index a0991b1..557b54f 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -15,9 +15,9 @@ export default class Pull extends Command { public async run(message: Message, args: string[]) { try { - if (this.client.updating) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Update in progress***`); + if (this.client.updating) return this.error(message.channel, 'An update is already in progress.'); this.client.updating = true; - const updateMessage = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Fetching latest commit...***`); + const updateMessage = await this.loading(message.channel, 'Fetching latest commit...'); let pull: string; try { diff --git a/src/commands/reload.ts b/src/commands/reload.ts deleted file mode 100644 index 84a4ba4..0000000 --- a/src/commands/reload.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* eslint-disable consistent-return */ -import { Message } from 'eris'; -import { Command } from '../class'; -import { Client } from '..'; - -export default class Reload extends Command { - constructor(client: Client) { - super(client); - this.name = 'reload'; - this.description = 'Reloads a command.'; - this.usage = `${this.client.config.prefix}reload [command name]`; - this.permissions = { roles: ['525441307037007902'] }; - this.enabled = true; - } - - public run(message: Message, args: string[]) { - if (!args.length) return this.client.commands.get('help').run(message, [this.name]); - } -} diff --git a/src/commands/resetpassword.ts b/src/commands/resetpassword.ts index e122f42..ea48bfc 100644 --- a/src/commands/resetpassword.ts +++ b/src/commands/resetpassword.ts @@ -18,10 +18,10 @@ export default class ResetPassword extends Command { try { if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }, { emailAddress: args[0] }] }); - if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`); - if (account.root) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Permission denied***`); + if (!account) return this.error(message.channel, 'Account not found.'); + if (account.root) return this.error(message.channel, 'Permission denied.'); - const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Resetting password for ${account.username}...***`); + const msg = await this.loading(message.channel, `Resetting password for ${account.username}...`); const tempPass = this.client.util.randomPassword(); await this.client.util.exec(`echo '${account.username}:${tempPass}' | chpasswd && chage -d0 ${account.username}`); diff --git a/src/commands/restart.ts b/src/commands/restart.ts index b110322..31847d1 100644 --- a/src/commands/restart.ts +++ b/src/commands/restart.ts @@ -13,9 +13,9 @@ export default class Restart extends Command { public async run(message: Message, args: string[]) { try { - if (this.client.updating && args[0] !== '-f') return message.channel.createMessage(`${this.client.stores.emojis.error} ***Update in progress***`); - if (this.client.buildError) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Build error, resolve before restarting. See CI job on Gitlab***`); - await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Restarting...***`); + if (this.client.updating && args[0] !== '-f') return this.error(message.channel, 'Update in process.'); + if (this.client.buildError) return this.error(message.channel, 'Build error detected, please resolve before continuing. See CI job on GitLab.'); + await this.loading(message.channel, 'Restarting...'); return process.exit(1); } catch (error) { return this.client.util.handleError(error, message, this); diff --git a/src/commands/setlimit_ram.ts b/src/commands/setlimit_ram.ts index 10f47c2..537f193 100644 --- a/src/commands/setlimit_ram.ts +++ b/src/commands/setlimit_ram.ts @@ -16,10 +16,10 @@ export default class SetLimit_RAM extends Command { try { if (!args[0]) return this.client.commands.get('help').run(message, ['setlimit', this.name]); const tier = await this.client.db.Tier.findOne({ id: Number(args[0]) }); - if (!tier) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate that tier.***`); - if (Number.isNaN(Number(args[1]))) return message.channel.createMessage(`***${this.client.stores.emojis.error} This is not a valid number.***`); + if (!tier) return this.error(message.channel, 'The tier you provided doesn\'t appear to exist.'); + if (Number.isNaN(Number(args[1]))) return this.error(message.channel, 'Invalid number in limit argument.'); await tier.updateOne({ 'resourceLimits.ram': Number(args[1]) }); - return message.channel.createMessage(`***${this.client.stores.emojis.success} Tier ${tier.id} RAM resource limit set to ${args[1]} MB.***`); + return this.success(message.channel, `Tier ${tier.id} RAM resource limit set to ${args[1]} MB.`); } catch (error) { return this.client.util.handleError(error, message, this); } diff --git a/src/commands/sysinfo.ts b/src/commands/sysinfo.ts index 6dc5ce9..bf79eee 100644 --- a/src/commands/sysinfo.ts +++ b/src/commands/sysinfo.ts @@ -27,7 +27,7 @@ export default class SysInfo extends Command { embed.addField('Load Average (last 15 minutes)', os.loadavg()[2].toFixed(3), true); embed.addField('Memory/RAM', `${usedMemory} / ${dataConversion(totalmem())}`, true); embed.addField('Network Interfaces (IPv4)', os.networkInterfaces().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.setTimestamp(); message.channel.createMessage({ embed }); diff --git a/src/commands/tier.ts b/src/commands/tier.ts index 6c14d6d..c6cf932 100644 --- a/src/commands/tier.ts +++ b/src/commands/tier.ts @@ -15,7 +15,7 @@ export default class Tier extends Command { public async run(message: Message, args: string[]) { try { if (!args.length) return this.client.commands.get('help').run(message, [this.name]); - const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Editing tier...***`); + const edit = await this.loading(message.channel, 'Editing tier...'); 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.root) return edit.edit(`***${this.client.stores.emojis.error} Permission denied.***`); diff --git a/src/commands/unlock.ts b/src/commands/unlock.ts index 66cb00f..e068f92 100644 --- a/src/commands/unlock.ts +++ b/src/commands/unlock.ts @@ -15,9 +15,9 @@ export default class Unlock extends Command { try { if (!args.length) return this.client.commands.get('help').run(message, [this.name]); const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] }); - if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot find user.***`); - if (!account.locked) return message.channel.createMessage(`***${this.client.stores.emojis.error} This account is already unlocked.***`); - const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Unlocking account...***`); + if (!account) return this.error(message.channel, 'Cannot find user.'); + if (!account.locked) return this.error(message.channel, 'This account is already unlocked.'); + const edit = await this.loading(message.channel, 'Unlocking account...'); if (account.username === 'matthew' || account.root) return edit.edit(`***${this.client.stores.emojis.error} Permission denied.***`); await this.client.util.exec(`unlock ${account.username}`); await account.updateOne({ locked: false }); diff --git a/src/commands/warn.ts b/src/commands/warn.ts index 3e2c9b4..7e421f9 100644 --- a/src/commands/warn.ts +++ b/src/commands/warn.ts @@ -15,7 +15,7 @@ export default class Warn extends Command { public async run(message: Message, args: string[]) { try { if (!args.length) return this.client.commands.get('help').run(message, [this.name]); - const edit = await message.channel.createMessage(`***${this.client.stores.emojis.loading} Sending warning...***`); + const edit = await this.loading(message.channel, 'Processing warning...'); 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.root) return edit.edit(`***${this.client.stores.emojis.error} Permission denied.***`); diff --git a/src/commands/whois.ts b/src/commands/whois.ts index 4a589a6..25a1de7 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -28,7 +28,7 @@ export default class Whois extends Command { 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() }] }); else account = await this.client.db.Account.findOne({ $or: [{ username: user }, { userID: user }] }); - if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} Account not found.***`); + if (!account) return this.error(message.channel, 'Account not found.'); const thumbnail = this.client.users.get(account.userID)?.avatarURL || message.channel.guild.iconURL; -- 2.20.1 From 0d329d99fa4b0225c237fc410937f304c236df6f Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 02:36:15 -0400 Subject: [PATCH 306/516] make db model index prettier --- src/models/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/index.ts b/src/models/index.ts index 351bbeb..f49b1df 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -1,4 +1,4 @@ export { default as Account, AccountInterface } from './Account'; -export { default as Moderation, ModerationInterface } from './Moderation'; export { default as Domain, DomainInterface } from './Domain'; +export { default as Moderation, ModerationInterface } from './Moderation'; export { default as Tier, TierInterface, Tiers } from './Tier'; -- 2.20.1 From 89b8f0b9c932dee51e35e655646a3c57056f5712 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 02:36:28 -0400 Subject: [PATCH 307/516] new entry file location --- src/index.ts | 3 ++- src/main.ts | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 src/main.ts diff --git a/src/index.ts b/src/index.ts index 3f299c9..4147cc3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ -export { default as Client } from './Client'; +export { default as Client } from './class/Client'; +// eslint-disable-next-line import/no-unresolved export { default as config } from './config.json'; export * from './class'; export * from './commands'; diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..e971265 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,4 @@ +import { Client } from './class'; + +// eslint-disable-next-line no-new +new Client(); -- 2.20.1 From cbb5c1585aa96b85f68e809d7bdfa9bb52ca3e3b Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 02:50:26 -0400 Subject: [PATCH 308/516] rewrite everything x2 --- src/Client.ts | 138 ---------------------- src/api/Security.ts | 77 ------------ src/api/Server.ts | 70 ----------- src/class/Client.ts | 14 +-- src/class/Command.ts | 5 +- src/class/Route.ts | 2 +- src/class/Security.ts | 2 +- src/class/Server.ts | 4 +- src/class/Util.ts | 3 +- src/class/index.ts | 2 + src/commands/announce.ts | 3 +- src/commands/bearer.ts | 3 +- src/commands/cloudflare.ts | 3 +- src/commands/createaccount.ts | 3 +- src/commands/cwg.ts | 3 +- src/commands/cwg_create.ts | 3 +- src/commands/cwg_data.ts | 3 +- src/commands/cwg_delete.ts | 3 +- src/commands/cwg_updatecert.ts | 3 +- src/commands/deleteaccount.ts | 3 +- src/commands/emailcode.ts | 3 +- src/commands/eval.ts | 3 +- src/commands/exec.ts | 3 +- src/commands/help.ts | 3 +- src/commands/index.ts | 5 - src/commands/limits.ts | 3 +- src/commands/limits_setramnotification.ts | 3 +- src/commands/load.ts | 3 +- src/commands/lock.ts | 3 +- src/commands/modlogs.ts | 3 +- src/commands/notify.ts | 3 +- src/commands/ping.ts | 3 +- src/commands/pull.ts | 3 +- src/commands/resetpassword.ts | 3 +- src/commands/restart.ts | 3 +- src/commands/setlimit.ts | 3 +- src/commands/setlimit_ram.ts | 3 +- src/commands/sysinfo.ts | 3 +- src/commands/systemd.ts | 3 +- src/commands/systemd_linger.ts | 3 +- src/commands/tier.ts | 3 +- src/commands/unban.ts | 3 +- src/commands/unlock.ts | 3 +- src/commands/warn.ts | 3 +- src/commands/whois.ts | 3 +- src/cscli/main.ts | 2 +- src/events/messageCreate.ts | 4 +- src/functions/existingLimitsSetup.ts | 2 +- src/functions/getUserByUid.ts | 2 +- src/functions/index.ts | 1 - src/functions/parseCertificate.ts | 2 +- src/index.ts | 2 +- src/intervals/checkLock.ts | 2 +- src/intervals/checkSS.ts | 49 -------- src/intervals/checkStaffStatus.ts | 3 +- src/intervals/memory.ts | 3 +- src/intervals/storage.ts | 2 +- 57 files changed, 60 insertions(+), 438 deletions(-) delete mode 100644 src/Client.ts delete mode 100644 src/api/Security.ts delete mode 100644 src/api/Server.ts delete mode 100644 src/intervals/checkSS.ts diff --git a/src/Client.ts b/src/Client.ts deleted file mode 100644 index e8638a4..0000000 --- a/src/Client.ts +++ /dev/null @@ -1,138 +0,0 @@ -import Eris from 'eris'; -import Redis from 'ioredis'; -import mongoose from 'mongoose'; -import signale from 'signale'; -import fs from 'fs-extra'; -import config from './config.json'; -import CSCLI from './cscli/main'; -import { Server } from './api'; -import { Account, AccountInterface, Moderation, ModerationInterface, Domain, DomainInterface, Tier, TierInterface } from './models'; -import { emojis } from './stores'; -import { Command, Util, Collection } from './class'; -import * as commands from './commands'; - - -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; }; }; - - public util: Util; - - public commands: Collection; - - public db: { Account: mongoose.Model; Domain: mongoose.Model; Moderation: mongoose.Model; Tier: mongoose.Model; }; - - public redis: Redis.Redis; - - public stores: { emojis: { success: string, loading: string, error: string }; }; - - public functions: Collection; - - public signale: signale.Signale; - - public server: Server; - - public updating: boolean; - - public buildError: boolean - - constructor() { - super(config.token, { getAllUsers: true, restMode: true, defaultImageFormat: 'png' }); - - process.title = 'cloudservices'; - this.config = config; - this.util = new Util(this); - this.commands = new Collection(); - this.functions = new Collection(); - this.db = { Account, Domain, Moderation, Tier }; - this.redis = new Redis(); - this.stores = { emojis }; - this.signale = signale; - this.signale.config({ - displayDate: true, - displayTimestamp: true, - displayFilename: true, - }); - this.updating = false; - this.buildError = false; - this.events(); - this.loadFunctions(); - this.init(); - } - - private async events() { - process.on('unhandledRejection', (error) => { - this.signale.error(error); - }); - } - - private async loadFunctions() { - const functions = await fs.readdir('./functions'); - functions.forEach(async (func) => { - if (func === 'index.ts' || func === 'index.js') return; - try { - const funcRequire: Function = require(`./functions/${func}`).default; - this.functions.set(func.split('.')[0], funcRequire); - } catch (error) { - this.signale.error(`Error occured loading ${func}`); - await this.util.handleError(error); - } - }); - } - - public loadCommand(CommandFile: any) { - // eslint-disable-next-line no-useless-catch - try { - // eslint-disable-next-line - const command: Command = new CommandFile(this); - if (command.subcmds.length) { - command.subcmds.forEach((C) => { - const cmd: Command = new C(this); - command.subcommands.add(cmd.name, cmd); - }); - } - delete command.subcmds; - this.commands.add(command.name, command); - this.signale.complete(`Loaded command ${command.name}`); - } catch (err) { throw err; } - } - - public async init() { - const evtFiles = await fs.readdir('./events/'); - Object.values(commands).forEach((c: Function) => this.loadCommand(c)); - - evtFiles.forEach((file) => { - const eventName = file.split('.')[0]; - if (file === 'index.js') return; - // eslint-disable-next-line - const event = new (require(`./events/${file}`).default)(this); - this.signale.complete(`Loaded event ${eventName}`); - this.on(eventName, (...args) => event.run(...args)); - delete require.cache[require.resolve(`./events/${file}`)]; - }); - - await mongoose.connect(config.mongoURL, { useNewUrlParser: true, useUnifiedTopology: true }); - await this.connect(); - this.on('ready', () => { - this.signale.info(`Connected to Discord as ${this.user.username}#${this.user.discriminator}`); - }); - const intervals = await fs.readdir('./intervals'); - intervals.forEach((interval) => { - // eslint-disable-next-line - if (interval === 'index.js') return; - require(`./intervals/${interval}`).default(this); - this.signale.complete(`Loaded interval ${interval.split('.')[0]}`); - }); - this.server = new Server(this, { port: this.config.port }); - // eslint-disable-next-line no-new - new CSCLI(this); - - const corepath = '/opt/CloudServices/dist'; - const cmdFiles = await fs.readdir('/opt/CloudServices/dist/commands'); - cmdFiles.forEach((f) => delete require.cache[`${corepath}/${f}`]); - delete require.cache[`${corepath}/config.json`]; - delete require.cache[`${corepath}/class/Util`]; - } -} - -// eslint-disable-next-line -new Client(); diff --git a/src/api/Security.ts b/src/api/Security.ts deleted file mode 100644 index 5488662..0000000 --- a/src/api/Security.ts +++ /dev/null @@ -1,77 +0,0 @@ -/* eslint-disable no-underscore-dangle */ -import crypto from 'crypto'; -import { Request } from 'express'; -import { Client } from '..'; -import { AccountInterface } from '../models'; - -export default class Security { - public client: Client; - - protected readonly keyBase: { key: string, iv: string }; - - constructor(client: Client) { - this.client = client; - this.keyBase = require(`${process.cwd()}/keys.json`); - } - - get keys() { - return { - key: Buffer.from(this.keyBase.key, 'base64'), - iv: Buffer.from(this.keyBase.iv, 'base64'), - }; - } - - /** - * Creates a new Bearer token. - * @param _id The Mongoose Document property labeled ._id - */ - public async createBearer(_id: string): Promise { - let account = await this.client.db.Account.findOne({ _id }); - if (!account) throw new Error(`Account [${_id}] cannot be found.`); - const salt = crypto.randomBytes(50).toString('base64'); - const cipher = crypto.createCipheriv('aes-256-gcm', this.keys.key, this.keys.iv); - await account.updateOne({ salt }); - account = await this.client.db.Account.findOne({ _id }); - let encrypted = cipher.update(JSON.stringify(account), 'utf8', 'base64'); - encrypted += cipher.final('base64'); - await account.updateOne({ authTag: cipher.getAuthTag() }); - return `${salt}:${encrypted}`; - } - - /** - * If the bearer token is valid, will return the Account, else will return null. - * @param bearer The bearer token provided. - */ - public async checkBearer(bearer: string): Promise { - const decipher = crypto.createDecipheriv('aes-256-gcm', this.keys.key, this.keys.iv); - try { - const salt = bearer.split(':')[0]; - const saltCheck = await this.client.db.Account.findOne({ salt }); - const encrypted = bearer.split(':')[1]; - let decrypted = decipher.update(encrypted, 'base64', 'utf8'); - decipher.setAuthTag(saltCheck.authTag); - decrypted += decipher.final('utf8'); - const json = JSON.parse(decrypted); - const account = await this.client.db.Account.findOne({ username: json.username }); - if (saltCheck.salt !== account.salt) return null; - return account; - } catch (error) { - this.client.util.handleError(error); - return null; - } - } - - /** - * Returns the Bearer token, searches in headers and query. - * @param req The Request object from Express. - */ - public extractBearer(req: Request): string { - if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') { - return req.headers.authorization.split(' ')[1]; - } - if (req.query && req.query.token) { - return req.query.token as string; - } - return '0000000000'; - } -} diff --git a/src/api/Server.ts b/src/api/Server.ts deleted file mode 100644 index db55dcf..0000000 --- a/src/api/Server.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* eslint-disable no-useless-return */ -import express from 'express'; -import bodyParser from 'body-parser'; -import helmet from 'helmet'; -import fs from 'fs-extra'; -import { Client } from '..'; -import { Security } from '.'; -import { Collection, Route } from '../class'; - -export default class Server { - public routes: Collection - - public client: Client; - - public security: Security; - - public app: express.Express; - - public options: { port: number } - - constructor(client: Client, options?: { port: number }) { - this.options = options; - this.routes = new Collection(); - this.client = client; - this.security = new Security(this.client); - this.app = express(); - this.connect(); - this.loadRoutes(); - } - - private async loadRoutes(): Promise { - const routes = await fs.readdir(`${__dirname}/routes`); - routes.forEach(async (routeFile) => { - if (routeFile === 'index.js') return; - try { - // eslint-disable-next-line new-cap - const route: Route = new (require(`${__dirname}/routes/${routeFile}`).default)(this); - if (route.conf.deprecated === true) { - route.deprecated(); - } else if (route.conf.maintenance === true) { - route.maintenance(); - } else { - route.bind(); - } - this.routes.set(route.conf.path, route); - this.app.use(route.conf.path, route.router); - this.client.signale.success(`Successfully loaded route ${route.conf.path}`); - } catch (error) { - this.client.util.handleError(error); - } - }); - } - - private connect(): void { - this.app.set('trust proxy', 'loopback'); - this.app.use(helmet({ - hsts: false, - hidePoweredBy: false, - contentSecurityPolicy: { - directives: { - defaultSrc: ["'self'"], - }, - }, - })); - this.app.use(bodyParser.json()); - this.app.listen(this.options.port, () => { - this.client.signale.success(`API Server listening on port ${this.options.port}`); - }); - } -} diff --git a/src/class/Client.ts b/src/class/Client.ts index 5ca7265..74dfe45 100644 --- a/src/class/Client.ts +++ b/src/class/Client.ts @@ -66,11 +66,11 @@ export default class Client extends Eris.Client { } private async loadFunctions() { - const functions = await fs.readdir('./functions'); + const functions = await fs.readdir('../functions'); functions.forEach(async (func) => { if (func === 'index.ts' || func === 'index.js') return; try { - const funcRequire: Function = require(`./functions/${func}`).default; + const funcRequire: Function = require(`../functions/${func}`).default; this.functions.set(func.split('.')[0], funcRequire); } catch (error) { this.signale.error(`Error occured loading ${func}`); @@ -97,17 +97,17 @@ export default class Client extends Eris.Client { } public async init() { - const evtFiles = await fs.readdir('./events/'); + const evtFiles = await fs.readdir('../events/'); Object.values(commands).forEach((c: Function) => this.loadCommand(c)); evtFiles.forEach((file) => { const eventName = file.split('.')[0]; if (file === 'index.js') return; // eslint-disable-next-line - const event = new (require(`./events/${file}`).default)(this); + const event = new (require(`../events/${file}`).default)(this); this.signale.complete(`Loaded event ${eventName}`); this.on(eventName, (...args) => event.run(...args)); - delete require.cache[require.resolve(`./events/${file}`)]; + delete require.cache[require.resolve(`../events/${file}`)]; }); await mongoose.connect(config.mongoURL, { useNewUrlParser: true, useUnifiedTopology: true }); @@ -115,11 +115,11 @@ export default class Client extends Eris.Client { this.on('ready', () => { this.signale.info(`Connected to Discord as ${this.user.username}#${this.user.discriminator}`); }); - const intervals = await fs.readdir('./intervals'); + const intervals = await fs.readdir('../intervals'); intervals.forEach((interval) => { // eslint-disable-next-line if (interval === 'index.js') return; - require(`./intervals/${interval}`).default(this); + require(`../intervals/${interval}`).default(this); this.signale.complete(`Loaded interval ${interval.split('.')[0]}`); }); this.server = new Server(this, { port: this.config.port }); diff --git a/src/class/Command.ts b/src/class/Command.ts index 3c987de..bbf3ecf 100644 --- a/src/class/Command.ts +++ b/src/class/Command.ts @@ -1,6 +1,5 @@ -import { Message, TextableChannel, Textable } from 'eris'; -import { Client } from '..'; -import { Collection } from '.'; +import { Message, TextableChannel } from 'eris'; +import { Client, Collection } from '.'; export default class Command { name: string diff --git a/src/class/Route.ts b/src/class/Route.ts index d96e24b..1374644 100644 --- a/src/class/Route.ts +++ b/src/class/Route.ts @@ -1,6 +1,6 @@ /* eslint-disable consistent-return */ import { Request, Response, NextFunction, Router as router } from 'express'; -import { Server } from '../api'; +import { Server } from '.'; export default class Route { public server: Server; diff --git a/src/class/Security.ts b/src/class/Security.ts index 5488662..7dee703 100644 --- a/src/class/Security.ts +++ b/src/class/Security.ts @@ -1,7 +1,7 @@ /* eslint-disable no-underscore-dangle */ import crypto from 'crypto'; import { Request } from 'express'; -import { Client } from '..'; +import { Client } from '.'; import { AccountInterface } from '../models'; export default class Security { diff --git a/src/class/Server.ts b/src/class/Server.ts index ded4c5f..ce4c056 100644 --- a/src/class/Server.ts +++ b/src/class/Server.ts @@ -3,9 +3,9 @@ import express from 'express'; import bodyParser from 'body-parser'; import helmet from 'helmet'; import fs from 'fs-extra'; -import { Client } from '..'; +import { Client, Collection, Route } from '.'; import { Security } from '../api'; -import { Collection, Route } from '.'; + export default class Server { public routes: Collection diff --git a/src/class/Util.ts b/src/class/Util.ts index db66f7d..afa999c 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -7,9 +7,8 @@ import { Message, PrivateChannel, GroupChannel, Member, User } from 'eris'; import uuid from 'uuid/v4'; import moment from 'moment'; import fs from 'fs'; -import { Client } from '..'; import { getUserByUid } from '../functions'; -import { AccountUtil, Command, RichEmbed } from '.'; +import { AccountUtil, Client, Command, RichEmbed } from '.'; import { ModerationInterface, AccountInterface, Account } from '../models'; export default class Util { diff --git a/src/class/index.ts b/src/class/index.ts index c40f8ca..4e0bb2e 100644 --- a/src/class/index.ts +++ b/src/class/index.ts @@ -4,4 +4,6 @@ export { default as Collection } from './Collection'; export { default as Command } from './Command'; export { default as RichEmbed } from './RichEmbed'; export { default as Route } from './Route'; +export { default as Security } from './Security'; +export { default as Server } from './Server'; export { default as Util } from './Util'; diff --git a/src/commands/announce.ts b/src/commands/announce.ts index 47bc21f..5ee1d2c 100644 --- a/src/commands/announce.ts +++ b/src/commands/announce.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Client } from '..'; -import { Command } from '../class'; +import { Client, Command } from '../class'; export default class Announce extends Command { constructor(client: Client) { diff --git a/src/commands/bearer.ts b/src/commands/bearer.ts index 19751c9..4cd92d0 100644 --- a/src/commands/bearer.ts +++ b/src/commands/bearer.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Command } from '../class'; -import { Client } from '..'; +import { Client, Command } from '../class'; export default class Bearer extends Command { constructor(client: Client) { diff --git a/src/commands/cloudflare.ts b/src/commands/cloudflare.ts index f912733..6415dda 100644 --- a/src/commands/cloudflare.ts +++ b/src/commands/cloudflare.ts @@ -1,7 +1,6 @@ import axios from 'axios'; import { Message } from 'eris'; -import { Client } from '..'; -import { Command } from '../class'; +import { Client, Command } from '../class'; export default class Cloudflare extends Command { constructor(client: Client) { diff --git a/src/commands/createaccount.ts b/src/commands/createaccount.ts index d3bba47..1ca5b34 100644 --- a/src/commands/createaccount.ts +++ b/src/commands/createaccount.ts @@ -1,6 +1,5 @@ import { Message, PrivateChannel, GroupChannel } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; +import { Client, Command } from '../class'; export default class CreateAccount extends Command { constructor(client: Client) { diff --git a/src/commands/cwg.ts b/src/commands/cwg.ts index b7a4ade..662e77d 100644 --- a/src/commands/cwg.ts +++ b/src/commands/cwg.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Command } from '../class'; -import { Client } from '..'; +import { Client, Command } from '../class'; import Create from './cwg_create'; import Data from './cwg_data'; import Delete from './cwg_delete'; diff --git a/src/commands/cwg_create.ts b/src/commands/cwg_create.ts index ffaa006..2ace78e 100644 --- a/src/commands/cwg_create.ts +++ b/src/commands/cwg_create.ts @@ -3,8 +3,7 @@ import axios from 'axios'; import { randomBytes } from 'crypto'; import { Message } from 'eris'; import { AccountInterface } from '../models'; -import { Command, RichEmbed } from '../class'; -import { Client } from '..'; +import { Client, Command, RichEmbed } from '../class'; import { parseCertificate } from '../functions'; export default class CWG_Create extends Command { diff --git a/src/commands/cwg_data.ts b/src/commands/cwg_data.ts index cfae12c..d3f8a8a 100644 --- a/src/commands/cwg_data.ts +++ b/src/commands/cwg_data.ts @@ -3,8 +3,7 @@ import moment from 'moment'; import x509 from '@ghaiklor/x509'; import { createPaginationEmbed } from 'eris-pagination'; import { Message } from 'eris'; -import { Command, RichEmbed } from '../class'; -import { Client } from '..'; +import { Client, Command, RichEmbed } from '../class'; export default class CWG_Data extends Command { constructor(client: Client) { diff --git a/src/commands/cwg_delete.ts b/src/commands/cwg_delete.ts index ab6af76..a1c50f1 100644 --- a/src/commands/cwg_delete.ts +++ b/src/commands/cwg_delete.ts @@ -1,8 +1,7 @@ import fs from 'fs-extra'; import axios from 'axios'; import { Message } from 'eris'; -import { Command, RichEmbed } from '../class'; -import { Client } from '..'; +import { Client, Command, RichEmbed } from '../class'; export default class CWG_Delete extends Command { constructor(client: Client) { diff --git a/src/commands/cwg_updatecert.ts b/src/commands/cwg_updatecert.ts index 2fbc230..9e3bd7d 100644 --- a/src/commands/cwg_updatecert.ts +++ b/src/commands/cwg_updatecert.ts @@ -1,8 +1,7 @@ import { writeFile, unlink } from 'fs-extra'; import axios from 'axios'; import { Message } from 'eris'; -import { Command } from '../class'; -import { Client } from '..'; +import { Client, Command } from '../class'; export default class CWG_UpdateCert extends Command { constructor(client: Client) { diff --git a/src/commands/deleteaccount.ts b/src/commands/deleteaccount.ts index 28a4431..b3818ca 100644 --- a/src/commands/deleteaccount.ts +++ b/src/commands/deleteaccount.ts @@ -1,7 +1,6 @@ import { Message, PrivateChannel } from 'eris'; import uuid from 'uuid/v4'; -import { Command } from '../class'; -import { Client } from '..'; +import { Client, Command } from '../class'; export default class DeleteAccount extends Command { constructor(client: Client) { diff --git a/src/commands/emailcode.ts b/src/commands/emailcode.ts index 6ba4475..6e3901e 100644 --- a/src/commands/emailcode.ts +++ b/src/commands/emailcode.ts @@ -1,7 +1,6 @@ import { randomBytes } from 'crypto'; import { Message } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; +import { Client, Command } from '../class'; export default class EmailCode extends Command { constructor(client: Client) { diff --git a/src/commands/eval.ts b/src/commands/eval.ts index 495b141..7ed5f07 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -2,8 +2,7 @@ import axios from 'axios'; import { Message } from 'eris'; import { inspect } from 'util'; -import { Client } from '..'; -import { Command } from '../class'; +import { Client, Command } from '../class'; export default class Eval extends Command { constructor(client: Client) { diff --git a/src/commands/exec.ts b/src/commands/exec.ts index 2dc185a..40bc6d1 100644 --- a/src/commands/exec.ts +++ b/src/commands/exec.ts @@ -1,7 +1,6 @@ import { Message } from 'eris'; import axios from 'axios'; -import { Client } from '..'; -import { Command } from '../class'; +import { Client, Command } from '../class'; export default class Exec extends Command { constructor(client: Client) { diff --git a/src/commands/help.ts b/src/commands/help.ts index e28b118..e450d2b 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -1,7 +1,6 @@ import { Message } from 'eris'; import { createPaginationEmbed } from 'eris-pagination'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; +import { Client, Command, RichEmbed } from '../class'; export default class Help extends Command { constructor(client: Client) { diff --git a/src/commands/index.ts b/src/commands/index.ts index 36aa044..029babf 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -4,7 +4,6 @@ export { default as cloudflare } from './cloudflare'; export { default as createaccount } from './createaccount'; export { default as cwg } from './cwg'; export { default as deleteaccount } from './deleteaccount'; -export { default as disk } from './disk'; export { default as emailcode } from './emailcode'; export { default as eval } from './eval'; export { default as exec } from './exec'; @@ -14,13 +13,10 @@ export { default as load } from './load'; export { default as lock } from './lock'; export { default as modlogs } from './modlogs'; export { default as notify } from './notify'; -export { default as parse } from './parse'; -export { default as parseall } from './parseall'; export { default as ping } from './ping'; export { default as pull } from './pull'; export { default as resetpassword } from './resetpassword'; export { default as restart } from './restart'; -export { default as securesign } from './securesign'; export { default as setlimit } from './setlimit'; export { default as sysinfo } from './sysinfo'; export { default as systemd } from './systemd'; @@ -29,4 +25,3 @@ export { default as unban } from './unban'; export { default as unlock } from './unlock'; export { default as warn } from './warn'; export { default as whois } from './whois'; -export { default as whoisold } from './whoisold'; diff --git a/src/commands/limits.ts b/src/commands/limits.ts index 1db6bf4..468b6de 100644 --- a/src/commands/limits.ts +++ b/src/commands/limits.ts @@ -1,8 +1,7 @@ import { Message } from 'eris'; -import { Command, RichEmbed } from '../class'; +import { Client, Command, RichEmbed } from '../class'; import { dataConversion } from '../functions'; import setRamNotification from './limits_setramnotification'; -import { Client } from '..'; export default class Limits extends Command { constructor(client: Client) { diff --git a/src/commands/limits_setramnotification.ts b/src/commands/limits_setramnotification.ts index bc8e18f..ae78ae6 100644 --- a/src/commands/limits_setramnotification.ts +++ b/src/commands/limits_setramnotification.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Command, RichEmbed } from '../class'; -import { Client } from '..'; +import { Client, Command } from '../class'; export default class Limits_SetRAMNotification extends Command { constructor(client: Client) { diff --git a/src/commands/load.ts b/src/commands/load.ts index 98d4d0f..915dc2c 100644 --- a/src/commands/load.ts +++ b/src/commands/load.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Client } from '..'; -import { Command } from '../class'; +import { Client, Command } from '../class'; export default class Load extends Command { constructor(client: Client) { diff --git a/src/commands/lock.ts b/src/commands/lock.ts index 10ccc77..831dbad 100644 --- a/src/commands/lock.ts +++ b/src/commands/lock.ts @@ -1,7 +1,6 @@ import moment, { unitOfTime } from 'moment'; import { Message } from 'eris'; -import { Client } from '..'; -import { Command } from '../class'; +import { Client, Command } from '../class'; export default class Lock extends Command { constructor(client: Client) { diff --git a/src/commands/modlogs.ts b/src/commands/modlogs.ts index bc13075..10d552f 100644 --- a/src/commands/modlogs.ts +++ b/src/commands/modlogs.ts @@ -1,7 +1,6 @@ import { Message } from 'eris'; import { createPaginationEmbed } from 'eris-pagination'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; +import { Client, Command, RichEmbed } from '../class'; export default class Modlogs extends Command { constructor(client: Client) { diff --git a/src/commands/notify.ts b/src/commands/notify.ts index 002c86b..df7d76b 100644 --- a/src/commands/notify.ts +++ b/src/commands/notify.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; +import { Client, Command, RichEmbed } from '../class'; export default class Notify extends Command { constructor(client: Client) { diff --git a/src/commands/ping.ts b/src/commands/ping.ts index a7c956d..76e3403 100644 --- a/src/commands/ping.ts +++ b/src/commands/ping.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Client } from '..'; -import { Command } from '../class'; +import { Client, Command } from '../class'; export default class Ping extends Command { constructor(client: Client) { diff --git a/src/commands/pull.ts b/src/commands/pull.ts index 557b54f..9c9ec1c 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -1,7 +1,6 @@ import { Message } from 'eris'; import axios from 'axios'; -import { Client } from '..'; -import { Command } from '../class'; +import { Client, Command } from '../class'; export default class Pull extends Command { constructor(client: Client) { diff --git a/src/commands/resetpassword.ts b/src/commands/resetpassword.ts index ea48bfc..eb9b8fd 100644 --- a/src/commands/resetpassword.ts +++ b/src/commands/resetpassword.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Client } from '..'; -import { Command } from '../class'; +import { Client, Command } from '../class'; export default class ResetPassword extends Command { constructor(client: Client) { diff --git a/src/commands/restart.ts b/src/commands/restart.ts index 31847d1..38050a7 100644 --- a/src/commands/restart.ts +++ b/src/commands/restart.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Client } from '..'; -import { Command } from '../class'; +import { Client, Command } from '../class'; export default class Restart extends Command { constructor(client: Client) { diff --git a/src/commands/setlimit.ts b/src/commands/setlimit.ts index 60fd53b..e706b47 100644 --- a/src/commands/setlimit.ts +++ b/src/commands/setlimit.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Command } from '../class'; -import { Client } from '..'; +import { Client, Command } from '../class'; import SetLimit_RAM from './setlimit_ram'; export default class SetLimit extends Command { diff --git a/src/commands/setlimit_ram.ts b/src/commands/setlimit_ram.ts index 537f193..321216e 100644 --- a/src/commands/setlimit_ram.ts +++ b/src/commands/setlimit_ram.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Command } from '../class'; -import { Client } from '..'; +import { Client, Command } from '../class'; export default class SetLimit_RAM extends Command { constructor(client: Client) { diff --git a/src/commands/sysinfo.ts b/src/commands/sysinfo.ts index bf79eee..474a5eb 100644 --- a/src/commands/sysinfo.ts +++ b/src/commands/sysinfo.ts @@ -1,9 +1,8 @@ import moment from 'moment'; import { Message } from 'eris'; import os, { totalmem } from 'os'; -import { Command, RichEmbed } from '../class'; +import { Client, Command, RichEmbed } from '../class'; import { dataConversion } from '../functions'; -import { Client } from '..'; export default class SysInfo extends Command { constructor(client: Client) { diff --git a/src/commands/systemd.ts b/src/commands/systemd.ts index 643eb89..a157518 100644 --- a/src/commands/systemd.ts +++ b/src/commands/systemd.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Command } from '../class'; -import { Client } from '..'; +import { Client, Command } from '../class'; import SystemD_Linger from './systemd_linger'; export default class SystemD extends Command { diff --git a/src/commands/systemd_linger.ts b/src/commands/systemd_linger.ts index f77eb79..bf764f0 100644 --- a/src/commands/systemd_linger.ts +++ b/src/commands/systemd_linger.ts @@ -1,7 +1,6 @@ /* eslint-disable consistent-return */ import { Message } from 'eris'; -import { Command } from '../class'; -import { Client } from '..'; +import { Client, Command } from '../class'; export default class SystemdD_Linger extends Command { constructor(client: Client) { diff --git a/src/commands/tier.ts b/src/commands/tier.ts index c6cf932..d30de9e 100644 --- a/src/commands/tier.ts +++ b/src/commands/tier.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; +import { Client, Command, RichEmbed } from '../class'; export default class Tier extends Command { constructor(client: Client) { diff --git a/src/commands/unban.ts b/src/commands/unban.ts index fca5352..0e62126 100644 --- a/src/commands/unban.ts +++ b/src/commands/unban.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Client } from '..'; -import { Command } from '../class'; +import { Client, Command } from '../class'; export default class Unban extends Command { constructor(client: Client) { diff --git a/src/commands/unlock.ts b/src/commands/unlock.ts index e068f92..f4b26a8 100644 --- a/src/commands/unlock.ts +++ b/src/commands/unlock.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Client } from '..'; -import { Command } from '../class'; +import { Client, Command } from '../class'; export default class Unlock extends Command { constructor(client: Client) { diff --git a/src/commands/warn.ts b/src/commands/warn.ts index 7e421f9..607f5c9 100644 --- a/src/commands/warn.ts +++ b/src/commands/warn.ts @@ -1,6 +1,5 @@ import { Message } from 'eris'; -import { Client } from '..'; -import { Command } from '../class'; +import { Client, Command } from '../class'; export default class Warn extends Command { constructor(client: Client) { diff --git a/src/commands/whois.ts b/src/commands/whois.ts index 25a1de7..51a9b12 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -1,7 +1,6 @@ import moment from 'moment'; import { Message, GuildTextableChannel, Member, Role } from 'eris'; -import { Client } from '..'; -import { Command, RichEmbed } from '../class'; +import { Client, Command, RichEmbed } from '../class'; import { dataConversion } from '../functions'; import { AccountInterface } from '../models'; diff --git a/src/cscli/main.ts b/src/cscli/main.ts index bf864de..5a4c02f 100644 --- a/src/cscli/main.ts +++ b/src/cscli/main.ts @@ -3,7 +3,7 @@ import net from 'net'; import crypto from 'crypto'; import { promises as fs } from 'fs'; -import Client from '../Client'; +import Client from '../class/Client'; import { dataConversion } from '../functions'; export default class CSCLI { diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts index 39684d7..21b303c 100644 --- a/src/events/messageCreate.ts +++ b/src/events/messageCreate.ts @@ -1,6 +1,5 @@ import { Message, TextChannel } from 'eris'; -import { Client } from '..'; -import Command from '../class/Command'; +import { Client } from '../class'; export default class { public client: Client @@ -25,7 +24,6 @@ export default class { if (resolved.cmd.permissions.roles) { for (const role of resolved.cmd.permissions.roles) { if (message.member && message.member.roles.includes(role)) { - // this.client.signale.debug(message.member.roles.includes(role)); hasRolePerms = true; break; } } diff --git a/src/functions/existingLimitsSetup.ts b/src/functions/existingLimitsSetup.ts index fb2e918..5946ae8 100644 --- a/src/functions/existingLimitsSetup.ts +++ b/src/functions/existingLimitsSetup.ts @@ -1,5 +1,5 @@ /* eslint-disable no-await-in-loop */ -import { Client } from '..'; +import { Client } from '../class'; export default async function existingLimitsSetup(client: Client): Promise { const tier1 = await client.db.Tier.findOne({ id: 1 }); diff --git a/src/functions/getUserByUid.ts b/src/functions/getUserByUid.ts index b56c148..f8033c3 100644 --- a/src/functions/getUserByUid.ts +++ b/src/functions/getUserByUid.ts @@ -1,4 +1,4 @@ -import { Client } from '..'; +import { Client } from '../class'; export default async function getUserByUid(client: Client, uid: number): Promise { const res = await client.util.exec(`${__dirname}/../bin/getUserByUid ${uid}`); diff --git a/src/functions/index.ts b/src/functions/index.ts index 6abf234..4c6b3f0 100644 --- a/src/functions/index.ts +++ b/src/functions/index.ts @@ -2,5 +2,4 @@ export { default as checkLock, clear as clearLock } from '../intervals/checkLock export { default as dataConversion } from './dataConversion'; export { default as existingLimitsSetup } from './existingLimitsSetup'; export { default as getUserByUid } from './getUserByUid'; -// export { default as checkSS, clear as clearSS } from './checkSS'; export { default as parseCertificate, Certificate } from './parseCertificate'; diff --git a/src/functions/parseCertificate.ts b/src/functions/parseCertificate.ts index f9d78ca..b474d5b 100644 --- a/src/functions/parseCertificate.ts +++ b/src/functions/parseCertificate.ts @@ -1,4 +1,4 @@ -import { Client } from '..'; +import { Client } from '../class'; export interface Certificate { subject: { diff --git a/src/index.ts b/src/index.ts index 4147cc3..a58f8ab 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -export { default as Client } from './class/Client'; +// export { default as Client } from './class/Client'; // eslint-disable-next-line import/no-unresolved export { default as config } from './config.json'; export * from './class'; diff --git a/src/intervals/checkLock.ts b/src/intervals/checkLock.ts index da8d33f..e3b0277 100644 --- a/src/intervals/checkLock.ts +++ b/src/intervals/checkLock.ts @@ -1,4 +1,4 @@ -import { Client } from '..'; +import { Client } from '../class'; let interval: NodeJS.Timeout; diff --git a/src/intervals/checkSS.ts b/src/intervals/checkSS.ts deleted file mode 100644 index 39cee9d..0000000 --- a/src/intervals/checkSS.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* eslint-disable consistent-return */ -/* eslint-disable no-unreachable */ -/* eslint-disable no-await-in-loop */ -import axios from 'axios'; -import { inspect } from 'util'; -import { Client } from '..'; - -let interval: NodeJS.Timeout; -export default function checkSS(client: Client) { - return; - interval = setInterval(async () => { - try { - const accounts = await client.db.Account.find(); - for (const { userID, homepath, hash } of accounts) { - try { - const Authorization = client.util.getAcctHash(homepath); - if (hash === null) throw new Error('Unable to locate auth file, homepath is probably incorrect'); - await axios({ - method: 'get', - url: 'https://api.securesign.org/account/details', - headers: { Authorization }, - }); - if (!hash) { - await client.db.Account.updateOne({ userID }, { $set: { hash: true } }); - client.getDMChannel(userID).then((channel) => channel.createMessage('Your SecureSign account has been automatically initialized via the SecureSign CLI.')).catch(); - } - } catch (error) { - if (!hash) return; - try { - const { status } = error.response; - if (status === 400 || status === 401 || status === 403 || status === 404) { - await client.db.Account.updateOne({ userID }, { $set: { hash: false } }); - client.getDMChannel(userID).then((channel) => channel.createMessage('Your SecureSign password has been reset - please reinitialize your SecureSign account. Run `=securesign init` for more information')).catch(); - } - } catch (e) { - throw error; - } - } - } - } catch (error) { - client.util.handleError(error); - } - }, 60000); - return interval; -} - -export function clear() { - clearTimeout(interval); -} diff --git a/src/intervals/checkStaffStatus.ts b/src/intervals/checkStaffStatus.ts index 6ea44e2..1b46eab 100644 --- a/src/intervals/checkStaffStatus.ts +++ b/src/intervals/checkStaffStatus.ts @@ -1,6 +1,5 @@ /* eslint-disable no-await-in-loop */ -import { Client } from '..'; -import { RichEmbed } from '../class'; +import { Client, RichEmbed } from '../class'; export default function checkStaffStatus(client: Client) { setInterval(async () => { diff --git a/src/intervals/memory.ts b/src/intervals/memory.ts index eea94ed..92ba296 100644 --- a/src/intervals/memory.ts +++ b/src/intervals/memory.ts @@ -1,8 +1,7 @@ /* eslint-disable no-useless-escape */ /* eslint-disable no-continue */ /* eslint-disable no-await-in-loop */ -import { Client } from '..'; -import { RichEmbed } from '../class'; +import { Client, RichEmbed } from '../class'; import { Tiers } from '../models'; const channelID = '691824484230889546'; diff --git a/src/intervals/storage.ts b/src/intervals/storage.ts index 488a578..e8ef484 100644 --- a/src/intervals/storage.ts +++ b/src/intervals/storage.ts @@ -1,7 +1,7 @@ /* eslint-disable no-await-in-loop */ // import fs from 'fs-extra'; import { spawn } from 'child_process'; -import { Client } from '..'; +import { Client } from '../class'; export default async function storage(client: Client) { let storageGo = spawn(`${__dirname}/../bin/storage`, [], { cwd: __dirname }); -- 2.20.1 From b15b7b514f35b5994124ca6d527de4a1d05f6f97 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 03:00:27 -0400 Subject: [PATCH 309/516] fixes --- src/class/Client.ts | 269 ++++++++++++++++++++++---------------------- src/cscli/main.ts | 170 ++++++++++++++-------------- 2 files changed, 219 insertions(+), 220 deletions(-) diff --git a/src/class/Client.ts b/src/class/Client.ts index 74dfe45..4f314c6 100644 --- a/src/class/Client.ts +++ b/src/class/Client.ts @@ -1,135 +1,134 @@ -import Eris from 'eris'; -import Redis from 'ioredis'; -import mongoose from 'mongoose'; -import signale from 'signale'; -import fs from 'fs-extra'; -import config from '../config.json'; -import CSCLI from '../cscli/main'; -import { Server } from '../api'; -import { Account, AccountInterface, Moderation, ModerationInterface, Domain, DomainInterface, Tier, TierInterface } from '../models'; -import { emojis } from '../stores'; -import { Command, Util, Collection } from '.'; -import * as commands from '../commands'; - - -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; }; }; - - public util: Util; - - public commands: Collection; - - public db: { Account: mongoose.Model; Domain: mongoose.Model; Moderation: mongoose.Model; Tier: mongoose.Model; }; - - public redis: Redis.Redis; - - public stores: { emojis: { success: string, loading: string, error: string }; }; - - public functions: Collection; - - public signale: signale.Signale; - - public server: Server; - - public updating: boolean; - - public buildError: boolean - - constructor() { - super(config.token, { getAllUsers: true, restMode: true, defaultImageFormat: 'png' }); - - process.title = 'cloudservices'; - this.config = config; - this.util = new Util(this); - this.commands = new Collection(); - this.functions = new Collection(); - this.db = { Account, Domain, Moderation, Tier }; - this.redis = new Redis(); - this.stores = { emojis }; - this.signale = signale; - this.signale.config({ - displayDate: true, - displayTimestamp: true, - displayFilename: true, - }); - this.updating = false; - this.buildError = false; - this.events(); - this.loadFunctions(); - this.init(); - } - - private async events() { - process.on('unhandledRejection', (error) => { - this.signale.error(error); - }); - } - - private async loadFunctions() { - const functions = await fs.readdir('../functions'); - functions.forEach(async (func) => { - if (func === 'index.ts' || func === 'index.js') return; - try { - const funcRequire: Function = require(`../functions/${func}`).default; - this.functions.set(func.split('.')[0], funcRequire); - } catch (error) { - this.signale.error(`Error occured loading ${func}`); - await this.util.handleError(error); - } - }); - } - - public loadCommand(CommandFile: any) { - // eslint-disable-next-line no-useless-catch - try { - // eslint-disable-next-line - const command: Command = new CommandFile(this); - if (command.subcmds.length) { - command.subcmds.forEach((C) => { - const cmd: Command = new C(this); - command.subcommands.add(cmd.name, cmd); - }); - } - delete command.subcmds; - this.commands.add(command.name, command); - this.signale.complete(`Loaded command ${command.name}`); - } catch (err) { throw err; } - } - - public async init() { - const evtFiles = await fs.readdir('../events/'); - Object.values(commands).forEach((c: Function) => this.loadCommand(c)); - - evtFiles.forEach((file) => { - const eventName = file.split('.')[0]; - if (file === 'index.js') return; - // eslint-disable-next-line - const event = new (require(`../events/${file}`).default)(this); - this.signale.complete(`Loaded event ${eventName}`); - this.on(eventName, (...args) => event.run(...args)); - delete require.cache[require.resolve(`../events/${file}`)]; - }); - - await mongoose.connect(config.mongoURL, { useNewUrlParser: true, useUnifiedTopology: true }); - await this.connect(); - this.on('ready', () => { - this.signale.info(`Connected to Discord as ${this.user.username}#${this.user.discriminator}`); - }); - const intervals = await fs.readdir('../intervals'); - intervals.forEach((interval) => { - // eslint-disable-next-line - if (interval === 'index.js') return; - require(`../intervals/${interval}`).default(this); - this.signale.complete(`Loaded interval ${interval.split('.')[0]}`); - }); - this.server = new Server(this, { port: this.config.port }); - // eslint-disable-next-line no-new - new CSCLI(this); - - const corepath = '/opt/CloudServices/dist'; - const cmdFiles = await fs.readdir('/opt/CloudServices/dist/commands'); - cmdFiles.forEach((f) => delete require.cache[`${corepath}/${f}`]); - delete require.cache[`${corepath}/config.json`]; - delete require.cache[`${corepath}/class/Util`]; - } -} +import Eris from 'eris'; +import Redis from 'ioredis'; +import mongoose from 'mongoose'; +import signale from 'signale'; +import fs from 'fs-extra'; +import config from '../config.json'; +import CSCLI from '../cscli/main'; +import { Account, AccountInterface, Moderation, ModerationInterface, Domain, DomainInterface, Tier, TierInterface } from '../models'; +import { emojis } from '../stores'; +import { Command, Util, Collection, Server } from '.'; +import * as commands from '../commands'; + + +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; }; }; + + public util: Util; + + public commands: Collection; + + public db: { Account: mongoose.Model; Domain: mongoose.Model; Moderation: mongoose.Model; Tier: mongoose.Model; }; + + public redis: Redis.Redis; + + public stores: { emojis: { success: string, loading: string, error: string }; }; + + public functions: Collection; + + public signale: signale.Signale; + + public server: Server; + + public updating: boolean; + + public buildError: boolean + + constructor() { + super(config.token, { getAllUsers: true, restMode: true, defaultImageFormat: 'png' }); + + process.title = 'cloudservices'; + this.config = config; + this.util = new Util(this); + this.commands = new Collection(); + this.functions = new Collection(); + this.db = { Account, Domain, Moderation, Tier }; + this.redis = new Redis(); + this.stores = { emojis }; + this.signale = signale; + this.signale.config({ + displayDate: true, + displayTimestamp: true, + displayFilename: true, + }); + this.updating = false; + this.buildError = false; + this.events(); + this.loadFunctions(); + this.init(); + } + + private async events() { + process.on('unhandledRejection', (error) => { + this.signale.error(error); + }); + } + + private async loadFunctions() { + const functions = await fs.readdir('../functions'); + functions.forEach(async (func) => { + if (func === 'index.ts' || func === 'index.js') return; + try { + const funcRequire: Function = require(`../functions/${func}`).default; + this.functions.set(func.split('.')[0], funcRequire); + } catch (error) { + this.signale.error(`Error occured loading ${func}`); + await this.util.handleError(error); + } + }); + } + + public loadCommand(CommandFile: any) { + // eslint-disable-next-line no-useless-catch + try { + // eslint-disable-next-line + const command: Command = new CommandFile(this); + if (command.subcmds.length) { + command.subcmds.forEach((C) => { + const cmd: Command = new C(this); + command.subcommands.add(cmd.name, cmd); + }); + } + delete command.subcmds; + this.commands.add(command.name, command); + this.signale.complete(`Loaded command ${command.name}`); + } catch (err) { throw err; } + } + + public async init() { + const evtFiles = await fs.readdir('../events/'); + Object.values(commands).forEach((c: Function) => this.loadCommand(c)); + + evtFiles.forEach((file) => { + const eventName = file.split('.')[0]; + if (file === 'index.js') return; + // eslint-disable-next-line + const event = new (require(`../events/${file}`).default)(this); + this.signale.complete(`Loaded event ${eventName}`); + this.on(eventName, (...args) => event.run(...args)); + delete require.cache[require.resolve(`../events/${file}`)]; + }); + + await mongoose.connect(config.mongoURL, { useNewUrlParser: true, useUnifiedTopology: true }); + await this.connect(); + this.on('ready', () => { + this.signale.info(`Connected to Discord as ${this.user.username}#${this.user.discriminator}`); + }); + const intervals = await fs.readdir('../intervals'); + intervals.forEach((interval) => { + // eslint-disable-next-line + if (interval === 'index.js') return; + require(`../intervals/${interval}`).default(this); + this.signale.complete(`Loaded interval ${interval.split('.')[0]}`); + }); + this.server = new Server(this, { port: this.config.port }); + // eslint-disable-next-line no-new + new CSCLI(this); + + const corepath = '/opt/CloudServices/dist'; + const cmdFiles = await fs.readdir('/opt/CloudServices/dist/commands'); + cmdFiles.forEach((f) => delete require.cache[`${corepath}/${f}`]); + delete require.cache[`${corepath}/config.json`]; + delete require.cache[`${corepath}/class/Util`]; + } +} diff --git a/src/cscli/main.ts b/src/cscli/main.ts index 5a4c02f..73d8a56 100644 --- a/src/cscli/main.ts +++ b/src/cscli/main.ts @@ -1,85 +1,85 @@ -/* eslint-disable no-case-declarations */ -/* eslint-disable consistent-return */ -import net from 'net'; -import crypto from 'crypto'; -import { promises as fs } from 'fs'; -import Client from '../class/Client'; -import { dataConversion } from '../functions'; - -export default class CSCLI { - public client: Client; - - public server: net.Server; - - #hmac: string; - - constructor(client: Client) { - this.client = client; - this.loadKeys(); - this.server = net.createServer((socket) => { - socket.on('data', async (data) => { - try { - await this.handle(socket, data); - } catch (err) { - await this.client.util.handleError(err); - socket.destroy(); - } - }); - }); - this.init(); - } - - public async handle(socket: net.Socket, data: Buffer) { - const args = data.toString().trim().split('$'); - const verification = this.verifyConnection(args[1], args[0]); - if (!verification) { - socket.write('UNAUTHORIZED TO EXECUTE ON THIS SERVER\n'); - return socket.destroy(); - } - const parsed: { Username: string, Type: string, Message?: string, HMAC: string } = JSON.parse(args[0]); - // FINISH VERIFICATION CHECKS - switch (parsed.Type) { - case 'lock': - await this.client.util.accounts.lock(parsed.Username, this.client.user.id, { reason: parsed.Message }); - break; - case 'killpid': - await this.client.util.exec(`kill -9 ${parsed.Message}`); - break; - case 'ram': - const memoryConversion = dataConversion(Number(await this.client.util.exec(`memory ${parsed.Username}`)) * 1000); - socket.write(`${memoryConversion}\n`); - socket.destroy(); - break; - case 'storage': - const res = await this.client.redis.get(`storage-${parsed.Username}`) ? dataConversion(Number(await this.client.redis.get(`storage-${parsed.Username}`))) : 'N/A'; - socket.write(`${res}\n`); - socket.destroy(); - break; - default: - socket.destroy(); - break; - } - } - - public verifyConnection(key: string, data: any): boolean { - const hmac = crypto.createHmac('sha256', this.#hmac); - hmac.update(data); - const computed = hmac.digest('hex'); - if (computed === key) return true; - return false; - } - - public async loadKeys() { - const key = await fs.readFile('/etc/cscli.conf', { encoding: 'utf8' }); - this.#hmac = key.toString().trim(); - } - - public init() { - this.server.on('error', (err) => { - this.client.util.handleError(err); - }); - this.server.listen(8124, () => { - this.client.signale.success('TCP socket is now listening for connections.'); - }); - } -} +/* eslint-disable no-case-declarations */ +/* eslint-disable consistent-return */ +import net from 'net'; +import crypto from 'crypto'; +import { promises as fs } from 'fs'; +import { Client } from '../class'; +import { dataConversion } from '../functions'; + +export default class CSCLI { + public client: Client; + + public server: net.Server; + + #hmac: string; + + constructor(client: Client) { + this.client = client; + this.loadKeys(); + this.server = net.createServer((socket) => { + socket.on('data', async (data) => { + try { + await this.handle(socket, data); + } catch (err) { + await this.client.util.handleError(err); + socket.destroy(); + } + }); + }); + this.init(); + } + + public async handle(socket: net.Socket, data: Buffer) { + const args = data.toString().trim().split('$'); + const verification = this.verifyConnection(args[1], args[0]); + if (!verification) { + socket.write('UNAUTHORIZED TO EXECUTE ON THIS SERVER\n'); + return socket.destroy(); + } + const parsed: { Username: string, Type: string, Message?: string, HMAC: string } = JSON.parse(args[0]); + // FINISH VERIFICATION CHECKS + switch (parsed.Type) { + case 'lock': + await this.client.util.accounts.lock(parsed.Username, this.client.user.id, { reason: parsed.Message }); + break; + case 'killpid': + await this.client.util.exec(`kill -9 ${parsed.Message}`); + break; + case 'ram': + const memoryConversion = dataConversion(Number(await this.client.util.exec(`memory ${parsed.Username}`)) * 1000); + socket.write(`${memoryConversion}\n`); + socket.destroy(); + break; + case 'storage': + const res = await this.client.redis.get(`storage-${parsed.Username}`) ? dataConversion(Number(await this.client.redis.get(`storage-${parsed.Username}`))) : 'N/A'; + socket.write(`${res}\n`); + socket.destroy(); + break; + default: + socket.destroy(); + break; + } + } + + public verifyConnection(key: string, data: any): boolean { + const hmac = crypto.createHmac('sha256', this.#hmac); + hmac.update(data); + const computed = hmac.digest('hex'); + if (computed === key) return true; + return false; + } + + public async loadKeys() { + const key = await fs.readFile('/etc/cscli.conf', { encoding: 'utf8' }); + this.#hmac = key.toString().trim(); + } + + public init() { + this.server.on('error', (err) => { + this.client.util.handleError(err); + }); + this.server.listen(8124, () => { + this.client.signale.success('TCP socket is now listening for connections.'); + }); + } +} -- 2.20.1 From 07d13f38a7521d6bd414b7a927a81815e23d1032 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 17:13:54 -0400 Subject: [PATCH 310/516] fix attempts --- src/class/Client.ts | 47 +++++++++++++++++++++---------------- src/class/Event.ts | 15 ++++++++++++ src/class/index.ts | 1 + src/events/messageCreate.ts | 6 +++-- src/main.ts | 12 +++++++++- 5 files changed, 58 insertions(+), 23 deletions(-) create mode 100644 src/class/Event.ts diff --git a/src/class/Client.ts b/src/class/Client.ts index 4f314c6..256a352 100644 --- a/src/class/Client.ts +++ b/src/class/Client.ts @@ -7,8 +7,7 @@ import config from '../config.json'; import CSCLI from '../cscli/main'; import { Account, AccountInterface, Moderation, ModerationInterface, Domain, DomainInterface, Tier, TierInterface } from '../models'; import { emojis } from '../stores'; -import { Command, Util, Collection, Server } from '.'; -import * as commands from '../commands'; +import { Command, Util, Collection, Server, Event } from '.'; export default class Client extends Eris.Client { @@ -18,6 +17,8 @@ export default class Client extends Eris.Client { public commands: Collection; + public events: Collection; + public db: { Account: mongoose.Model; Domain: mongoose.Model; Moderation: mongoose.Model; Tier: mongoose.Model; }; public redis: Redis.Redis; @@ -41,6 +42,7 @@ export default class Client extends Eris.Client { this.config = config; this.util = new Util(this); this.commands = new Collection(); + this.events = new Collection(); this.functions = new Collection(); this.db = { Account, Domain, Moderation, Tier }; this.redis = new Redis(); @@ -53,18 +55,16 @@ export default class Client extends Eris.Client { }); this.updating = false; this.buildError = false; - this.events(); - this.loadFunctions(); - this.init(); + this.errorEvents(); } - private async events() { + public async errorEvents() { process.on('unhandledRejection', (error) => { this.signale.error(error); }); } - private async loadFunctions() { + public async loadFunctions() { const functions = await fs.readdir('../functions'); functions.forEach(async (func) => { if (func === 'index.ts' || func === 'index.js') return; @@ -95,20 +95,27 @@ export default class Client extends Eris.Client { } catch (err) { throw err; } } + public async loadEvents(eventFiles: { [s: string]: typeof Event; } | ArrayLike) { + const evtFiles = Object.entries(eventFiles); + for (const [name, Ev] of evtFiles) { + const event = new Ev(this); + this.events.add(event.event, event); + this.on(event.event, event.run); + this.signale.success(`Successfully loaded event: ${name}`); + delete require.cache[require.resolve(`${__dirname}/../events/${name}`)]; + } + } + + public async loadCommands(commandFiles: { [s: string]: typeof Command; } | ArrayLike) { + const cmdFiles = Object.values(commandFiles); + for (const Cmd of cmdFiles) { + const command = new Cmd(this); + this.commands.add(command.name, command); + this.signale.success(`Successfully loaded command: ${command.name}`); + } + } + public async init() { - const evtFiles = await fs.readdir('../events/'); - Object.values(commands).forEach((c: Function) => this.loadCommand(c)); - - evtFiles.forEach((file) => { - const eventName = file.split('.')[0]; - if (file === 'index.js') return; - // eslint-disable-next-line - const event = new (require(`../events/${file}`).default)(this); - this.signale.complete(`Loaded event ${eventName}`); - this.on(eventName, (...args) => event.run(...args)); - delete require.cache[require.resolve(`../events/${file}`)]; - }); - await mongoose.connect(config.mongoURL, { useNewUrlParser: true, useUnifiedTopology: true }); await this.connect(); this.on('ready', () => { diff --git a/src/class/Event.ts b/src/class/Event.ts new file mode 100644 index 0000000..658f18c --- /dev/null +++ b/src/class/Event.ts @@ -0,0 +1,15 @@ +import { Client } from '.'; + +export default class Event { + public client: Client + + public event: string; + + constructor(client: Client) { + this.client = client; + this.event = ''; + this.run = this.run.bind(this); + } + + public async run(...args: any[]): Promise { return Promise.resolve(); } +} diff --git a/src/class/index.ts b/src/class/index.ts index 4e0bb2e..ad33446 100644 --- a/src/class/index.ts +++ b/src/class/index.ts @@ -2,6 +2,7 @@ export { default as AccountUtil } from './AccountUtil'; export { default as Client } from './Client'; export { default as Collection } from './Collection'; export { default as Command } from './Command'; +export { default as Event } from './Event'; export { default as RichEmbed } from './RichEmbed'; export { default as Route } from './Route'; export { default as Security } from './Security'; diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts index 21b303c..5c956c3 100644 --- a/src/events/messageCreate.ts +++ b/src/events/messageCreate.ts @@ -1,11 +1,13 @@ import { Message, TextChannel } from 'eris'; -import { Client } from '../class'; +import { Client, Event } from '../class'; -export default class { +export default class extends Event { public client: Client constructor(client: Client) { + super(client); this.client = client; + this.event = 'messageCreate'; } public async run(message: Message) { diff --git a/src/main.ts b/src/main.ts index e971265..65bc183 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,14 @@ import { Client } from './class'; +import * as eventFiles from './events'; +import * as commandFiles from './commands'; // eslint-disable-next-line no-new -new Client(); +async function main() { + const client = new Client(); + await client.loadCommands(commandFiles); + await client.loadEvents(eventFiles); + await client.loadFunctions(); + await client.init(); +} + +main(); -- 2.20.1 From 9e72e02e78e20159415af63519835fee9fcfba89 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 17:17:08 -0400 Subject: [PATCH 311/516] fixes for client path resolve --- src/class/Client.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/class/Client.ts b/src/class/Client.ts index 256a352..8564287 100644 --- a/src/class/Client.ts +++ b/src/class/Client.ts @@ -65,11 +65,11 @@ export default class Client extends Eris.Client { } public async loadFunctions() { - const functions = await fs.readdir('../functions'); + const functions = await fs.readdir(`${__dirname}/../functions`); functions.forEach(async (func) => { if (func === 'index.ts' || func === 'index.js') return; try { - const funcRequire: Function = require(`../functions/${func}`).default; + const funcRequire: Function = require(`${__dirname}/../functions/${func}`).default; this.functions.set(func.split('.')[0], funcRequire); } catch (error) { this.signale.error(`Error occured loading ${func}`); @@ -121,11 +121,11 @@ export default class Client extends Eris.Client { this.on('ready', () => { this.signale.info(`Connected to Discord as ${this.user.username}#${this.user.discriminator}`); }); - const intervals = await fs.readdir('../intervals'); + const intervals = await fs.readdir(`${__dirname}/../intervals`); intervals.forEach((interval) => { // eslint-disable-next-line if (interval === 'index.js') return; - require(`../intervals/${interval}`).default(this); + require(`${__dirname}/../intervals/${interval}`).default(this); this.signale.complete(`Loaded interval ${interval.split('.')[0]}`); }); this.server = new Server(this, { port: this.config.port }); -- 2.20.1 From d15932fe4789ec67da5da0a16c3bad2fcfe51780 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 17:19:14 -0400 Subject: [PATCH 312/516] fix server route resolve --- src/class/Server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/Server.ts b/src/class/Server.ts index ce4c056..f000868 100644 --- a/src/class/Server.ts +++ b/src/class/Server.ts @@ -34,7 +34,7 @@ export default class Server { if (routeFile === 'index.js') return; try { // eslint-disable-next-line new-cap - const route: Route = new (require(`${__dirname}/routes/${routeFile}`).default)(this); + const route: Route = new (require(`${__dirname}/../api/routes/${routeFile}`).default)(this); if (route.conf.deprecated === true) { route.deprecated(); } else if (route.conf.maintenance === true) { -- 2.20.1 From 1af0f58b2373817bfb7522b56a60dcdf710e86aa Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 17:20:35 -0400 Subject: [PATCH 313/516] fix server route resolve --- src/class/Server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/Server.ts b/src/class/Server.ts index f000868..9351437 100644 --- a/src/class/Server.ts +++ b/src/class/Server.ts @@ -29,7 +29,7 @@ export default class Server { } private async loadRoutes(): Promise { - const routes = await fs.readdir(`${__dirname}/routes`); + const routes = await fs.readdir(`${__dirname}/../api/routes`); routes.forEach(async (routeFile) => { if (routeFile === 'index.js') return; try { -- 2.20.1 From 47444a26ed6ee97eebe20fcfdc919482cc01be82 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 17:26:39 -0400 Subject: [PATCH 314/516] fixes for command resolve --- src/class/Client.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/class/Client.ts b/src/class/Client.ts index 8564287..5e96d72 100644 --- a/src/class/Client.ts +++ b/src/class/Client.ts @@ -110,6 +110,13 @@ export default class Client extends Eris.Client { const cmdFiles = Object.values(commandFiles); for (const Cmd of cmdFiles) { const command = new Cmd(this); + if (command.subcmds.length) { + command.subcmds.forEach((C) => { + const cmd: Command = new C(this); + command.subcommands.add(cmd.name, cmd); + }); + } + delete command.subcmds; this.commands.add(command.name, command); this.signale.success(`Successfully loaded command: ${command.name}`); } -- 2.20.1 From 59f8336d2548a01e57b669a8ec69de9baf4e931e Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 17:31:18 -0400 Subject: [PATCH 315/516] api enable --- src/api/routes/Account.ts | 2 +- src/api/routes/Root.ts | 2 +- src/class/Route.ts | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/api/routes/Account.ts b/src/api/routes/Account.ts index 40b1685..44365bc 100644 --- a/src/api/routes/Account.ts +++ b/src/api/routes/Account.ts @@ -5,7 +5,7 @@ import { Req } from '../interfaces'; export default class Account extends Route { constructor(server: Server) { - super(server, { path: '/account', deprecated: false, maintenance: true }); + super(server, { path: '/account', deprecated: false, maintenance: false }); } public bind() { diff --git a/src/api/routes/Root.ts b/src/api/routes/Root.ts index 41f8466..4b96550 100644 --- a/src/api/routes/Root.ts +++ b/src/api/routes/Root.ts @@ -4,7 +4,7 @@ import { Route } from '../../class'; export default class Root extends Route { constructor(server: Server) { - super(server, { path: '/', deprecated: false, maintenance: true }); + super(server, { path: '/', deprecated: false, maintenance: false }); } public bind() { diff --git a/src/class/Route.ts b/src/class/Route.ts index 1374644..ff6f36c 100644 --- a/src/class/Route.ts +++ b/src/class/Route.ts @@ -10,6 +10,11 @@ export default class Route { public conf: { path: string, deprecated?: boolean, maintenance?: boolean }; protected constructor(server: Server, conf: { path: string, deprecated?: boolean, maintenance?: boolean }) { + this.conf = { + path: null, + deprecated: false, + maintenance: false, + }; this.server = server; this.router = router(); this.conf = conf; -- 2.20.1 From e09665bad641ee651ad197799436c21957f49195 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 17:54:42 -0400 Subject: [PATCH 316/516] change from crypto to jwt for bearer tokens --- src/class/Security.ts | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/src/class/Security.ts b/src/class/Security.ts index 7dee703..2a3a126 100644 --- a/src/class/Security.ts +++ b/src/class/Security.ts @@ -1,5 +1,5 @@ /* eslint-disable no-underscore-dangle */ -import crypto from 'crypto'; +import jwt from 'jsonwebtoken'; import { Request } from 'express'; import { Client } from '.'; import { AccountInterface } from '../models'; @@ -26,16 +26,9 @@ export default class Security { * @param _id The Mongoose Document property labeled ._id */ public async createBearer(_id: string): Promise { - let account = await this.client.db.Account.findOne({ _id }); + const account = await this.client.db.Account.findOne({ _id }); if (!account) throw new Error(`Account [${_id}] cannot be found.`); - const salt = crypto.randomBytes(50).toString('base64'); - const cipher = crypto.createCipheriv('aes-256-gcm', this.keys.key, this.keys.iv); - await account.updateOne({ salt }); - account = await this.client.db.Account.findOne({ _id }); - let encrypted = cipher.update(JSON.stringify(account), 'utf8', 'base64'); - encrypted += cipher.final('base64'); - await account.updateOne({ authTag: cipher.getAuthTag() }); - return `${salt}:${encrypted}`; + return jwt.sign({ id: account.id }, this.keys.key, { issuer: 'Library of Code sp-us | CSD' }); } /** @@ -43,20 +36,12 @@ export default class Security { * @param bearer The bearer token provided. */ public async checkBearer(bearer: string): Promise { - const decipher = crypto.createDecipheriv('aes-256-gcm', this.keys.key, this.keys.iv); try { - const salt = bearer.split(':')[0]; - const saltCheck = await this.client.db.Account.findOne({ salt }); - const encrypted = bearer.split(':')[1]; - let decrypted = decipher.update(encrypted, 'base64', 'utf8'); - decipher.setAuthTag(saltCheck.authTag); - decrypted += decipher.final('utf8'); - const json = JSON.parse(decrypted); - const account = await this.client.db.Account.findOne({ username: json.username }); - if (saltCheck.salt !== account.salt) return null; + const res: any = jwt.verify(bearer, this.keys.key, { issuer: 'Library of Code sp-us | CSD' }); + const account = await this.client.db.Account.findOne({ _id: res.id }); + if (!account) return null; return account; - } catch (error) { - this.client.util.handleError(error); + } catch { return null; } } -- 2.20.1 From 891e77a43f0c5b751b5cb5be4a4804789a5f4859 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 18:07:10 -0400 Subject: [PATCH 317/516] add utility for revoking bearer tokens --- src/api/routes/Root.ts | 3 +-- src/class/Security.ts | 1 + src/commands/bearer.ts | 4 +++- src/commands/bearer_revoke.ts | 29 +++++++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 src/commands/bearer_revoke.ts diff --git a/src/api/routes/Root.ts b/src/api/routes/Root.ts index 4b96550..dd7be74 100644 --- a/src/api/routes/Root.ts +++ b/src/api/routes/Root.ts @@ -28,8 +28,7 @@ export default class Root extends Route { cpuClock: os.cpus()[0].speed / 1000, cpuCores: os.cpus().length, hostname: os.hostname(), - ipv4: os.networkInterfaces().eth0.filter((r) => r.family === 'IPv4')[0].address, - ipv6: os.networkInterfaces().eth0.filter((r) => r.family === 'IPv6')[0].address, + ipv4: os.networkInterfaces().enp0s3.filter((r) => r.family === 'IPv4')[0].address, }, }; res.status(200).json({ code: this.constants.codes.SUCCESS, message: response }); diff --git a/src/class/Security.ts b/src/class/Security.ts index 2a3a126..105b34a 100644 --- a/src/class/Security.ts +++ b/src/class/Security.ts @@ -40,6 +40,7 @@ export default class Security { const res: any = jwt.verify(bearer, this.keys.key, { issuer: 'Library of Code sp-us | CSD' }); const account = await this.client.db.Account.findOne({ _id: res.id }); if (!account) return null; + if (account.revokedBearers?.includes(bearer)) return null; return account; } catch { return null; diff --git a/src/commands/bearer.ts b/src/commands/bearer.ts index 4cd92d0..039ebb0 100644 --- a/src/commands/bearer.ts +++ b/src/commands/bearer.ts @@ -1,5 +1,6 @@ import { Message } from 'eris'; import { Client, Command } from '../class'; +import Bearer_Revoke from './bearer_revoke'; export default class Bearer extends Command { constructor(client: Client) { @@ -7,6 +8,7 @@ export default class Bearer extends Command { this.name = 'bearer'; this.description = 'Creates a bearer token.'; this.usage = `${this.client.config.prefix}bearer`; + this.subcmds = [Bearer_Revoke]; this.guildOnly = false; this.enabled = true; } @@ -19,7 +21,7 @@ export default class Bearer extends Command { const bearer = await this.client.server.security.createBearer(account._id); const dm = await this.client.getDMChannel(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}`); - this.error(message.channel, 'Bearer token sent to direct messages.'); + this.success(message.channel, 'Bearer token sent to direct messages.'); return setTimeout(() => { msg.delete(); }, 60000); diff --git a/src/commands/bearer_revoke.ts b/src/commands/bearer_revoke.ts new file mode 100644 index 0000000..fc4d418 --- /dev/null +++ b/src/commands/bearer_revoke.ts @@ -0,0 +1,29 @@ +import { Message } from 'eris'; +import { Client, Command } from '../class'; + +export default class Bearer_Revoke extends Command { + constructor(client: Client) { + super(client); + this.name = 'revoke'; + this.description = 'Revokes an API bearer token.'; + this.usage = `${this.client.config.prefix}bearer revoke `; + this.enabled = true; + this.guildOnly = false; + } + + public async run(message: Message, args: string[]) { + try { + if (!args[0]) return this.client.commands.get('help').run(message, ['bearer', this.name]); + const account = await this.client.db.Account.findOne({ userID: message.author.id }); + if (!account) return this.error(message.channel, 'You do not have an account.'); + + const bearerVerify = await this.client.server.security.checkBearer(args[0]); + if (!bearerVerify || bearerVerify?.userID !== account.userID) return this.error(message.channel, 'Permission denied.'); + if (account.revokedBearers?.includes(args[0])) return this.error(message.channel, 'This bearer token is already revoked.'); + await account.updateOne({ $addToSet: { revokedBearers: args[0] } }); + return this.success(message.channel, 'Revoked bearer token.'); + } catch (err) { + return this.client.util.handleError(err, message, this); + } + } +} -- 2.20.1 From d807d6bdfca43d286bdca180d9dac1ff02c9ee6e Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 18:08:19 -0400 Subject: [PATCH 318/516] add jwt module and revokedBearers entry in Account model --- package.json | 3 + src/models/Account.ts | 2 + yarn.lock | 675 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 670 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 1dd0f55..5a875c5 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "fs-extra": "^8.1.0", "helmet": "^3.21.2", "ioredis": "^4.14.1", + "jsonwebtoken": "^8.5.1", "moment": "^2.24.0", "moment-precise-range-plugin": "^1.3.0", "mongoose": "^5.7.4", @@ -34,6 +35,7 @@ "@types/fs-extra": "^8.0.0", "@types/helmet": "^0.0.45", "@types/ioredis": "^4.0.18", + "@types/jsonwebtoken": "^8.5.0", "@types/mongoose": "^5.7.14", "@types/nodemailer": "^6.2.1", "@types/signale": "^1.2.1", @@ -43,6 +45,7 @@ "eslint": "^6.5.1", "eslint-config-airbnb-base": "^14.0.0", "eslint-plugin-import": "^2.18.2", + "madge": "^3.9.2", "typescript": "^3.6.4" } } diff --git a/src/models/Account.ts b/src/models/Account.ts index 11c18da..9f025d7 100644 --- a/src/models/Account.ts +++ b/src/models/Account.ts @@ -20,6 +20,7 @@ export interface AccountInterface extends Document { hash: boolean, salt: string, authTag: Buffer + revokedBearers: string[], } const Account = new Schema({ @@ -42,6 +43,7 @@ const Account = new Schema({ hash: Boolean, salt: String, authTag: Buffer, + revokedBearers: Array, }); export default model('Account', Account); diff --git a/yarn.lock b/yarn.lock index cc234d5..7024be9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,6 +23,11 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/parser@^7.0.0": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.3.tgz#7e71d892b0d6e7d04a1af4c3c79d72c1f10f5315" + integrity sha512-oJtNJCMFdIMwXGmx+KxuaD7i3b8uS7TTFYW/FNG2BT8m+fmGHoiPYoH0Pe3gya07WuFmM5FCDIr1x0irkD/hyA== + "@ghaiklor/x509@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@ghaiklor/x509/-/x509-1.0.0.tgz#d35a9136d13827ddf29a30bcfd9e7fa2f54cda9b" @@ -107,6 +112,13 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== +"@types/jsonwebtoken@^8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz#2531d5e300803aa63279b232c014acf780c981c5" + integrity sha512-9bVao7LvyorRGZCw0VmH/dr7Og+NdjYSsKAxB43OQoComFbBgsEpoR9JW6+qSq/ogwVBg8GI2MfAlk4SYI4OLg== + dependencies: + "@types/node" "*" + "@types/mime@*": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" @@ -213,6 +225,19 @@ semver "^6.3.0" tsutils "^3.17.1" +"@typescript-eslint/typescript-estree@^2.29.0": + version "2.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5" + integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg== + dependencies: + debug "^4.1.1" + eslint-visitor-keys "^1.1.0" + glob "^7.1.6" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" @@ -273,6 +298,11 @@ ansi-styles@^4.1.0: "@types/color-name" "^1.1.1" color-convert "^2.0.1" +app-module-path@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/app-module-path/-/app-module-path-2.2.0.tgz#641aa55dfb7d6a6f0a8141c4b9c0aa50b6c24dd5" + integrity sha1-ZBqlXft9am8KgUHEucCqULbCTdU= + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -302,6 +332,11 @@ array.prototype.flat@^1.2.1: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" +ast-module-types@^2.3.1, ast-module-types@^2.3.2, ast-module-types@^2.4.0, ast-module-types@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/ast-module-types/-/ast-module-types-2.6.0.tgz#f9f367fd273bbe01e52f2c51b5f46b65801d5d7f" + integrity sha512-zXSoVaMrf2R+r+ISid5/9a8SXm1LLdkhHzh6pSRhj9jklzruOOl1hva1YmFT33wAstg/f9ZndJAlq1BSrFLSGA== + astral-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" @@ -366,6 +401,11 @@ bson@^1.1.4: resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.4.tgz#f76870d799f15b854dffb7ee32f0a874797f7e89" integrity sha512-S/yKGU1syOMzO86+dGpg2qGoDL0zvzcb262G+gqEy6TgP6rt6z6qxSFX/8X6vLC91P7G7C3nLs0+bvDzmvBA3Q== +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= + bytes@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" @@ -381,7 +421,7 @@ camelize@1.0.0: resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.2: +chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.2, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -398,6 +438,14 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -410,11 +458,21 @@ cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" +cli-spinners@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.3.0.tgz#0632239a4b5aa4c958610142c34bb7a651fc8df5" + integrity sha512-Xs2Hf2nzrvJMFKimOR7YR0QwZ8fc0u98kdtwN1eNAZzNQgH3vK2pXzff6GJtKh7S5hoJ87ECiAiZFS2fb5Ii2w== + cli-width@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + cluster-key-slot@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" @@ -444,6 +502,21 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +commander@^2.13.0, commander@^2.16.0, commander@^2.19.0, commander@^2.20.3, commander@^2.8.1: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" + integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -521,18 +594,37 @@ debug@3.1.0, debug@=3.1.0: dependencies: ms "2.0.0" -debug@^4.0.1, debug@^4.1.1: +debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== dependencies: ms "^2.1.1" +decomment@^0.9.2: + version "0.9.2" + resolved "https://registry.yarnpkg.com/decomment/-/decomment-0.9.2.tgz#4dffdfbe96a32b0fdf301f758b7f92f7fbe82ab4" + integrity sha512-sblyUmOJZxiL7oJ2ogJS6jtl/67+CTOW87SrYE/96u3PhDYikYoLCdLzcnceToiQejOLlqNnLCkaxx/+nE/ehg== + dependencies: + esprima "4.0.1" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -555,11 +647,99 @@ depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= +dependency-tree@^7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/dependency-tree/-/dependency-tree-7.2.1.tgz#41c8f6feb54a2ae32475c0158e8d2c2696bb7f54" + integrity sha512-nBxnjkqDW4LqAzBazy60V4lE0mAtIQ+oers/GIIvVvGYVdCD9+RNNd4G9jjstyz7ZFVg/j/OiYCvK5MjoVqA2w== + dependencies: + commander "^2.19.0" + debug "^4.1.1" + filing-cabinet "^2.5.1" + precinct "^6.2.0" + typescript "^3.7.5" + destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +detective-amd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/detective-amd/-/detective-amd-3.0.0.tgz#40c8e21e229df8bca1ee2d4b952a7b67b01e2a5a" + integrity sha512-kOpKHyabdSKF9kj7PqYHLeHPw+TJT8q2u48tZYMkIcas28el1CYeLEJ42Nm+563/Fq060T5WknfwDhdX9+kkBQ== + dependencies: + ast-module-types "^2.3.1" + escodegen "^1.8.0" + get-amd-module-type "^3.0.0" + node-source-walk "^4.0.0" + +detective-cjs@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/detective-cjs/-/detective-cjs-3.1.1.tgz#18da3e39a002d2098a1123d45ce1de1b0d9045a0" + integrity sha512-JQtNTBgFY6h8uT6pgph5QpV3IyxDv+z3qPk/FZRDT9TlFfm5dnRtpH39WtQEr1khqsUxVqXzKjZHpdoQvQbllg== + dependencies: + ast-module-types "^2.4.0" + node-source-walk "^4.0.0" + +detective-es6@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/detective-es6/-/detective-es6-2.2.0.tgz#8f2baba3f8cd90a5cfd748f5ac436f0158ed2585" + integrity sha512-fSpNY0SLER7/sVgQZ1NxJPwmc9uCTzNgdkQDhAaj8NPYwr7Qji9QBcmbNvtMCnuuOGMuKn3O7jv0An+/WRWJZQ== + dependencies: + node-source-walk "^4.0.0" + +detective-less@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/detective-less/-/detective-less-1.0.2.tgz#a68af9ca5f69d74b7d0aa190218b211d83b4f7e3" + integrity sha512-Rps1xDkEEBSq3kLdsdnHZL1x2S4NGDcbrjmd4q+PykK5aJwDdP5MBgrJw1Xo+kyUHuv3JEzPqxr+Dj9ryeDRTA== + dependencies: + debug "^4.0.0" + gonzales-pe "^4.2.3" + node-source-walk "^4.0.0" + +detective-postcss@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/detective-postcss/-/detective-postcss-3.0.1.tgz#511921951f66135e17d0ece2e7604c6e4966c9c6" + integrity sha512-tfTS2GdpUal5NY0aCqI4dpEy8Xfr88AehYKB0iBIZvo8y2g3UsrcDnrp9PR2FbzoW7xD5Rip3NJW7eCSvtqdUw== + dependencies: + debug "^4.1.1" + is-url "^1.2.4" + postcss "^7.0.2" + postcss-values-parser "^1.5.0" + +detective-sass@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/detective-sass/-/detective-sass-3.0.1.tgz#496b819efd1f5c4dd3f0e19b43a8634bdd6927c4" + integrity sha512-oSbrBozRjJ+QFF4WJFbjPQKeakoaY1GiR380NPqwdbWYd5wfl5cLWv0l6LsJVqrgWfFN1bjFqSeo32Nxza8Lbw== + dependencies: + debug "^4.1.1" + gonzales-pe "^4.2.3" + node-source-walk "^4.0.0" + +detective-scss@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/detective-scss/-/detective-scss-2.0.1.tgz#06f8c21ae6dedad1fccc26d544892d968083eaf8" + integrity sha512-VveyXW4WQE04s05KlJ8K0bG34jtHQVgTc9InspqoQxvnelj/rdgSAy7i2DXAazyQNFKlWSWbS+Ro2DWKFOKTPQ== + dependencies: + debug "^4.1.1" + gonzales-pe "^4.2.3" + node-source-walk "^4.0.0" + +detective-stylus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/detective-stylus/-/detective-stylus-1.0.0.tgz#50aee7db8babb990381f010c63fabba5b58e54cd" + integrity sha1-UK7n24uruZA4HwEMY/q7pbWOVM0= + +detective-typescript@^5.8.0: + version "5.8.0" + resolved "https://registry.yarnpkg.com/detective-typescript/-/detective-typescript-5.8.0.tgz#c46776571e26bad6c9ada020cb3cb4e5625d1311" + integrity sha512-SrsUCfCaDTF64QVMHMidRal+kmkbIc5zP8cxxZPsomWx9vuEUjBlSJNhf7/ypE5cLdJJDI4qzKDmyzqQ+iz/xg== + dependencies: + "@typescript-eslint/typescript-estree" "^2.29.0" + ast-module-types "^2.6.0" + node-source-walk "^4.2.0" + typescript "^3.8.3" + dns-prefetch-control@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz#73988161841f3dcc81f47686d539a2c702c88624" @@ -585,6 +765,13 @@ dont-sniff-mimetype@1.1.0: resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz#c7d0427f8bcb095762751252af59d148b0a623b2" integrity sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug== +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -605,6 +792,15 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= +enhanced-resolve@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.2.0.tgz#5d43bda4a0fd447cb0ebbe71bef8deff8805ad0d" + integrity sha512-S7eiFb/erugyd1rLb6mQ3Vuq+EXHv5cpCkNqqIkYkBgN2QdFnyCZzFBleqwGEx4lgNGYij81BWnCrFNK7vxvjQ== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.5.0" + tapable "^1.0.0" + "eris-pagination@git+https://github.com/bsian03/eris-pagination#c0f77b118e98309e89e6522ef545f9d121601f21": version "0.5.0" resolved "git+https://github.com/bsian03/eris-pagination#c0f77b118e98309e89e6522ef545f9d121601f21" @@ -625,6 +821,13 @@ eris@bsian03/eris#dev: opusscript "^0.0.7" tweetnacl "^1.0.1" +errno@^0.1.3: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== + dependencies: + prr "~1.0.1" + error-ex@^1.2.0, error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -668,6 +871,18 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +escodegen@^1.8.0: + version "1.14.3" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" + integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + eslint-config-airbnb-base@^14.0.0: version "14.1.0" resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.1.0.tgz#2ba4592dd6843258221d9bff2b6831bd77c874e4" @@ -790,7 +1005,7 @@ espree@^6.1.2: acorn-jsx "^5.2.0" eslint-visitor-keys "^1.1.0" -esprima@^4.0.0: +esprima@4.0.1, esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -809,7 +1024,7 @@ esrecurse@^4.1.0: dependencies: estraverse "^4.1.0" -estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -920,6 +1135,30 @@ file-entry-cache@^5.0.1: dependencies: flat-cache "^2.0.1" +file-exists-dazinatorfork@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/file-exists-dazinatorfork/-/file-exists-dazinatorfork-1.0.2.tgz#cd8d0d85f63e39dc81eceb0b687c44a2cca95c47" + integrity sha512-r70c72ln2YHzQINNfxDp02hAhbGkt1HffZ+Du8oetWDLjDtFja/Lm10lUaSh9e+wD+7VDvPee0b0C9SAy8pWZg== + +filing-cabinet@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/filing-cabinet/-/filing-cabinet-2.5.1.tgz#f920976d46310710595ed995f033a301570ef6ab" + integrity sha512-GWOdObzou2L0HrJUk8MpJa01q0ZOwuTwTssM2+P+ABJWEGlVWd6ueEatANFdin94/3rdkVSdqpH14VqCNqp3RA== + dependencies: + app-module-path "^2.2.0" + commander "^2.13.0" + debug "^4.1.1" + decomment "^0.9.2" + enhanced-resolve "^4.1.0" + is-relative-path "^1.0.2" + module-definition "^3.0.0" + module-lookup-amd "^6.1.0" + resolve "^1.11.1" + resolve-dependency-path "^2.0.0" + sass-lookup "^3.0.0" + stylus-lookup "^3.0.1" + typescript "^3.0.3" + finalhandler@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" @@ -940,6 +1179,13 @@ find-up@^2.0.0, find-up@^2.1.0: dependencies: locate-path "^2.0.0" +find@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/find/-/find-0.3.0.tgz#4082e8fc8d8320f1a382b5e4f521b9bc50775cb8" + integrity sha512-iSd+O4OEYV/I36Zl8MdYJO0xD82wH528SaCieTVHhclgiYNe9y+yPKSwK+A7/WsmHL1EZ+pYUJBXWTL5qofksw== + dependencies: + traverse-chain "~0.1.0" + flat-cache@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" @@ -954,6 +1200,11 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== +flatten@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b" + integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== + follow-redirects@1.5.10: version "1.5.10" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" @@ -1000,6 +1251,19 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +get-amd-module-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-amd-module-type/-/get-amd-module-type-3.0.0.tgz#bb334662fa04427018c937774570de495845c288" + integrity sha512-99Q7COuACPfVt18zH9N4VAMyb81S6TUgJm2NgV6ERtkh9VIkAaByZkW530wl3lLN5KTtSrK9jVLxYsoP5hQKsw== + dependencies: + ast-module-types "^2.3.2" + node-source-walk "^4.0.0" + +get-own-enumerable-property-symbols@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" + integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== + glob-parent@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" @@ -1026,11 +1290,25 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" +gonzales-pe@^4.2.3: + version "4.3.0" + resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.3.0.tgz#fe9dec5f3c557eead09ff868c65826be54d067b3" + integrity sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ== + dependencies: + minimist "^1.2.5" + graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== +graphviz@0.0.9: + version "0.0.9" + resolved "https://registry.yarnpkg.com/graphviz/-/graphviz-0.0.9.tgz#0bbf1df588c6a92259282da35323622528c4bbc4" + integrity sha512-SmoY2pOtcikmMCqCSy2NO1YsRfu9OO0wpTlOYW++giGjfX1a6gax/m1Fo8IdUd0/3H15cTOfR1SMKwohj4LKsg== + dependencies: + temp "~0.4.0" + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -1163,6 +1441,11 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -1181,6 +1464,11 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + inquirer@^7.0.0: version "7.1.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.1.0.tgz#1298a01859883e17c7264b82870ae1034f92dd29" @@ -1257,6 +1545,16 @@ is-glob@^4.0.0, is-glob@^4.0.1: dependencies: is-extglob "^2.1.1" +is-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== + +is-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= + is-regex@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" @@ -1264,6 +1562,16 @@ is-regex@^1.0.5: dependencies: has "^1.0.3" +is-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= + +is-relative-path@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-relative-path/-/is-relative-path-1.0.2.tgz#091b46a0d67c1ed0fe85f1f8cfdde006bb251d46" + integrity sha1-CRtGoNZ8HtD+hfH4z93gBrslHUY= + is-string@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" @@ -1276,6 +1584,11 @@ is-symbol@^1.0.2: dependencies: has-symbols "^1.0.1" +is-url@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" + integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== + isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -1321,6 +1634,39 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonwebtoken@^8.5.1: + version "8.5.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" + integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^5.6.0" + +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + kareem@2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.1.tgz#def12d9c941017fabfb00f873af95e9c99e1be87" @@ -1372,16 +1718,103 @@ lodash.flatten@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= + lodash@^4.17.14, lodash@^4.17.15: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== +log-symbols@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" + integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== + dependencies: + chalk "^2.4.2" + +madge@^3.9.2: + version "3.9.2" + resolved "https://registry.yarnpkg.com/madge/-/madge-3.9.2.tgz#a432de2c858092d379c2910a21a622ad2b1b24c7" + integrity sha512-6ZvyKinAOOzcRpvpm1iyOuds+LvWIq3o3GmUYAHMJdIpDAgVY3mphxVzeWNo3agIOv0X0T/zbLycXQm9Rn19nA== + dependencies: + chalk "^4.1.0" + commander "^5.1.0" + commondir "^1.0.1" + debug "^4.0.1" + dependency-tree "^7.2.1" + detective-amd "^3.0.0" + detective-cjs "^3.1.1" + detective-es6 "^2.1.0" + detective-less "^1.0.2" + detective-postcss "^3.0.1" + detective-sass "^3.0.1" + detective-scss "^2.0.1" + detective-stylus "^1.0.0" + detective-typescript "^5.8.0" + graphviz "0.0.9" + ora "^4.0.4" + pify "^5.0.0" + pluralize "^8.0.0" + precinct "^6.3.1" + pretty-ms "^7.0.0" + rc "^1.2.7" + typescript "^3.9.5" + walkdir "^0.4.1" + +make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= +memory-fs@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" + integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + memory-pager@^1.0.2: version "1.5.0" resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" @@ -1426,7 +1859,7 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.5: +minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== @@ -1438,6 +1871,26 @@ mkdirp@^0.5.1: dependencies: minimist "^1.2.5" +module-definition@^3.0.0, module-definition@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/module-definition/-/module-definition-3.3.0.tgz#aae06d68c99c5f93841e59b8a4469b974956d4d4" + integrity sha512-HTplA9xwDzH67XJFC1YvZMUElWJD28DV0dUq7lhTs+JKJamUOWA/CcYWSlhW5amJO66uWtY7XdltT+LfX0wIVg== + dependencies: + ast-module-types "^2.6.0" + node-source-walk "^4.0.0" + +module-lookup-amd@^6.1.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/module-lookup-amd/-/module-lookup-amd-6.2.0.tgz#70600008b3f26630fde9ef9ae6165ac69de6ecbb" + integrity sha512-uxHCj5Pw9psZiC1znjU2qPsubt6haCSsN9m7xmIdoTciEgfxUkE1vhtDvjHPuOXEZrVJhjKgkmkP+w73rRuelQ== + dependencies: + commander "^2.8.1" + debug "^4.1.0" + file-exists-dazinatorfork "^1.0.2" + find "^0.3.0" + requirejs "^2.3.5" + requirejs-config-file "^3.1.1" + moment-precise-range-plugin@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/moment-precise-range-plugin/-/moment-precise-range-plugin-1.3.0.tgz#60ac075fdfd14689f6d102af751d171a80b4ab60" @@ -1544,6 +1997,13 @@ nocache@2.1.0: resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f" integrity sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q== +node-source-walk@^4.0.0, node-source-walk@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/node-source-walk/-/node-source-walk-4.2.0.tgz#c2efe731ea8ba9c03c562aa0a9d984e54f27bc2c" + integrity sha512-hPs/QMe6zS94f5+jG3kk9E7TNm4P2SulrKiLWMzKszBfNZvL/V6wseHlTd7IvfW0NZWqPtK3+9yYNr+3USGteA== + dependencies: + "@babel/parser" "^7.0.0" + nodemailer@^6.3.1: version "6.4.6" resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.4.6.tgz#d37f504f6560b36616f646a606894fe18819107f" @@ -1620,7 +2080,7 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -optionator@^0.8.3: +optionator@^0.8.1, optionator@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== @@ -1637,6 +2097,20 @@ opusscript@^0.0.7: resolved "https://registry.yarnpkg.com/opusscript/-/opusscript-0.0.7.tgz#7dd7ec55b302d26bf588e6fc3feb090b8c7da856" integrity sha512-DcBadTdYTUuH9zQtepsLjQn4Ll6rs3dmeFvN+SD0ThPnxRBRm/WC1zXWPg+wgAJimB784gdZvUMA57gDP7FdVg== +ora@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/ora/-/ora-4.0.4.tgz#e8da697cc5b6a47266655bf68e0fb588d29a545d" + integrity sha512-77iGeVU1cIdRhgFzCK8aw1fbtT1B/iZAvWjS+l/o1x0RShMgxHUZaD2yDpWsNCPwXg9z1ZA78Kbdvr8kBmG/Ww== + dependencies: + chalk "^3.0.0" + cli-cursor "^3.1.0" + cli-spinners "^2.2.0" + is-interactive "^1.0.0" + log-symbols "^3.0.0" + mute-stream "0.0.8" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -1683,6 +2157,11 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" +parse-ms@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-2.1.0.tgz#348565a753d4391fa524029956b172cb7753097d" + integrity sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA== + parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -1730,6 +2209,16 @@ pify@^3.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" + integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== + pkg-conf@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-2.1.0.tgz#2126514ca6f2abfebd168596df18ba57867f0058" @@ -1745,11 +2234,60 @@ pkg-dir@^2.0.0: dependencies: find-up "^2.1.0" +pluralize@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" + integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== + +postcss-values-parser@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-1.5.0.tgz#5d9fa63e2bcb0179ce48f3235303765eb89f3047" + integrity sha512-3M3p+2gMp0AH3da530TlX8kiO1nxdTnc3C6vr8dMxRLIlh8UYkz0/wcwptSXjhtx2Fr0TySI7a+BHDQ8NL7LaQ== + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss@^7.0.2: + version "7.0.32" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.32.tgz#4310d6ee347053da3433db2be492883d62cec59d" + integrity sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +precinct@^6.2.0, precinct@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/precinct/-/precinct-6.3.1.tgz#8ad735a8afdfc48b56ed39c9ad3bf999b6b928dc" + integrity sha512-JAwyLCgTylWminoD7V0VJwMElWmwrVSR6r9HaPWCoswkB4iFzX7aNtO7VBfAVPy+NhmjKb8IF8UmlWJXzUkOIQ== + dependencies: + commander "^2.20.3" + debug "^4.1.1" + detective-amd "^3.0.0" + detective-cjs "^3.1.1" + detective-es6 "^2.1.0" + detective-less "^1.0.2" + detective-postcss "^3.0.1" + detective-sass "^3.0.1" + detective-scss "^2.0.1" + detective-stylus "^1.0.0" + detective-typescript "^5.8.0" + module-definition "^3.3.0" + node-source-walk "^4.2.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= +pretty-ms@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-7.0.0.tgz#45781273110caf35f55cab21a8a9bd403a233dc0" + integrity sha512-J3aPWiC5e9ZeZFuSeBraGxSkGMOvulSWsxDByOcbD1Pr75YL3LSNIKIb52WXbCLE1sS5s4inBBbryjF4Y05Ceg== + dependencies: + parse-ms "^2.1.0" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -1768,6 +2306,11 @@ proxy-addr@~2.0.5: forwarded "~0.1.2" ipaddr.js "1.9.1" +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" @@ -1793,6 +2336,16 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + read-pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" @@ -1810,7 +2363,7 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -readable-stream@^2.3.5: +readable-stream@^2.0.1, readable-stream@^2.3.5: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -1868,6 +2421,25 @@ require_optional@^1.0.1: resolve-from "^2.0.0" semver "^5.1.0" +requirejs-config-file@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/requirejs-config-file/-/requirejs-config-file-3.1.2.tgz#de8c0b3eebdf243511c994a8a24b006f8b825997" + integrity sha512-sdLWywcDuNz7EIOhenSbRfT4YF84nItDv90coN2htbokjmU2QeyQuSBZILQUKNksepl8UPVU+hgYySFaDxbJPQ== + dependencies: + esprima "^4.0.0" + make-dir "^2.1.0" + stringify-object "^3.2.1" + +requirejs@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9" + integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg== + +resolve-dependency-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-dependency-path/-/resolve-dependency-path-2.0.0.tgz#11700e340717b865d216c66cabeb4a2a3c696736" + integrity sha512-DIgu+0Dv+6v2XwRaNWnumKu7GPufBBOr5I1gRPJHkvghrfCGOooJODFvgFimX/KRxk9j0whD2MnKHzM1jYvk9w== + resolve-from@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" @@ -1878,7 +2450,7 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1: +resolve@^1.10.0, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1: version "1.17.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== @@ -1917,7 +2489,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.1.1, safe-buffer@^5.1.2: +safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -1934,7 +2506,14 @@ saslprep@^1.0.0: dependencies: sparse-bitfield "^3.0.3" -"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.5.0: +sass-lookup@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/sass-lookup/-/sass-lookup-3.0.0.tgz#3b395fa40569738ce857bc258e04df2617c48cac" + integrity sha512-TTsus8CfFRn1N44bvdEai1no6PqdmDiQUiqW5DlpmtT+tYnIt1tXtDIph5KA1efC+LmioJXSnCtUVpcK9gaKIg== + dependencies: + commander "^2.16.0" + +"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -1944,6 +2523,11 @@ semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.3.2: + version "7.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== + send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -2023,6 +2607,11 @@ sliced@1.0.1: resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= +source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + sparse-bitfield@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" @@ -2130,6 +2719,15 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +stringify-object@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" + integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== + dependencies: + get-own-enumerable-property-symbols "^3.0.0" + is-obj "^1.0.1" + is-regexp "^1.0.0" + strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -2154,6 +2752,19 @@ strip-json-comments@^3.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.0.tgz#7638d31422129ecf4457440009fba03f9f9ac180" integrity sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w== +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +stylus-lookup@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/stylus-lookup/-/stylus-lookup-3.0.2.tgz#c9eca3ff799691020f30b382260a67355fefdddd" + integrity sha512-oEQGHSjg/AMaWlKe7gqsnYzan8DLcGIHe0dUaFkucZZ14z4zjENRlQMCHT4FNsiWnJf17YN9OvrCfCoi7VvOyg== + dependencies: + commander "^2.8.1" + debug "^4.1.0" + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -2161,6 +2772,13 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + supports-color@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" @@ -2178,6 +2796,16 @@ table@^5.2.3: slice-ansi "^2.1.0" string-width "^3.0.0" +tapable@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +temp@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/temp/-/temp-0.4.0.tgz#671ad63d57be0fe9d7294664b3fc400636678a60" + integrity sha1-ZxrWPVe+D+nXKUZks/xABjZnimA= + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -2200,6 +2828,11 @@ toidentifier@1.0.0: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== +traverse-chain@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1" + integrity sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE= + tslib@^1.8.1, tslib@^1.9.0: version "1.11.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.2.tgz#9c79d83272c9a7aaf166f73915c9667ecdde3cc9" @@ -2242,11 +2875,21 @@ type-is@~1.6.17, type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" +typescript@^3.0.3, typescript@^3.7.5, typescript@^3.8.3, typescript@^3.9.5: + version "3.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" + integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== + typescript@^3.6.4: version "3.8.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= + universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -2297,6 +2940,18 @@ vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= +walkdir@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.4.1.tgz#dc119f83f4421df52e3061e514228a2db20afa39" + integrity sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ== + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" -- 2.20.1 From 9a77963823c0cf65c43c79021bf9752fa4ccf668 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 18:11:38 -0400 Subject: [PATCH 319/516] delete msg after bearer revocation --- src/commands/bearer_revoke.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/bearer_revoke.ts b/src/commands/bearer_revoke.ts index fc4d418..b2f5645 100644 --- a/src/commands/bearer_revoke.ts +++ b/src/commands/bearer_revoke.ts @@ -13,6 +13,7 @@ export default class Bearer_Revoke extends Command { public async run(message: Message, args: string[]) { try { + message.delete(); if (!args[0]) return this.client.commands.get('help').run(message, ['bearer', this.name]); const account = await this.client.db.Account.findOne({ userID: message.author.id }); if (!account) return this.error(message.channel, 'You do not have an account.'); -- 2.20.1 From 9c6e90080247a8f51430a5454fba6c80dc162e82 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 18:22:44 -0400 Subject: [PATCH 320/516] invalidate authentication for locked accounts --- src/class/Security.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/class/Security.ts b/src/class/Security.ts index 105b34a..bd00631 100644 --- a/src/class/Security.ts +++ b/src/class/Security.ts @@ -40,6 +40,7 @@ export default class Security { const res: any = jwt.verify(bearer, this.keys.key, { issuer: 'Library of Code sp-us | CSD' }); const account = await this.client.db.Account.findOne({ _id: res.id }); if (!account) return null; + if (account.locked) return null; if (account.revokedBearers?.includes(bearer)) return null; return account; } catch { -- 2.20.1 From 8378b27c96ab9b5e3764f1dde81723fd8d2c6b23 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 23:46:51 -0400 Subject: [PATCH 321/516] daemonization changes for storage calculations --- src/go/storage/storage.go | 18 +++++++----------- src/intervals/storage.ts | 23 +++++++++++++++++++++-- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/go/storage/storage.go b/src/go/storage/storage.go index afd6abf..ab87d75 100644 --- a/src/go/storage/storage.go +++ b/src/go/storage/storage.go @@ -41,7 +41,7 @@ func HandleError(e error, serv int) { } func main() { - var status bool + fmt.Println("Starting CSD-GO-STR Daemon [GO]") config := &ConfigStruct{} file, err := ioutil.ReadFile("../config.json") HandleError(err, 1) @@ -56,19 +56,18 @@ func main() { _, err = RedisClient.Ping().Result() fmt.Printf("Connected to Redis [GO]\n") HandleError(err, 1) - status = false - for { + /*for { fmt.Printf("Calling handler func [GO]\n") if status == false { - handler(&status, *config) + handler(*config) time.Sleep(1000000 * time.Millisecond) } - } + }*/ + handler(*config) } -func handler(status *bool, config ConfigStruct) { - *status = true +func handler(config ConfigStruct) { mongoClient, err := mongo.NewClient(options.Client().ApplyURI(config.MongoDB)) HandleError(err, 1) ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) @@ -88,7 +87,6 @@ func handler(status *bool, config ConfigStruct) { } err = mongoClient.Disconnect(ctx) HandleError(err, 1) - *status = false } func checkAccountSizeAndUpdate(username string, id string) { @@ -97,12 +95,10 @@ func checkAccountSizeAndUpdate(username string, id string) { usernameFormat := strings.Replace(username, "\"", "", -1) sizeHome := DirSize(&userHomeDirectory) size += sizeHome - sizeMail := DirSize(&userHomeDirectory) - size += sizeMail status := RedisClient.Set("storage"+"-"+usernameFormat, size, 0) fmt.Println(status.Name()) if status.Err() != nil { fmt.Println(status.Err()) } - fmt.Printf("Set Call | Username: %v, ID: %v | Bytes: %f\n", string(username), string(id), size) + fmt.Printf("Set Call | Username: %v, ID: %v | Bytes: %f\n [GO]", string(username), string(id), size) } diff --git a/src/intervals/storage.ts b/src/intervals/storage.ts index e8ef484..e41ba29 100644 --- a/src/intervals/storage.ts +++ b/src/intervals/storage.ts @@ -3,12 +3,31 @@ import { spawn } from 'child_process'; import { Client } from '../class'; +let interval: NodeJS.Timeout; + export default async function storage(client: Client) { - let storageGo = spawn(`${__dirname}/../bin/storage`, [], { cwd: __dirname }); + async function determineInterval(client0: Client) { + const accounts = await client0.db.Account.countDocuments(); + return (accounts * 2) * 60000; + } + let intervalTiming = await determineInterval(client); + /* let storageGo = spawn(`${__dirname}/../bin/storage`, [], { cwd: __dirname }); storageGo.stdout.on('data', (data) => client.signale.log(data.toString())); storageGo.stderr.on('data', (data) => client.signale.log(data.toString())); storageGo.on('exit', (code) => { client.signale.log(`Go storage func exited with code ${code}, restarting`); storageGo = spawn(`${__dirname}/../bin/storage`, [], { cwd: __dirname }); - }); + }); */ + interval = setInterval(async () => { + intervalTiming = await determineInterval(client); + const storageDaemon = spawn(`${__dirname}/../bin/storage`, [], { cwd: __dirname }); + storageDaemon.stdout.on('data', (data) => client.signale.log(data.toString())); + storageDaemon.stderr.on('data', (data) => client.signale.log(data.toString())); + storageDaemon.on('exit', (code) => { + client.signale.log(`CSD-GO-STR Daemon exited with code ${code}.`); + storageDaemon.removeAllListeners(); + }); + }, intervalTiming); } + +export const clear = () => clearInterval(interval); -- 2.20.1 From 00dde49d79f0c498a9ee029a586e8484c30cba9a Mon Sep 17 00:00:00 2001 From: Matthew R Date: Mon, 29 Jun 2020 23:57:30 -0400 Subject: [PATCH 322/516] daemonization changes for storage calculations --- src/intervals/storage.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/intervals/storage.ts b/src/intervals/storage.ts index e41ba29..a3298a0 100644 --- a/src/intervals/storage.ts +++ b/src/intervals/storage.ts @@ -18,6 +18,7 @@ export default async function storage(client: Client) { client.signale.log(`Go storage func exited with code ${code}, restarting`); storageGo = spawn(`${__dirname}/../bin/storage`, [], { cwd: __dirname }); }); */ + client.signale.info(`Activated CSD-GO-STR daemon startup interval. Starting in ${intervalTiming / 60000}min.`); interval = setInterval(async () => { intervalTiming = await determineInterval(client); const storageDaemon = spawn(`${__dirname}/../bin/storage`, [], { cwd: __dirname }); @@ -26,6 +27,7 @@ export default async function storage(client: Client) { storageDaemon.on('exit', (code) => { client.signale.log(`CSD-GO-STR Daemon exited with code ${code}.`); storageDaemon.removeAllListeners(); + client.signale.info(`Reactivating CSD-GO-STR daemon startup interval. Reactivating in ${intervalTiming / 60000}min.`); }); }, intervalTiming); } -- 2.20.1 From 5e022b523a2021a59847151e5b14907504c4fd4b Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 30 Jun 2020 15:03:49 -0400 Subject: [PATCH 323/516] changes --- src/go/storage/storage.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/go/storage/storage.go b/src/go/storage/storage.go index ab87d75..3fdaa61 100644 --- a/src/go/storage/storage.go +++ b/src/go/storage/storage.go @@ -4,13 +4,15 @@ import ( "context" "encoding/json" "fmt" + "io/ioutil" + "os" + "strings" + "time" + "github.com/go-redis/redis/v7" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - "io/ioutil" - "strings" - "time" ) // RedisClient the Redis client @@ -81,12 +83,14 @@ func handler(config ConfigStruct) { HandleError(err, 0) for cur.Next(context.TODO()) { - go 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()) - time.Sleep(600000 * time.Millisecond) + time.Sleep(300000 * time.Millisecond) } err = mongoClient.Disconnect(ctx) HandleError(err, 1) + fmt.Println("CSD-GO-STR finished, exiting with code 0. [GO]") + os.Exit(0) } func checkAccountSizeAndUpdate(username string, id string) { -- 2.20.1 From 51ba72ff0826c026243b52e910502f0e1e5235a3 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 30 Jun 2020 17:33:24 -0400 Subject: [PATCH 324/516] new cmds for cscli --- src/cscli/main.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/cscli/main.ts b/src/cscli/main.ts index 73d8a56..37e5abe 100644 --- a/src/cscli/main.ts +++ b/src/cscli/main.ts @@ -55,6 +55,16 @@ export default class CSCLI { socket.write(`${res}\n`); socket.destroy(); break; + case 'processcount': + const processCount = await this.client.util.exec(`ps -U ${parsed.Username} -u ${parsed.Username} u | wc -l`); + socket.write(`${processCount}\n`); + socket.destroy(); + break; + case 'sshlogins': + const sshLogins = await this.client.util.exec(`who | grep ${parsed.Username} | wc -l`); + socket.write(`${sshLogins}\n`); + socket.destroy(); + break; default: socket.destroy(); break; -- 2.20.1 From 050335b760c994d9e9a06e656939f9b1f844dd59 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Wed, 1 Jul 2020 00:38:47 -0400 Subject: [PATCH 325/516] add systemd status cmd --- src/commands/exec.ts | 2 +- src/commands/systemd_status.ts | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/commands/systemd_status.ts diff --git a/src/commands/exec.ts b/src/commands/exec.ts index 40bc6d1..d224fe1 100644 --- a/src/commands/exec.ts +++ b/src/commands/exec.ts @@ -17,7 +17,7 @@ export default class Exec extends Command { try { if (!args.length) return this.client.commands.get('help').run(message, [this.name]); - const response = await this.loading(message.channel, `***Executing \`${args.join(' ')}\``); + const response = await this.loading(message.channel, `***Executing \`${args.join(' ')}\`***`); let result: string; try { result = await this.client.util.exec(args.join(' '), { cwd: '/opt/CloudServices' }); diff --git a/src/commands/systemd_status.ts b/src/commands/systemd_status.ts new file mode 100644 index 0000000..998457f --- /dev/null +++ b/src/commands/systemd_status.ts @@ -0,0 +1,31 @@ +import { Message } from 'eris'; +import { Client, Command, RichEmbed } from '../class'; + +export default class SystemD_Status extends Command { + constructor(client: Client) { + super(client); + this.name = 'status'; + this.description = 'Prints out the status of a SystemD service that you run.'; + this.usage = `${this.client.config.prefix}systemd status Date: Wed, 1 Jul 2020 00:47:09 -0400 Subject: [PATCH 326/516] fixes --- src/class/Util.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index afa999c..5ecdf5e 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -33,7 +33,7 @@ export default class Util { * @param options childProcess.ExecOptions */ public async exec(command: string, options: childProcess.ExecOptions = {}): Promise { - return new Promise((res, rej) => { + /* return new Promise((res, rej) => { let output = ''; const writeFunction = (data: string|Buffer|Error) => { output += `${data}`; @@ -50,6 +50,13 @@ export default class Util { if (code !== 0) rej(new Error(`Command failed: ${command}\n${output}`)); res(output); }); + }); */ + return new Promise((resolve, reject) => { + childProcess.exec(command, options, (err, stdout, stderr) => { + if (stderr) reject(new Error(`Command failed: ${command}\n${stderr}`)); + if (err) reject(err); + resolve(stdout); + }); }); } -- 2.20.1 From 20ce572fef319f91aa7bb80ddbe05471fbf53e44 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Wed, 1 Jul 2020 00:49:58 -0400 Subject: [PATCH 327/516] formatting --- src/commands/exec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/exec.ts b/src/commands/exec.ts index d224fe1..bba1640 100644 --- a/src/commands/exec.ts +++ b/src/commands/exec.ts @@ -17,7 +17,7 @@ export default class Exec extends Command { try { if (!args.length) return this.client.commands.get('help').run(message, [this.name]); - const response = await this.loading(message.channel, `***Executing \`${args.join(' ')}\`***`); + const response = await this.loading(message.channel, `\`${args.join(' ')}\``); let result: string; try { result = await this.client.util.exec(args.join(' '), { cwd: '/opt/CloudServices' }); -- 2.20.1 From dfa6e6e642818b2964f73d2e4c1fe689ee11e465 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Wed, 1 Jul 2020 00:50:26 -0400 Subject: [PATCH 328/516] bind subcmd --- src/commands/systemd.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/systemd.ts b/src/commands/systemd.ts index a157518..6adf97c 100644 --- a/src/commands/systemd.ts +++ b/src/commands/systemd.ts @@ -1,6 +1,7 @@ import { Message } from 'eris'; import { Client, Command } from '../class'; import SystemD_Linger from './systemd_linger'; +import SystemD_Status from './systemd_status'; export default class SystemD extends Command { constructor(client: Client) { @@ -8,7 +9,7 @@ export default class SystemD extends Command { this.name = 'systemd'; this.description = 'Manages various aspects for your user SystemD.'; this.usage = `Run ${this.client.config.prefix}${this.name} [subcommand] for usage information`; - this.subcmds = [SystemD_Linger]; + this.subcmds = [SystemD_Linger, SystemD_Status]; this.enabled = true; } -- 2.20.1 From 07e3e7ffdbc0e86495b63963cb98d1308e818f20 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Wed, 1 Jul 2020 00:54:29 -0400 Subject: [PATCH 329/516] fixes --- src/commands/systemd_status.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/commands/systemd_status.ts b/src/commands/systemd_status.ts index 998457f..e789b9f 100644 --- a/src/commands/systemd_status.ts +++ b/src/commands/systemd_status.ts @@ -15,8 +15,7 @@ export default class SystemD_Status extends Command { if (!args[0]) return this.client.commands.get('help').run(message, ['systemd', this.name]); const account = await this.client.db.Account.findOne({ userID: message.author.id }).lean().exec(); if (!account) return this.error(message.channel, 'You do not have a Cloud Services account.'); - const cmd = await this.client.util.exec(`runuser ${account.username} -c 'DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/\${UID}/bus" systemctl --user s - tatus ${args[0]}'`); + const cmd = await this.client.util.exec(`runuser ${account.username} -c 'DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/\${UID}/bus" systemctl --user status ${args[0]}'`); if (cmd.includes('could not be found')) return this.error(message.channel, 'The service name you provided doesn\'t exist.'); const embed = new RichEmbed(); embed.setTitle(`SystemD Status | ${args[0]}`); -- 2.20.1 From c0e1c54ce0798cd73912b9803f48b4dfe005a67e Mon Sep 17 00:00:00 2001 From: Matthew R Date: Wed, 1 Jul 2020 01:24:00 -0400 Subject: [PATCH 330/516] commands to start/restart/stop a systemd service --- src/commands/systemd.ts | 3 +++ src/commands/systemd_restart.ts | 30 ++++++++++++++++++++++++++++++ src/commands/systemd_start.ts | 30 ++++++++++++++++++++++++++++++ src/commands/systemd_stop.ts | 30 ++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 src/commands/systemd_restart.ts create mode 100644 src/commands/systemd_start.ts create mode 100644 src/commands/systemd_stop.ts diff --git a/src/commands/systemd.ts b/src/commands/systemd.ts index 6adf97c..65015f7 100644 --- a/src/commands/systemd.ts +++ b/src/commands/systemd.ts @@ -2,6 +2,9 @@ import { Message } from 'eris'; import { Client, Command } from '../class'; import SystemD_Linger from './systemd_linger'; import SystemD_Status from './systemd_status'; +import SystemD_Start from './systemd_start'; +import SystemD_Restart from './systemd_restart'; +import SystemD_Stop from './systemd_stop'; export default class SystemD extends Command { constructor(client: Client) { diff --git a/src/commands/systemd_restart.ts b/src/commands/systemd_restart.ts new file mode 100644 index 0000000..14428b9 --- /dev/null +++ b/src/commands/systemd_restart.ts @@ -0,0 +1,30 @@ +import { Message } from 'eris'; +import { Client, Command } from '../class'; + +export default class SystemD_Restart extends Command { + constructor(client: Client) { + super(client); + this.name = 'restart'; + this.description = `Restarts a SystemD user service, if the service has never been started or isn't running use \`${this.client.config.prefix}systemd start \`.`; + this.usage = `${this.client.config.prefix}systemd restart `; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + if (!args[0]) return this.client.commands.get('help').run(message, ['systemd', this.name]); + 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.'); + try { + await this.client.util.exec(`runuser ${account.username} -c 'DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/\${UID}/bus" systemctl --user restart ${args[0]}'`); + message.delete(); + return this.success(message.channel, 'Service restarted.'); + } catch (err) { + if (err.includes('not found')) return this.error(message.channel, 'Service not found.'); + return this.error(message.channel, err.toString()); + } + } catch (err) { + return this.client.util.handleError(err, message, this); + } + } +} diff --git a/src/commands/systemd_start.ts b/src/commands/systemd_start.ts new file mode 100644 index 0000000..2b57db9 --- /dev/null +++ b/src/commands/systemd_start.ts @@ -0,0 +1,30 @@ +import { Message } from 'eris'; +import { Client, Command } from '../class'; + +export default class SystemD_Start extends Command { + constructor(client: Client) { + super(client); + this.name = 'start'; + this.description = `Starts a SystemD user service, if the service is already running use \`${this.client.config.prefix}systemd restart \`.`; + this.usage = `${this.client.config.prefix}systemd start `; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + if (!args[0]) return this.client.commands.get('help').run(message, ['systemd', this.name]); + 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.'); + try { + await this.client.util.exec(`runuser ${account.username} -c 'DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/\${UID}/bus" systemctl --user start ${args[0]}'`); + message.delete(); + return this.success(message.channel, 'Service started.'); + } catch (err) { + if (err.includes('not found')) return this.error(message.channel, 'Service not found.'); + return this.error(message.channel, err.toString()); + } + } catch (err) { + return this.client.util.handleError(err, message, this); + } + } +} diff --git a/src/commands/systemd_stop.ts b/src/commands/systemd_stop.ts new file mode 100644 index 0000000..b7e4ef6 --- /dev/null +++ b/src/commands/systemd_stop.ts @@ -0,0 +1,30 @@ +import { Message } from 'eris'; +import { Client, Command } from '../class'; + +export default class SystemD_Stop extends Command { + constructor(client: Client) { + super(client); + this.name = 'stop'; + this.description = 'Stops a SystemD user service.'; + this.usage = `${this.client.config.prefix}systemd stop `; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + if (!args[0]) return this.client.commands.get('help').run(message, ['systemd', this.name]); + 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.'); + try { + await this.client.util.exec(`runuser ${account.username} -c 'DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/\${UID}/bus" systemctl --user stop ${args[0]}'`); + message.delete(); + return this.success(message.channel, 'Service stopped.'); + } catch (err) { + if (err.includes('not found')) return this.error(message.channel, 'Service not found.'); + return this.error(message.channel, err.toString()); + } + } catch (err) { + return this.client.util.handleError(err, message, this); + } + } +} -- 2.20.1 From 4bfee04aa26e0cd6aa0016337e2b732a43d3d602 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Wed, 1 Jul 2020 01:27:57 -0400 Subject: [PATCH 331/516] bind subcmds --- src/commands/systemd.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/systemd.ts b/src/commands/systemd.ts index 65015f7..5aae99a 100644 --- a/src/commands/systemd.ts +++ b/src/commands/systemd.ts @@ -12,7 +12,7 @@ export default class SystemD extends Command { this.name = 'systemd'; this.description = 'Manages various aspects for your user SystemD.'; this.usage = `Run ${this.client.config.prefix}${this.name} [subcommand] for usage information`; - this.subcmds = [SystemD_Linger, SystemD_Status]; + this.subcmds = [SystemD_Linger, SystemD_Status, SystemD_Start, SystemD_Restart, SystemD_Stop]; this.enabled = true; } -- 2.20.1 From ba0ac570004c28675630340556d87b0489f05865 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Wed, 1 Jul 2020 16:42:43 -0400 Subject: [PATCH 332/516] push fix --- src/commands/systemd_restart.ts | 2 +- src/commands/systemd_start.ts | 2 +- src/commands/systemd_status.ts | 8 ++++++-- src/commands/systemd_stop.ts | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/commands/systemd_restart.ts b/src/commands/systemd_restart.ts index 14428b9..3e3db9b 100644 --- a/src/commands/systemd_restart.ts +++ b/src/commands/systemd_restart.ts @@ -20,7 +20,7 @@ export default class SystemD_Restart extends Command { message.delete(); return this.success(message.channel, 'Service restarted.'); } catch (err) { - if (err.includes('not found')) return this.error(message.channel, 'Service not found.'); + if (err.toString().includes('could not be found')) return this.error(message.channel, 'Service not found.'); return this.error(message.channel, err.toString()); } } catch (err) { diff --git a/src/commands/systemd_start.ts b/src/commands/systemd_start.ts index 2b57db9..1d6029f 100644 --- a/src/commands/systemd_start.ts +++ b/src/commands/systemd_start.ts @@ -20,7 +20,7 @@ export default class SystemD_Start extends Command { message.delete(); return this.success(message.channel, 'Service started.'); } catch (err) { - if (err.includes('not found')) return this.error(message.channel, 'Service not found.'); + if (err.toString().includes('could not be found')) return this.error(message.channel, 'Service not found.'); return this.error(message.channel, err.toString()); } } catch (err) { diff --git a/src/commands/systemd_status.ts b/src/commands/systemd_status.ts index e789b9f..bf38471 100644 --- a/src/commands/systemd_status.ts +++ b/src/commands/systemd_status.ts @@ -15,8 +15,12 @@ export default class SystemD_Status extends Command { if (!args[0]) return this.client.commands.get('help').run(message, ['systemd', this.name]); const account = await this.client.db.Account.findOne({ userID: message.author.id }).lean().exec(); if (!account) return this.error(message.channel, 'You do not have a Cloud Services account.'); - const cmd = await this.client.util.exec(`runuser ${account.username} -c 'DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/\${UID}/bus" systemctl --user status ${args[0]}'`); - if (cmd.includes('could not be found')) return this.error(message.channel, 'The service name you provided doesn\'t exist.'); + let cmd: string; + try { + cmd = await this.client.util.exec(`runuser ${account.username} -c 'DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/\${UID}/bus" systemctl --user status ${args[0]}'`); + } catch (err) { + if (err.toString().includes('could not be found')) return this.error(message.channel, 'The service name you provided doesn\'t exist.'); + } const embed = new RichEmbed(); embed.setTitle(`SystemD Status | ${args[0]}`); embed.setDescription(`\`\`\`sh\n${cmd}\n\`\`\``); diff --git a/src/commands/systemd_stop.ts b/src/commands/systemd_stop.ts index b7e4ef6..9bf44d0 100644 --- a/src/commands/systemd_stop.ts +++ b/src/commands/systemd_stop.ts @@ -20,7 +20,7 @@ export default class SystemD_Stop extends Command { message.delete(); return this.success(message.channel, 'Service stopped.'); } catch (err) { - if (err.includes('not found')) return this.error(message.channel, 'Service not found.'); + if (err.toString().includes('not found')) return this.error(message.channel, 'Service not found.'); return this.error(message.channel, err.toString()); } } catch (err) { -- 2.20.1 From 1bc6b7c625e297b8b9d4e0ff43cfba50982c785d Mon Sep 17 00:00:00 2001 From: Matthew R Date: Wed, 1 Jul 2020 17:54:32 -0400 Subject: [PATCH 333/516] fixes --- src/class/Util.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/class/Util.ts b/src/class/Util.ts index 5ecdf5e..c756e9b 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -33,7 +33,7 @@ export default class Util { * @param options childProcess.ExecOptions */ public async exec(command: string, options: childProcess.ExecOptions = {}): Promise { - /* return new Promise((res, rej) => { + return new Promise((res, rej) => { let output = ''; const writeFunction = (data: string|Buffer|Error) => { output += `${data}`; @@ -50,14 +50,14 @@ export default class Util { if (code !== 0) rej(new Error(`Command failed: ${command}\n${output}`)); res(output); }); - }); */ - return new Promise((resolve, reject) => { + }); + /* return new Promise((resolve, reject) => { childProcess.exec(command, options, (err, stdout, stderr) => { if (stderr) reject(new Error(`Command failed: ${command}\n${stderr}`)); if (err) reject(err); resolve(stdout); }); - }); + }); */ } public async sendMessageToUserTerminal(username: string, message: string): Promise { -- 2.20.1 From 4773c9f9521cf5d64f709f4f9dadb34732dbc1f5 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Wed, 1 Jul 2020 17:58:06 -0400 Subject: [PATCH 334/516] fix bullshit --- src/commands/resetpassword.ts | 8 ++++---- src/commands/systemd_status.ts | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/commands/resetpassword.ts b/src/commands/resetpassword.ts index eb9b8fd..9cdb87c 100644 --- a/src/commands/resetpassword.ts +++ b/src/commands/resetpassword.ts @@ -22,13 +22,13 @@ export default class ResetPassword extends Command { const msg = await this.loading(message.channel, `Resetting password for ${account.username}...`); const tempPass = this.client.util.randomPassword(); - 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); try { - await dmChannel.createMessage(`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` + await dmChannel.createMessage(`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` + '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) { if (error.code === 50007) completeMessage += '\n*Unable to DM user*'; diff --git a/src/commands/systemd_status.ts b/src/commands/systemd_status.ts index bf38471..0afcf9b 100644 --- a/src/commands/systemd_status.ts +++ b/src/commands/systemd_status.ts @@ -15,11 +15,12 @@ export default class SystemD_Status extends Command { if (!args[0]) return this.client.commands.get('help').run(message, ['systemd', this.name]); const account = await this.client.db.Account.findOne({ userID: message.author.id }).lean().exec(); if (!account) return this.error(message.channel, 'You do not have a Cloud Services account.'); - let cmd: string; + let cmd: string = ''; try { - cmd = await this.client.util.exec(`runuser ${account.username} -c 'DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/\${UID}/bus" systemctl --user status ${args[0]}'`); + cmd += await this.client.util.exec(`runuser ${account.username} -c 'DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/\${UID}/bus" systemctl --user status ${args[0]}'`); } catch (err) { 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()); } const embed = new RichEmbed(); embed.setTitle(`SystemD Status | ${args[0]}`); -- 2.20.1 From 1b0f09988599bbe54413375298a045352ecd1e9e Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 4 Jul 2020 22:57:22 -0400 Subject: [PATCH 335/516] changes to route and account util classes --- src/class/AccountUtil.ts | 7 +++---- src/class/Route.ts | 9 +++++++++ src/class/Server.ts | 1 + src/class/Util.ts | 8 ++++++++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/class/AccountUtil.ts b/src/class/AccountUtil.ts index 01b004d..61dcd3c 100644 --- a/src/class/AccountUtil.ts +++ b/src/class/AccountUtil.ts @@ -56,10 +56,10 @@ export default class AccountUtil {
  • #cloud-announcements - Announcements regarding the cloud machine will be here. These include planned maintenance, updates to preinstalled services etc.
  • #cloud-info - Important information you will need to, or should, know to a certain extent. These include our infractions system and Tier limits
  • #cloud-support - A support channel specifically for the cloud machine, you can use this to ask how to renew your certificates, for example
  • -
  • Library of Code Support Desk - Our Support desk, you can contact Staff here.
  • +
  • Library of Code Support Desk - Our Support desk, you can contact Staff here.
  • Want to support us?

    -

    You can support us on Patreon! Head to our Patreon page and feel free to donate as much or as little as you want!
    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!

    +

    You can support us on Patreon! Head to our Patreon page and feel free to donate as much or as little as you want!
    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!

    Library of Code sp-us | Support Team `, @@ -70,8 +70,7 @@ export default class AccountUtil { dmChannel.createMessage('<: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` + `You will be asked to change your password, \`(current) UNIX password\` is \`${tempPass}\`, then create a password that is at least 12 characters long, with at least one number, special character, and an uppercase letter\n` - + 'Bear in mind that when you enter your password, it will be blank, so be careful not to type in your password incorrectly.\n' - + 'You may now return to Modmail, and continue setting up your account from there.\n\n' + + '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' + 'An email containing some useful information has also been sent.\n' + `Your support key is \`${code}\`. Pin this message, you may need this key to contact Library of Code in the future.`).catch(); return { account: accountInterface, tempPass }; diff --git a/src/class/Route.ts b/src/class/Route.ts index ff6f36c..95d713f 100644 --- a/src/class/Route.ts +++ b/src/class/Route.ts @@ -34,6 +34,15 @@ export default class Route { }); } + public init(): void { + this.router.all('*', (req, res, next) => { + 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 }); + else if (this.conf.deprecated === true) res.status(501).json({ code: this.constants.codes.DEPRECATED, message: this.constants.messages.DEPRECATED }); + else next(); + }); + } + /** * This function checks for the presense of a Bearer token with Security.extractBearer(), * then it will attempt to validate it with Security.checkBearer(). diff --git a/src/class/Server.ts b/src/class/Server.ts index 9351437..88d6e82 100644 --- a/src/class/Server.ts +++ b/src/class/Server.ts @@ -40,6 +40,7 @@ export default class Server { } else if (route.conf.maintenance === true) { route.maintenance(); } else { + route.init(); route.bind(); } this.routes.set(route.conf.path, route); diff --git a/src/class/Util.ts b/src/class/Util.ts index c756e9b..f7f5c68 100644 --- a/src/class/Util.ts +++ b/src/class/Util.ts @@ -60,6 +60,14 @@ export default class Util { }); */ } + public sanitize(str: string): string { + let ret = str; + ret = ret.replace('\\', '~'); + ret = ret.replace('.', '~'); + ret = ret.replace(/\W|_/g, '~'); + return ret; + } + public async sendMessageToUserTerminal(username: string, message: string): Promise { const ptsArray = await this.getPTS(username); if (!ptsArray) return false; -- 2.20.1 From 8495560e18854d83487633d2384fb6007a49041b Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 4 Jul 2020 22:58:09 -0400 Subject: [PATCH 336/516] changes to server data and moderation routes --- src/api/routes/Account.ts | 15 ++++++++----- src/api/routes/Root.ts | 44 +++++++++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/api/routes/Account.ts b/src/api/routes/Account.ts index 44365bc..50a9384 100644 --- a/src/api/routes/Account.ts +++ b/src/api/routes/Account.ts @@ -27,14 +27,13 @@ export default class Account extends Route { res.status(200).json({ code: this.constants.codes.SUCCESS, message: acc }); } catch (error) { this.handleError(error, res); - this.server.client.util.handleError(error); } }); this.router.get('/moderations/:id?', async (req: Req, res) => { try { const moderations = await this.server.client.db.Moderation.find({ username: req.account.username }); - if (!moderations.length) res.sendStatus(204); + if (!moderations.length) return res.status(204).json({ code: this.constants.codes.NOT_FOUND, message: null }); if (req.params.id) { const filtered = moderations.filter((moderation) => moderation.logID === req.params.id); res.status(200).json({ code: this.constants.codes.SUCCESS, message: { filtered } }); @@ -43,7 +42,6 @@ export default class Account extends Route { } } catch (error) { this.handleError(error, res); - this.server.client.util.handleError(error); } }); @@ -54,16 +52,23 @@ export default class Account extends Route { this.server.client.util.exec(`memory ${req.account.username}`), this.server.client.redis.get(`storage-${req.account.username}`), ]); + let storage: string; + if (req.query?.cache === 'true') { + const val = await this.server.client.util.exec(`du -sb /home/${req.account.username}`); + // eslint-disable-next-line prefer-destructuring + storage = val.split('\t')[0]; + } else { + storage = diskUsage; + } res.status(200).json({ code: this.constants.codes.SUCCESS, message: { cpu: Number(`${cpuUsage.split('\n')[0] || '0'}`), ram: (Number(ramUsage) * 1000) / 1024 / 1024, - disk: Number(diskUsage) / 1024 / 1024, + disk: Number(storage) / 1024 / 1024, }, }); } catch (error) { this.handleError(error, res); - this.server.client.util.handleError(error); } }); } diff --git a/src/api/routes/Root.ts b/src/api/routes/Root.ts index dd7be74..85c92cb 100644 --- a/src/api/routes/Root.ts +++ b/src/api/routes/Root.ts @@ -8,33 +8,45 @@ export default class Root extends Route { } public bind() { - this.router.get('/', async (req, res) => { + this.router.get('/', async (_req, res) => { try { const date = new Date(); date.setSeconds(-process.uptime()); - const accounts = await this.server.client.db.Account.find(); + const accounts = await this.server.client.db.Account.find().lean().exec(); const administrators = accounts.filter((account) => account.root === true).length; + const technicians = accounts.filter((account) => account?.permissions?.director === true).length; + const staff = accounts.filter((account) => account?.permissions?.staff === true).length; const response = { - nodeVersion: process.version, - uptime: process.uptime(), - server: { - users: accounts.length, - administrators, + csd: { + nodeVersion: process.version, + uptime: process.uptime(), }, - stats: { - uptime: os.uptime(), - loadAverage: os.loadavg(), - cpuModel: os.cpus()[0].model, - cpuClock: os.cpus()[0].speed / 1000, - cpuCores: os.cpus().length, - hostname: os.hostname(), - ipv4: os.networkInterfaces().enp0s3.filter((r) => r.family === 'IPv4')[0].address, + server: { + userCount: accounts.length, + administratorCount: administrators, + technicianCount: technicians, + staffCount: staff, + stats: { + uptime: os.uptime(), + loadAverages: os.loadavg(), + hostname: os.hostname(), + ipv4Address: os.networkInterfaces().enp0s3.filter((r) => r.family === 'IPv4')[0].address, + operatingSystem: { + platform: os.platform(), + kernelVersion: os.version(), + release: os.release(), + }, + cpu: { + model: os.cpus()[0].model, + clockSpeed: os.cpus()[0].speed / 1000, + coreCount: os.cpus().length, + }, + }, }, }; res.status(200).json({ code: this.constants.codes.SUCCESS, message: response }); } catch (error) { this.handleError(error, res); - this.server.client.util.handleError(error); } }); } -- 2.20.1 From ea2a61fddd24bff46db402f8d69a244162703b86 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 4 Jul 2020 23:01:37 -0400 Subject: [PATCH 337/516] fixes to root path endpoint --- src/api/routes/Root.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/api/routes/Root.ts b/src/api/routes/Root.ts index 85c92cb..3e17b77 100644 --- a/src/api/routes/Root.ts +++ b/src/api/routes/Root.ts @@ -33,7 +33,6 @@ export default class Root extends Route { ipv4Address: os.networkInterfaces().enp0s3.filter((r) => r.family === 'IPv4')[0].address, operatingSystem: { platform: os.platform(), - kernelVersion: os.version(), release: os.release(), }, cpu: { -- 2.20.1 From 9802240e94d26069683b3c3bedf9cf2297385d86 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 4 Jul 2020 23:04:16 -0400 Subject: [PATCH 338/516] fixes to root path endpoint --- src/api/routes/Account.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/routes/Account.ts b/src/api/routes/Account.ts index 50a9384..ff5f259 100644 --- a/src/api/routes/Account.ts +++ b/src/api/routes/Account.ts @@ -53,7 +53,7 @@ export default class Account extends Route { this.server.client.redis.get(`storage-${req.account.username}`), ]); let storage: string; - if (req.query?.cache === 'true') { + if (req.query?.cache === 'false') { const val = await this.server.client.util.exec(`du -sb /home/${req.account.username}`); // eslint-disable-next-line prefer-destructuring storage = val.split('\t')[0]; -- 2.20.1 From b0239282f47ab891a326a2149963228f38204ca7 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 4 Jul 2020 23:44:49 -0400 Subject: [PATCH 339/516] add info cmd --- src/commands/index.ts | 1 + src/commands/info.ts | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/commands/info.ts diff --git a/src/commands/index.ts b/src/commands/index.ts index 029babf..0f7f9a9 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -8,6 +8,7 @@ export { default as emailcode } from './emailcode'; export { default as eval } from './eval'; export { default as exec } from './exec'; export { default as help } from './help'; +export { default as info } from './info'; export { default as limits } from './limits'; export { default as load } from './load'; export { default as lock } from './lock'; diff --git a/src/commands/info.ts b/src/commands/info.ts new file mode 100644 index 0000000..6682aca --- /dev/null +++ b/src/commands/info.ts @@ -0,0 +1,39 @@ +import { Message } from 'eris'; +import { totalmem } from 'os'; +import { Client, Command, RichEmbed } from '../class'; +import { version as erisVersion } from '../../node_modules/eris/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 ioredisVersion } from '../../node_modules/ioredis/package.json'; +import { version as tscVersion } from '../../node_modules/typescript/package.json'; + +export default class Info extends Command { + constructor(client: Client) { + super(client); + this.name = 'info'; + this.description = 'Provides information about CSD.'; + this.usage = `${this.client.config.prefix}info`; + this.enabled = true; + } + + public async run(message: Message) { + try { + const embed = new RichEmbed(); + embed.setTitle('Information'); + embed.setThumbnail(this.client.user.avatarURL); + embed.addField('Language(s)', '<:ts:604565354554982401> TypeScript, <:Go:703449475405971466> Go', 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('Process Manager', `SystemD (${await this.client.util.exec('systemd --version')})`, true); + embed.addField('Discord Library', `Eris (${erisVersion})`, true); + embed.addField('HTTP Server Library', `Express (${expressVersion})`, true); + embed.addField('Database Library', `MongoDB w/ Mongoose ODM (${mongooseVersion})`, 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('Repository', 'https://loc.sh/csdgit | Licensed under GNU Affero General Public License V3', true); + return message.channel.createMessage({ embed }); + } catch (err) { + return this.client.util.handleError(err, message, this); + } + } +} -- 2.20.1 From ea35c1984409fa77fcc4b719624dd9304986d995 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Sat, 4 Jul 2020 23:48:34 -0400 Subject: [PATCH 340/516] info command changes --- src/commands/info.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/info.ts b/src/commands/info.ts index 6682aca..e288ba6 100644 --- a/src/commands/info.ts +++ b/src/commands/info.ts @@ -24,7 +24,7 @@ export default class Info extends Command { embed.addField('Language(s)', '<:ts:604565354554982401> TypeScript, <:Go:703449475405971466> Go', 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('Process Manager', `SystemD (${await this.client.util.exec('systemd --version')})`, 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('HTTP Server Library', `Express (${expressVersion})`, true); embed.addField('Database Library', `MongoDB w/ Mongoose ODM (${mongooseVersion})`, true); -- 2.20.1 From 4d02a5feef4d0925a863b2a831bde982056c3f27 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 7 Jul 2020 05:29:34 -0400 Subject: [PATCH 341/516] new cscli cmd --- src/commands/systemd_restart.ts | 2 +- src/commands/systemd_start.ts | 2 +- src/commands/systemd_status.ts | 2 +- src/commands/systemd_stop.ts | 2 +- src/cscli/main.ts | 6 ++++++ 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/commands/systemd_restart.ts b/src/commands/systemd_restart.ts index 3e3db9b..d21fb26 100644 --- a/src/commands/systemd_restart.ts +++ b/src/commands/systemd_restart.ts @@ -7,7 +7,7 @@ export default class SystemD_Restart extends Command { this.name = 'restart'; this.description = `Restarts a SystemD user service, if the service has never been started or isn't running use \`${this.client.config.prefix}systemd start \`.`; this.usage = `${this.client.config.prefix}systemd restart `; - this.enabled = true; + this.enabled = false; } public async run(message: Message, args: string[]) { diff --git a/src/commands/systemd_start.ts b/src/commands/systemd_start.ts index 1d6029f..944dd57 100644 --- a/src/commands/systemd_start.ts +++ b/src/commands/systemd_start.ts @@ -7,7 +7,7 @@ export default class SystemD_Start extends Command { this.name = 'start'; this.description = `Starts a SystemD user service, if the service is already running use \`${this.client.config.prefix}systemd restart \`.`; this.usage = `${this.client.config.prefix}systemd start `; - this.enabled = true; + this.enabled = false; } public async run(message: Message, args: string[]) { diff --git a/src/commands/systemd_status.ts b/src/commands/systemd_status.ts index 0afcf9b..1f7d51a 100644 --- a/src/commands/systemd_status.ts +++ b/src/commands/systemd_status.ts @@ -7,7 +7,7 @@ export default class SystemD_Status extends Command { this.name = 'status'; this.description = 'Prints out the status of a SystemD service that you run.'; this.usage = `${this.client.config.prefix}systemd status `; - this.enabled = true; + this.enabled = false; } public async run(message: Message, args: string[]) { diff --git a/src/cscli/main.ts b/src/cscli/main.ts index 37e5abe..6aaba58 100644 --- a/src/cscli/main.ts +++ b/src/cscli/main.ts @@ -65,6 +65,12 @@ export default class CSCLI { socket.write(`${sshLogins}\n`); socket.destroy(); break; + case 'ramlimit': + const account = await this.client.db.Account.findOne({ username: parsed.Username }).lean().exec(); + const tier = await this.client.db.Tier.findOne({ 'resourceLimits.ram': account.tier }).lean().exec(); + socket.write(`${tier.resourceLimits.ram}`); + socket.destroy(); + break; default: socket.destroy(); break; -- 2.20.1 From b78b1a2e38a1cca3f99a430b1117cc5c39714383 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 7 Jul 2020 05:36:08 -0400 Subject: [PATCH 342/516] fix tier issue --- src/cscli/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cscli/main.ts b/src/cscli/main.ts index 6aaba58..b2452da 100644 --- a/src/cscli/main.ts +++ b/src/cscli/main.ts @@ -67,7 +67,7 @@ export default class CSCLI { break; case 'ramlimit': const account = await this.client.db.Account.findOne({ username: parsed.Username }).lean().exec(); - const tier = await this.client.db.Tier.findOne({ 'resourceLimits.ram': account.tier }).lean().exec(); + const tier = await this.client.db.Tier.findOne({ id: account.tier }).lean().exec(); socket.write(`${tier.resourceLimits.ram}`); socket.destroy(); break; -- 2.20.1 From 3a0305b6ec1a44fbf3dd39b05108ab92838b7273 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 7 Jul 2020 05:38:08 -0400 Subject: [PATCH 343/516] fix tier issue --- src/cscli/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cscli/main.ts b/src/cscli/main.ts index b2452da..84655f2 100644 --- a/src/cscli/main.ts +++ b/src/cscli/main.ts @@ -68,7 +68,7 @@ export default class CSCLI { case 'ramlimit': const account = await this.client.db.Account.findOne({ username: parsed.Username }).lean().exec(); const tier = await this.client.db.Tier.findOne({ id: account.tier }).lean().exec(); - socket.write(`${tier.resourceLimits.ram}`); + socket.write(`${tier.resourceLimits.ram}\n`); socket.destroy(); break; default: -- 2.20.1 From 98ec12266d687b0214c5a221f8038558e9a5d132 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 7 Jul 2020 21:15:10 -0400 Subject: [PATCH 344/516] changes to go func --- Makefile | 2 +- src/go/storage/storage.go | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 6bd5ba5..39b0916 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ check_cert_signatures: file dist/bin/checkCertSignatures storage: - HOME=/root go build -ldflags="-s -w" -o dist/bin/storage ${storage_files} + HOME=/root go build -ldflags="-s -w" -buildmode=pie -o dist/bin/storage ${storage_files} @chmod 740 dist/bin/storage file dist/bin/storage diff --git a/src/go/storage/storage.go b/src/go/storage/storage.go index 3fdaa61..dabfd4c 100644 --- a/src/go/storage/storage.go +++ b/src/go/storage/storage.go @@ -8,6 +8,7 @@ import ( "os" "strings" "time" + "sync" "github.com/go-redis/redis/v7" "go.mongodb.org/mongo-driver/bson" @@ -81,28 +82,31 @@ func handler(config ConfigStruct) { collection := mongoClient.Database("cloudservices").Collection("accounts") cur, err := collection.Find(context.TODO(), bson.D{}) HandleError(err, 0) - + + var wg sync.WaitGroup for cur.Next(context.TODO()) { - checkAccountSizeAndUpdate(cur.Current.Lookup("username").String(), cur.Current.Lookup("id").String()) + wg.Add(1) + go checkAccountSizeAndUpdate(cur.Current.Lookup("username").String(), cur.Current.Lookup("id").String(), &wg) fmt.Printf("Checking account information for %s\n", cur.Current.Lookup("username").String()) - time.Sleep(300000 * time.Millisecond) } + wg.Wait() err = mongoClient.Disconnect(ctx) HandleError(err, 1) fmt.Println("CSD-GO-STR finished, exiting with code 0. [GO]") os.Exit(0) } -func checkAccountSizeAndUpdate(username string, id string) { +func checkAccountSizeAndUpdate(username string, id string, wg *sync.WaitGroup) { var size float64 = 0 var userHomeDirectory string = strings.Replace(strings.Join([]string{"/home/", string(username)}, ""), "\"", "", -1) usernameFormat := strings.Replace(username, "\"", "", -1) sizeHome := DirSize(&userHomeDirectory) size += sizeHome status := RedisClient.Set("storage"+"-"+usernameFormat, size, 0) - fmt.Println(status.Name()) + fmt.Printf("Redis Status: %s [GO]\n", status.Name()) if status.Err() != nil { fmt.Println(status.Err()) } - fmt.Printf("Set Call | Username: %v, ID: %v | Bytes: %f\n [GO]", string(username), string(id), size) + fmt.Printf("Set Call | Username: %v, ID: %v | Bytes: %f [GO]\n", string(username), string(id), size) + wg.Done() } -- 2.20.1 From 529a640d9e13a3284da7136e8168486b5ec3b27d Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 7 Jul 2020 21:16:56 -0400 Subject: [PATCH 345/516] changes to go func --- src/intervals/storage.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/intervals/storage.ts b/src/intervals/storage.ts index a3298a0..a2499ac 100644 --- a/src/intervals/storage.ts +++ b/src/intervals/storage.ts @@ -11,6 +11,17 @@ export default async function storage(client: Client) { return (accounts * 2) * 60000; } let intervalTiming = await determineInterval(client); + + async function start() { + const storageDaemon = spawn(`${__dirname}/../bin/storage`, [], { cwd: __dirname }); + storageDaemon.stdout.on('data', (data) => client.signale.log(data.toString())); + storageDaemon.stderr.on('data', (data) => client.signale.log(data.toString())); + storageDaemon.on('exit', (code) => { + client.signale.log(`CSD-GO-STR Daemon exited with code ${code}.`); + storageDaemon.removeAllListeners(); + client.signale.info(`Reactivating CSD-GO-STR daemon startup interval. Reactivating in ${intervalTiming / 60000}min.`); + }); + } /* let storageGo = spawn(`${__dirname}/../bin/storage`, [], { cwd: __dirname }); storageGo.stdout.on('data', (data) => client.signale.log(data.toString())); storageGo.stderr.on('data', (data) => client.signale.log(data.toString())); @@ -21,14 +32,7 @@ export default async function storage(client: Client) { client.signale.info(`Activated CSD-GO-STR daemon startup interval. Starting in ${intervalTiming / 60000}min.`); interval = setInterval(async () => { intervalTiming = await determineInterval(client); - const storageDaemon = spawn(`${__dirname}/../bin/storage`, [], { cwd: __dirname }); - storageDaemon.stdout.on('data', (data) => client.signale.log(data.toString())); - storageDaemon.stderr.on('data', (data) => client.signale.log(data.toString())); - storageDaemon.on('exit', (code) => { - client.signale.log(`CSD-GO-STR Daemon exited with code ${code}.`); - storageDaemon.removeAllListeners(); - client.signale.info(`Reactivating CSD-GO-STR daemon startup interval. Reactivating in ${intervalTiming / 60000}min.`); - }); + await start(); }, intervalTiming); } -- 2.20.1 From 85dd17eebb8433409b16f2860657057404e26675 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Tue, 7 Jul 2020 21:21:19 -0400 Subject: [PATCH 346/516] changes to go func --- src/intervals/storage.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/intervals/storage.ts b/src/intervals/storage.ts index a2499ac..77bc29d 100644 --- a/src/intervals/storage.ts +++ b/src/intervals/storage.ts @@ -29,6 +29,7 @@ export default async function storage(client: Client) { client.signale.log(`Go storage func exited with code ${code}, restarting`); storageGo = spawn(`${__dirname}/../bin/storage`, [], { cwd: __dirname }); }); */ + await start(); client.signale.info(`Activated CSD-GO-STR daemon startup interval. Starting in ${intervalTiming / 60000}min.`); interval = setInterval(async () => { intervalTiming = await determineInterval(client); -- 2.20.1 From a314a98957233f14a7748721c5f6af0206aaa8da Mon Sep 17 00:00:00 2001 From: Bsian Date: Mon, 20 Jul 2020 23:56:55 +0100 Subject: [PATCH 347/516] Add usage --- src/commands/lock.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/lock.ts b/src/commands/lock.ts index 831dbad..273dc51 100644 --- a/src/commands/lock.ts +++ b/src/commands/lock.ts @@ -9,6 +9,7 @@ export default class Lock extends Command { this.description = 'Locks an account.'; this.permissions = { roles: ['662163685439045632', '701454780828221450'] }; this.enabled = true; + this.usage = `${this.client.config.prefix}lock [User Name | User ID/Mention]