diff --git a/src/api/Security.ts b/src/api/Security.ts index b3962c3..0d96067 100644 --- a/src/api/Security.ts +++ b/src/api/Security.ts @@ -1,15 +1,23 @@ import crypto from 'crypto'; import { Request } from 'express'; import { Client } from '..'; +import { AccountInterface } from '../models'; export default class Security { public client: Client; - public keyPair: { publicKey: string, privateKey: string }; + private keyBase: { key: string, iv: string }; constructor(client: Client) { this.client = client; - this.keyPair = require(`${process.cwd()}/keys.json`); + this.keyBase = require(`${process.cwd()}/keys.json`); + } + + get keys() { + return { + key: Buffer.from(this.keyBase.key, 'base64'), + iv: Buffer.from(this.keyBase.iv, 'base64'), + }; } /** @@ -19,26 +27,22 @@ export default class Security { public async createBearer(_id: string): Promise { const account = await this.client.db.Account.findOne({ _id }); if (!account) throw new Error(`Account [${_id}] cannot be found.`); - const bearer = crypto.randomBytes(12).toString('base64'); - const sign = crypto.createSign('sha3-224'); - sign.update(bearer); - sign.end(); - const signature = sign.sign(this.keyPair.privateKey, 'hex'); - await account.updateOne({ bearerSignature: signature }); - return bearer; + const cipher = crypto.createCipheriv('aes-256-gcm', this.keys.key, this.keys.iv); + let encrypted = cipher.update(JSON.stringify(account), 'utf8', 'base64'); + encrypted += cipher.final('base64'); + return encrypted; } - public async checkBearer(_id: string, bearer: string): Promise { - const account = await this.client.db.Account.findOne({ _id }); - if (!account) return false; - if (!account.bearerSignature) return false; - const verify = crypto.createVerify('sha3-224'); - verify.update(bearer); - verify.end(); + public async checkBearer(bearer: string): Promise { + const decipher = crypto.createDecipheriv('aes-256-gcm', this.keys.key, this.keys.iv); try { - return verify.verify(this.keyPair.publicKey, account.bearerSignature, 'hex'); + let decrypted = decipher.update(bearer, 'base64', 'utf8'); + decrypted += decipher.final('utf8'); + const json = JSON.parse(decrypted); + const account = await this.client.db.Account.findOne({ username: json.username }); + return account; } catch { - return false; + return null; } } diff --git a/src/api/interfaces.ts b/src/api/interfaces.ts new file mode 100644 index 0000000..411ad80 --- /dev/null +++ b/src/api/interfaces.ts @@ -0,0 +1,6 @@ +import express from 'express'; +import { AccountInterface } from '../models'; + +export interface Req extends express.Request { + account: AccountInterface +} diff --git a/src/api/routes/Account.ts b/src/api/routes/Account.ts index 6f120a0..830edbb 100644 --- a/src/api/routes/Account.ts +++ b/src/api/routes/Account.ts @@ -1,6 +1,7 @@ /* eslint-disable consistent-return */ import { Server } from '..'; import { Route } from '../../class'; +import { Req } from '../interfaces'; export default class Account extends Route { constructor(server: Server) { @@ -9,26 +10,34 @@ export default class Account extends Route { public bind() { this.router.use(async (req, res, next) => { - const account = await this.server.client.db.Account.findOne({ username: req.query.username }); - if (!account) return res.status(401).json({ code: this.constants.codes.ACCOUNT_NOT_FOUND, message: 'UNAUTHORIZED' }); - // eslint-disable-next-line no-underscore-dangle - const authResult = await this.server.security.checkBearer(account._id, this.server.security.extractBearer(req)); - if (!authResult) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: 'UNAUTHORIZED' }); + const account = await this.server.security.checkBearer(this.server.security.extractBearer(req)); + if (!account) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: 'BEARER_TOKEN_INVALID' }); + Object.defineProperty(req, 'account', { value: account, writable: true, enumerable: true, configurable: true }); next(); }); - this.router.get('/', async (req, res) => { - const account = await this.server.client.db.Account.findOne({ username: req.query.username }); + this.router.get('/', async (req: Req, res) => { const acc: any = {}; - acc.username = account.username; - acc.userID = account.userID; - acc.email = account.emailAddress; - acc.locked = account.locked; - acc.root = account.root; - acc.createdAt = account.createdAt; - acc.createdBy = account.createdBy; - acc.permissions = account.permissions; + acc.username = req.account.username; + acc.userID = req.account.userID; + acc.email = req.account.emailAddress; + acc.locked = req.account.locked; + acc.root = req.account.root; + acc.createdAt = req.account.createdAt; + acc.createdBy = req.account.createdBy; + acc.permissions = req.account.permissions; res.status(200).json({ code: this.constants.codes.SUCCESS, message: acc }); }); + + this.router.get('/moderations/:id', async (req: Req, res) => { + const moderations = await this.server.client.db.Moderation.find({ username: req.account.username }); + if (!moderations.length) res.sendStatus(204); + 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 } }); + } else { + res.status(200).json({ code: this.constants.codes.SUCCESS, message: moderations }); + } + }); } } diff --git a/src/models/Account.ts b/src/models/Account.ts index 3baa9f7..b05241d 100644 --- a/src/models/Account.ts +++ b/src/models/Account.ts @@ -7,7 +7,6 @@ export interface AccountInterface extends Document { createdBy: string, createdAt: Date, locked: boolean, - bearerSignature: string, permissions: { support: boolean, staff: boolean, @@ -26,7 +25,6 @@ const Account: Schema = new Schema({ createdBy: String, createdAt: Date, locked: Boolean, - bearerSignature: String, permissions: { support: Boolean, staff: Boolean,