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.'); + }); + } +}