Change Bearer methods (verify to encrypt)

merge-requests/1/merge
Matthew 2019-11-16 22:55:25 -05:00
parent ba214c5335
commit b0fe33f98a
No known key found for this signature in database
GPG Key ID: 766BE43AE75F7559
4 changed files with 52 additions and 35 deletions

View File

@ -1,15 +1,23 @@
import crypto from 'crypto'; import crypto from 'crypto';
import { Request } from 'express'; import { Request } from 'express';
import { Client } from '..'; import { Client } from '..';
import { AccountInterface } from '../models';
export default class Security { export default class Security {
public client: Client; public client: Client;
public keyPair: { publicKey: string, privateKey: string }; private keyBase: { key: string, iv: string };
constructor(client: Client) { constructor(client: Client) {
this.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<string> { public async createBearer(_id: string): Promise<string> {
const 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.`); if (!account) throw new Error(`Account [${_id}] cannot be found.`);
const bearer = crypto.randomBytes(12).toString('base64'); const cipher = crypto.createCipheriv('aes-256-gcm', this.keys.key, this.keys.iv);
const sign = crypto.createSign('sha3-224'); let encrypted = cipher.update(JSON.stringify(account), 'utf8', 'base64');
sign.update(bearer); encrypted += cipher.final('base64');
sign.end(); return encrypted;
const signature = sign.sign(this.keyPair.privateKey, 'hex');
await account.updateOne({ bearerSignature: signature });
return bearer;
} }
public async checkBearer(_id: string, bearer: string): Promise<boolean> { public async checkBearer(bearer: string): Promise<null | AccountInterface> {
const account = await this.client.db.Account.findOne({ _id }); const decipher = crypto.createDecipheriv('aes-256-gcm', this.keys.key, this.keys.iv);
if (!account) return false;
if (!account.bearerSignature) return false;
const verify = crypto.createVerify('sha3-224');
verify.update(bearer);
verify.end();
try { 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 { } catch {
return false; return null;
} }
} }

6
src/api/interfaces.ts Normal file
View File

@ -0,0 +1,6 @@
import express from 'express';
import { AccountInterface } from '../models';
export interface Req extends express.Request {
account: AccountInterface
}

View File

@ -1,6 +1,7 @@
/* eslint-disable consistent-return */ /* eslint-disable consistent-return */
import { Server } from '..'; import { Server } from '..';
import { Route } from '../../class'; import { Route } from '../../class';
import { Req } from '../interfaces';
export default class Account extends Route { export default class Account extends Route {
constructor(server: Server) { constructor(server: Server) {
@ -9,26 +10,34 @@ export default class Account extends Route {
public bind() { public bind() {
this.router.use(async (req, res, next) => { this.router.use(async (req, res, next) => {
const account = await this.server.client.db.Account.findOne({ username: req.query.username }); const account = await this.server.security.checkBearer(this.server.security.extractBearer(req));
if (!account) return res.status(401).json({ code: this.constants.codes.ACCOUNT_NOT_FOUND, message: 'UNAUTHORIZED' }); if (!account) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: 'BEARER_TOKEN_INVALID' });
// eslint-disable-next-line no-underscore-dangle Object.defineProperty(req, 'account', { value: account, writable: true, enumerable: true, configurable: true });
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' });
next(); next();
}); });
this.router.get('/', async (req, res) => { this.router.get('/', async (req: Req, res) => {
const account = await this.server.client.db.Account.findOne({ username: req.query.username });
const acc: any = {}; const acc: any = {};
acc.username = account.username; acc.username = req.account.username;
acc.userID = account.userID; acc.userID = req.account.userID;
acc.email = account.emailAddress; acc.email = req.account.emailAddress;
acc.locked = account.locked; acc.locked = req.account.locked;
acc.root = account.root; acc.root = req.account.root;
acc.createdAt = account.createdAt; acc.createdAt = req.account.createdAt;
acc.createdBy = account.createdBy; acc.createdBy = req.account.createdBy;
acc.permissions = account.permissions; acc.permissions = req.account.permissions;
res.status(200).json({ code: this.constants.codes.SUCCESS, message: acc }); 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 });
}
});
} }
} }

View File

@ -7,7 +7,6 @@ export interface AccountInterface extends Document {
createdBy: string, createdBy: string,
createdAt: Date, createdAt: Date,
locked: boolean, locked: boolean,
bearerSignature: string,
permissions: { permissions: {
support: boolean, support: boolean,
staff: boolean, staff: boolean,
@ -26,7 +25,6 @@ const Account: Schema = new Schema({
createdBy: String, createdBy: String,
createdAt: Date, createdAt: Date,
locked: Boolean, locked: Boolean,
bearerSignature: String,
permissions: { permissions: {
support: Boolean, support: Boolean,
staff: Boolean, staff: Boolean,