From 7a799206386336f42706a4542f821a3b83ad2601 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Fri, 18 Dec 2020 18:27:23 -0500 Subject: [PATCH] cscli tcp rewrite --- src/cscli/handlers/index.ts | 8 ++ src/cscli/handlers/killpid.ts | 13 ++++ src/cscli/handlers/lock.ts | 13 ++++ src/cscli/handlers/processCount.ts | 13 ++++ src/cscli/handlers/ram.ts | 14 ++++ src/cscli/handlers/ramLimit.ts | 14 ++++ src/cscli/handlers/score.ts | 24 ++++++ src/cscli/handlers/sshLogins.ts | 13 ++++ src/cscli/handlers/storage.ts | 14 ++++ src/cscli/handlers/userInfo.ts | 13 ++++ src/cscli/index.ts | 1 + src/cscli/main.ts | 119 +++++++++++++++-------------- 12 files changed, 201 insertions(+), 58 deletions(-) create mode 100644 src/cscli/handlers/index.ts create mode 100644 src/cscli/handlers/killpid.ts create mode 100644 src/cscli/handlers/lock.ts create mode 100644 src/cscli/handlers/processCount.ts create mode 100644 src/cscli/handlers/ram.ts create mode 100644 src/cscli/handlers/ramLimit.ts create mode 100644 src/cscli/handlers/score.ts create mode 100644 src/cscli/handlers/sshLogins.ts create mode 100644 src/cscli/handlers/storage.ts create mode 100644 src/cscli/handlers/userInfo.ts create mode 100644 src/cscli/index.ts diff --git a/src/cscli/handlers/index.ts b/src/cscli/handlers/index.ts new file mode 100644 index 0000000..d02d3a4 --- /dev/null +++ b/src/cscli/handlers/index.ts @@ -0,0 +1,8 @@ +export { default as killpid } from './killpid'; +export { default as lock } from './lock'; +export { default as processCount } from './processCount'; +export { default as ram } from './ram'; +export { default as ramLimit } from './ramLimit'; +export { default as score } from './score'; +export { default as sshLogins } from './sshLogins'; +export { default as storage } from './storage'; diff --git a/src/cscli/handlers/killpid.ts b/src/cscli/handlers/killpid.ts new file mode 100644 index 0000000..97a53f0 --- /dev/null +++ b/src/cscli/handlers/killpid.ts @@ -0,0 +1,13 @@ +import { TCPHandler, Context } from '..'; + +export default class KillPID extends TCPHandler { + constructor() { + super(); + this.endpoint = 'killpid'; + } + + public async handle(ctx: Context) { + await ctx.client.util.exec(`kill -9 ${ctx.data.message}`); + return ctx.socket.destroy(); + } +} diff --git a/src/cscli/handlers/lock.ts b/src/cscli/handlers/lock.ts new file mode 100644 index 0000000..66987f4 --- /dev/null +++ b/src/cscli/handlers/lock.ts @@ -0,0 +1,13 @@ +import { TCPHandler, Context } from '..'; + +export default class Lock extends TCPHandler { + constructor() { + super(); + this.endpoint = 'lock'; + } + + public async handle(ctx: Context) { + await ctx.client.util.accounts.lock(ctx.data.username, ctx.client.user.id, { reason: ctx.data.message }); + return ctx.socket.destroy(); + } +} diff --git a/src/cscli/handlers/processCount.ts b/src/cscli/handlers/processCount.ts new file mode 100644 index 0000000..d41c140 --- /dev/null +++ b/src/cscli/handlers/processCount.ts @@ -0,0 +1,13 @@ +import { TCPHandler, Context } from '..'; + +export default class ProcessCount extends TCPHandler { + constructor() { + super(); + this.endpoint = 'processcount'; + } + + public async handle(ctx: Context) { + const processCount = await ctx.client.util.exec(`ps -U ${ctx.data.username} -u ${ctx.data.username} u | wc -l`); + return ctx.send(processCount); + } +} diff --git a/src/cscli/handlers/ram.ts b/src/cscli/handlers/ram.ts new file mode 100644 index 0000000..114d41b --- /dev/null +++ b/src/cscli/handlers/ram.ts @@ -0,0 +1,14 @@ +import { TCPHandler, Context } from '..'; +import { dataConversion } from '../../functions'; + +export default class RAM extends TCPHandler { + constructor() { + super(); + this.endpoint = 'ram'; + } + + public async handle(ctx: Context) { + const memoryConversion = dataConversion(Number(await ctx.client.util.exec(`memory ${ctx.data.username}`)) * 1000); + return ctx.send(memoryConversion); + } +} diff --git a/src/cscli/handlers/ramLimit.ts b/src/cscli/handlers/ramLimit.ts new file mode 100644 index 0000000..442c39d --- /dev/null +++ b/src/cscli/handlers/ramLimit.ts @@ -0,0 +1,14 @@ +import { TCPHandler, Context } from '..'; + +export default class RAMLimits extends TCPHandler { + constructor() { + super(); + this.endpoint = 'ramlimit'; + } + + public async handle(ctx: Context) { + const account = await ctx.client.db.Account.findOne({ username: ctx.data.username }).lean().exec(); + const tier = await ctx.client.db.Tier.findOne({ id: account.tier }).lean().exec(); + return ctx.send(tier.resourceLimits.ram.toString()); + } +} diff --git a/src/cscli/handlers/score.ts b/src/cscli/handlers/score.ts new file mode 100644 index 0000000..9c04dbe --- /dev/null +++ b/src/cscli/handlers/score.ts @@ -0,0 +1,24 @@ +import { TCPHandler, Context } from '..'; +import { Report } from '../../class'; + +export default class Score extends TCPHandler { + constructor() { + super(); + this.endpoint = 'score'; + } + + public async handle(ctx: Context) { + const acc = await ctx.client.db.Account.findOne({ username: ctx.data.username }); + if (!acc) { return ctx.socket.destroy(); } + const pin = await Report.getPIN(acc.userID, ctx.client.config.internalKey); + if (pin.status !== 'SUCCESS') { return ctx.socket.destroy(); } + + const report = await Report.soft(acc.userID, pin.pin[2], ctx.client.config.vendorKey); + if (report.status !== 'SUCCESS') { return ctx.socket.destroy(); } + + if (!report.totalScore) { return ctx.send('N/C'); } + if (report.totalScore === 0) { return ctx.send('---'); } + + return ctx.send(report.totalScore.toString()); + } +} diff --git a/src/cscli/handlers/sshLogins.ts b/src/cscli/handlers/sshLogins.ts new file mode 100644 index 0000000..2b29fb8 --- /dev/null +++ b/src/cscli/handlers/sshLogins.ts @@ -0,0 +1,13 @@ +import { TCPHandler, Context } from '..'; + +export default class SSHLogins extends TCPHandler { + constructor() { + super(); + this.endpoint = 'sshlogins'; + } + + public async handle(ctx: Context) { + const sshLogins = await ctx.client.util.exec(`who | grep ${ctx.data.username} | wc -l`); + return ctx.send(sshLogins); + } +} diff --git a/src/cscli/handlers/storage.ts b/src/cscli/handlers/storage.ts new file mode 100644 index 0000000..9c6f529 --- /dev/null +++ b/src/cscli/handlers/storage.ts @@ -0,0 +1,14 @@ +import { TCPHandler, Context } from '..'; +import { dataConversion } from '../../functions'; + +export default class Storage extends TCPHandler { + constructor() { + super(); + this.endpoint = 'storage'; + } + + public async handle(ctx: Context) { + const res = await ctx.client.redis.get(`storage-${ctx.data.username}`) ? dataConversion(Number(await ctx.client.redis.get(`storage-${ctx.data.username}`))) : 'N/A'; + return ctx.send(res); + } +} diff --git a/src/cscli/handlers/userInfo.ts b/src/cscli/handlers/userInfo.ts new file mode 100644 index 0000000..fbdf788 --- /dev/null +++ b/src/cscli/handlers/userInfo.ts @@ -0,0 +1,13 @@ +import { TCPHandler, Context } from '..'; + +export default class UserInfo extends TCPHandler { + constructor() { + super(); + this.endpoint = 'userinfo'; + } + + public async handle(ctx: Context) { + const account = await ctx.client.db.Account.findOne({ username: ctx.data.username }); + return ctx.send(account.toJSON()); + } +} diff --git a/src/cscli/index.ts b/src/cscli/index.ts new file mode 100644 index 0000000..12fdc49 --- /dev/null +++ b/src/cscli/index.ts @@ -0,0 +1 @@ +export { default as CSCLI, TCPHandler, Context } from './main'; diff --git a/src/cscli/main.ts b/src/cscli/main.ts index 9963ed0..7e947a4 100644 --- a/src/cscli/main.ts +++ b/src/cscli/main.ts @@ -1,16 +1,59 @@ +/* eslint-disable max-classes-per-file */ /* 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, Report } from '../class'; -import { dataConversion } from '../functions'; +import { Client, Collection } from '../class'; + +import * as handlerFiles from './handlers'; + +export class TCPHandler { + public endpoint: string; + + public handle(ctx: Context): Promise { return Promise.resolve(); } +} + +export class Context { + public socket: net.Socket; + + public client: Client; + + public data: { + username: string, + endpoint: string, + message?: string, + additionalData?: object, + HMAC: string, + } + + constructor(socket: net.Socket, data: string, client: Client) { + const parsed: { Username: string, Type: string, Message?: string, Data?: object, HMAC: string } = JSON.parse(data); + + this.socket = socket; + this.client = client; + this.data = { + username: parsed.Username, + endpoint: parsed.Type, + message: parsed.Message, + additionalData: parsed.Data, + HMAC: parsed.HMAC, + }; + } + + public send(v: string) { + this.socket.write(`${v.toString()}\n`); + this.socket.destroy(); + } +} export default class CSCLI { public client: Client; public server: net.Server; + public handlers: Collection; + #hmac: string; constructor(client: Client) { @@ -29,6 +72,15 @@ export default class CSCLI { this.init(); } + public load() { + const hdFiles = Object.values(handlerFiles); + for (const Handler of hdFiles) { + const handler = new Handler(); + this.handlers.add(handler.endpoint, handler); + this.client.signale.success(`Successfully loaded TCP endpoint '${handler.endpoint}'.`); + } + } + public async handle(socket: net.Socket, data: Buffer) { const args = data.toString().trim().split('$'); const verification = this.verifyConnection(args[1], args[0]); @@ -36,64 +88,15 @@ export default class CSCLI { 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]); + const parsed: { Username: string, Type: string, Message?: string, Data?: any, HMAC: string } = JSON.parse(args[0]); // FINISH VERIFICATION CHECKS - switch (parsed.Type) { - case 'score': - try { - const acc = await this.client.db.Account.findOne({ username: parsed.Username }); - if (!acc) { socket.destroy(); break; } - const pin = await Report.getPIN(acc.userID, this.client.config.internalKey); - if (pin.status !== 'SUCCESS') { socket.destroy(); break; } + const handler: TCPHandler = this.handlers.get(parsed.Type); + if (!handler) return socket.destroy(); - const report = await Report.soft(acc.userID, pin.pin[2], this.client.config.vendorKey); - if (report.status !== 'SUCCESS') { socket.destroy(); break; } - - if (!report.totalScore) { socket.write('N/C\n'); socket.destroy(); break; } - if (report.totalScore === 0) { socket.write('---\n'); socket.destroy(); break; } - - socket.write(`${report.totalScore}\n`); - socket.destroy(); - } catch { - socket.write('---\n'); - socket.destroy(); - } - break; - 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; - 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; - 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}\n`); - socket.destroy(); - break; - default: - socket.destroy(); - break; + const context = new Context(socket, args[0], this.client); + await handler.handle(context); + if (!context.socket.destroyed) { + socket.destroy(); } }