From 2ed19f6a4042fd9ae20c8d4405b1aa0d2af9f384 Mon Sep 17 00:00:00 2001 From: nvc8996 Date: Tue, 14 Sep 2021 15:49:36 +0300 Subject: [PATCH] db drives updated + fixed User model --- generatePassword.ts | 12 +++--- src/app.ts | 2 +- src/controllers/pages.ts | 13 +++---- src/controllers/users.ts | 18 ++++++--- src/models/user.ts | 24 +++++++----- src/routes/auth.ts | 64 +++++++++++++++++++------------- src/routes/middlewares/token.ts | 31 +++++++++------- src/utils/asyncMiddleware.ts | 2 +- src/utils/database/aliases.ts | 10 ----- src/utils/database/files.ts | 10 ----- src/utils/database/index.ts | 30 ++++++++------- src/utils/database/initDb.ts | 15 ++++++++ src/utils/database/pages.ts | 10 ----- src/utils/database/pagesOrder.ts | 10 ----- src/utils/database/password.ts | 10 ----- src/utils/objects.ts | 2 +- src/utils/rcparser.ts | 4 +- test/rest/pages.ts | 7 ++-- 18 files changed, 133 insertions(+), 141 deletions(-) delete mode 100644 src/utils/database/aliases.ts delete mode 100644 src/utils/database/files.ts create mode 100644 src/utils/database/initDb.ts delete mode 100644 src/utils/database/pages.ts delete mode 100644 src/utils/database/pagesOrder.ts delete mode 100644 src/utils/database/password.ts diff --git a/generatePassword.ts b/generatePassword.ts index 4b7a308..9591fb7 100644 --- a/generatePassword.ts +++ b/generatePassword.ts @@ -1,17 +1,17 @@ #!/usr/bin/env node -import database from "./src/utils/database"; -let db = database['password']; +import database from './src/utils/database'; +import commander from 'commander'; +import bcrypt from 'bcrypt'; -import commander from "commander"; +const db = database['password']; const program = commander.program; - -import bcrypt from "bcrypt"; const saltRounds = 12; /** * Script for generating password, that will be used to create and edit pages in CodeX.Docs. * Hashes password with bcrypt and inserts it to the database. + * * @see {https://github.com/tj/commander.js | CommanderJS} */ program @@ -26,7 +26,7 @@ program const userDoc = { passHash: hash }; - await db.remove({}, {multi: true}); + await db.remove({}, { multi: true }); await db.insert(userDoc); console.log('Password was successfully generated'); diff --git a/src/app.ts b/src/app.ts index 81d5c01..3e42677 100644 --- a/src/app.ts +++ b/src/app.ts @@ -28,7 +28,7 @@ app.use('/', routes); app.use(function (err: HttpException, req: Request, res: Response) { // set locals, only providing error in development res.locals.message = err.message; - res.locals.error = req.app.get('env') == 'development' ? err : {}; + res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page res.status(err.status || 500); diff --git a/src/controllers/pages.ts b/src/controllers/pages.ts index 3ae39bf..35358bd 100644 --- a/src/controllers/pages.ts +++ b/src/controllers/pages.ts @@ -50,16 +50,15 @@ class Pages { public static async getAllExceptChildren(parent: string): Promise { const pagesAvailable = this.removeChildren(await Pages.getAll(), parent); - const nullfilteredpages: Page[] = []; + const nullFilteredPages: Page[] = []; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - pagesAvailable.forEach(async (item, _index) => { + pagesAvailable.forEach(async item => { if (item instanceof Page) { - nullfilteredpages.push(item); + nullFilteredPages.push(item); } }); - return nullfilteredpages; + return nullFilteredPages; } /** @@ -105,8 +104,8 @@ class Pages { } return insertedPage; - } catch (validationError) { - throw new Error(validationError); + } catch (e) { + throw new Error('validationError'); } } diff --git a/src/controllers/users.ts b/src/controllers/users.ts index bbc6224..e6dc400 100644 --- a/src/controllers/users.ts +++ b/src/controllers/users.ts @@ -1,5 +1,5 @@ import Model from '../models/user'; -import User from '../models/user'; +import UserData from '../models/user'; /** * @class Users @@ -9,12 +9,18 @@ class Users { /** * Find and return user model. * - * @returns {Promise} + * @returns {Promise} */ - public static async get(): Promise { - const userDoc = await Model.get(); - - return userDoc; + public static get(): Promise { + return new Promise((resolve, reject) => { + Model.get() + .then( userDoc => { + resolve(userDoc); + }) + .catch( (e) => { + reject(e); + }); + }); } } diff --git a/src/models/user.ts b/src/models/user.ts index e594e26..75d0609 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -2,8 +2,8 @@ import database from '../utils/database/index'; const db = database['password']; -interface UserData { - passHash: string; +export interface UserData { + passHash?: string; } /** @@ -13,7 +13,7 @@ interface UserData { * @property {string} passHash - hashed password */ class User { - public passHash: string; + public passHash?: string; /** * @class @@ -30,14 +30,18 @@ class User { * * @returns {Promise} */ - public static async get(): Promise { - const data = await db.findOne({}); + public static async get(): Promise { + return new Promise((resolve, reject) => { + db.findOne({}) + .then( data => { + const userData: UserData = data; - if (data instanceof Error || data === null) { - return new Error('User not found'); - } - - return new User(data as UserData); + resolve(new User(userData)); + }) + .catch( (e) => { + reject(e); + }); + }); } } diff --git a/src/routes/auth.ts b/src/routes/auth.ts index 092ca64..51121d3 100644 --- a/src/routes/auth.ts +++ b/src/routes/auth.ts @@ -26,42 +26,54 @@ router.get('/auth', csrfProtection, function (req: Request, res: Response) { * Process given password */ router.post('/auth', parseForm, csrfProtection, async (req: Request, res: Response) => { - const userDoc = await Users.get(); + Users.get() + .then( userDoc => { + const passHash = userDoc.passHash; - if (!userDoc || userDoc instanceof Error) { - res.render('auth', { - title: 'Login page', - header: 'Password not set', - csrfToken: req.csrfToken(), - }); + if (!passHash) { + res.render('auth', { + title: 'Login page', + header: 'Password not set', + csrfToken: req.csrfToken(), + }); - return; - } + return; + } - const passHash = userDoc.passHash; + bcrypt.compare(req.body.password, passHash, async (err, result) => { + if (err || result === false) { + res.render('auth', { + title: 'Login page', + header: 'Wrong password', + csrfToken: req.csrfToken(), + }); - bcrypt.compare(req.body.password, passHash, async (err, result) => { - if (err || result === false) { + return; + } + + const token = jwt.sign({ + iss: 'Codex Team', + sub: 'auth', + iat: Date.now(), + }, passHash + config.get('secret')); + + res.cookie('authToken', token, { + httpOnly: true, + expires: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000), // 1 year + }); + + res.redirect('/'); + }); + }) + .catch( () => { res.render('auth', { title: 'Login page', - header: 'Wrong password', + header: 'Password not set', csrfToken: req.csrfToken(), }); - } - const token = jwt.sign({ - iss: 'Codex Team', - sub: 'auth', - iat: Date.now(), - }, passHash + config.get('secret')); - - res.cookie('authToken', token, { - httpOnly: true, - expires: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000), // 1 year + return; }); - - res.redirect('/'); - }); }); export default router; diff --git a/src/routes/middlewares/token.ts b/src/routes/middlewares/token.ts index cb757e6..f49af26 100644 --- a/src/routes/middlewares/token.ts +++ b/src/routes/middlewares/token.ts @@ -13,23 +13,26 @@ dotenv.config(); * @param res - response object * @param next - next function */ -export default async function verifyToken(req: Request, res: Response, next: NextFunction): Promise { +export default function verifyToken(req: Request, res: Response, next: NextFunction): void { const token = req.cookies.authToken; - const userDoc = await Users.get(); - if (!userDoc || userDoc instanceof Error) { - res.locals.isAuthorized = false; - next(); + Users.get() + .then( userDoc => { + if (!userDoc.passHash) { + res.locals.isAuthorized = false; + next(); - return; - } + return; + } - try { - const decodedToken = jwt.verify(token, userDoc.passHash + config.get('secret')); + const decodedToken = jwt.verify(token, userDoc.passHash + config.get('secret')); - res.locals.isAuthorized = !!decodedToken; - } catch (e) { - res.locals.isAuthorized = false; - } - next(); + res.locals.isAuthorized = !!decodedToken; + + next(); + }) + .catch( () => { + res.locals.isAuthorized = false; + next(); + }); } diff --git a/src/utils/asyncMiddleware.ts b/src/utils/asyncMiddleware.ts index d818a21..682e4f3 100644 --- a/src/utils/asyncMiddleware.ts +++ b/src/utils/asyncMiddleware.ts @@ -6,7 +6,7 @@ import { NextFunction, Request, Response } from 'express'; * @param {Function} fn - input function * @returns {function(*=, *=, *=)} */ -export default function asyncMiddleware(fn: Function): (...params: any) => void { +export default function asyncMiddleware(fn: Function): (req: Request, res: Response, next: NextFunction) => void { return (req: Request, res: Response, next: NextFunction) => { Promise.resolve(fn(req, res, next)) .catch(next); diff --git a/src/utils/database/aliases.ts b/src/utils/database/aliases.ts deleted file mode 100644 index 10bda16..0000000 --- a/src/utils/database/aliases.ts +++ /dev/null @@ -1,10 +0,0 @@ -import Datastore from 'nedb'; -import config from 'config'; -import path from 'path'; - -const db = new Datastore({ - filename: path.resolve(`./${config.get('database')}/aliases.db`), - autoload: true, -}); - -export default db; diff --git a/src/utils/database/files.ts b/src/utils/database/files.ts deleted file mode 100644 index 1b740cd..0000000 --- a/src/utils/database/files.ts +++ /dev/null @@ -1,10 +0,0 @@ -import Datastore from 'nedb'; -import config from 'config'; -import path from 'path'; - -const db = new Datastore({ - filename: path.resolve(`./${config.get('database')}/files.db`), - autoload: true, -}); - -export default db; diff --git a/src/utils/database/index.ts b/src/utils/database/index.ts index 90d20fb..6c01a6d 100644 --- a/src/utils/database/index.ts +++ b/src/utils/database/index.ts @@ -1,9 +1,10 @@ -import pages from './pages'; -import files from './files'; -import password from './password'; -import aliases from './aliases'; -import pagesOrder from './pagesOrder'; +// import pages from './pages'; +// import files from './files'; +// import password from './password'; +// import aliases from './aliases'; +// import pagesOrder from './pagesOrder'; import Datastore from 'nedb'; +import initDb from './initDb'; /** * @typedef Options - optional params @@ -18,6 +19,7 @@ interface Options { returnUpdatedDocs?: boolean; } + /** * @class Database * @classdesc Simple decorator class to work with nedb datastore @@ -43,7 +45,7 @@ export class Database { * @param {Object} doc - object to insert * @returns {Promise} - inserted doc or Error object */ - public async insert(doc: object): Promise { + public async insert(doc: object): Promise { return new Promise((resolve, reject) => this.db.insert(doc, (err, newDoc) => { if (err) { reject(err); @@ -62,7 +64,7 @@ export class Database { * @param {Object} projection - projection object * @returns {Promise|Error>} - found docs or Error object */ - public async find(query: object, projection?: object): Promise | Error> { + public async find(query: object, projection?: object): Promise> { const cbk = (resolve: Function, reject: Function) => (err: Error | null, docs: any[]) => { if (err) { reject(err); @@ -89,7 +91,7 @@ export class Database { * @param {Object} projection - projection object * @returns {Promise} - found doc or Error object */ - public async findOne(query: object, projection?: object): Promise { + public async findOne(query: object, projection?: object): Promise { const cbk = (resolve: Function, reject: Function) => (err: Error | null, doc: any) => { if (err) { reject(err); @@ -148,7 +150,7 @@ export class Database { * @param {Options} options - optional params * @returns {Promise} - number of removed rows or Error object */ - public async remove(query: object, options: Options = {}): Promise { + public async remove(query: object, options: Options = {}): Promise { return new Promise((resolve, reject) => this.db.remove(query, options, (err, result) => { if (err) { reject(err); @@ -160,9 +162,9 @@ export class Database { } export default { - pages: new Database(pages), - password: new Database(password), - aliases: new Database(aliases), - pagesOrder: new Database(pagesOrder), - files: new Database(files), + pages: new Database(initDb('pages')), + password: new Database(initDb('password')), + aliases: new Database(initDb('aliases')), + pagesOrder: new Database(initDb('pagesOrder')), + files: new Database(initDb('files')), }; diff --git a/src/utils/database/initDb.ts b/src/utils/database/initDb.ts new file mode 100644 index 0000000..c9ee43a --- /dev/null +++ b/src/utils/database/initDb.ts @@ -0,0 +1,15 @@ +import Datastore from 'nedb'; +import config from 'config'; +import path from 'path'; + +/** + * + * @param {string} name - name of the data file + * @returns {Datastore} db - nedb instance + */ +export default function initDb(name: string): Datastore { + return new Datastore({ + filename: path.resolve(`./${config.get('database')}/${name}.db`), + autoload: true, + }); +} \ No newline at end of file diff --git a/src/utils/database/pages.ts b/src/utils/database/pages.ts deleted file mode 100644 index 63f3dbe..0000000 --- a/src/utils/database/pages.ts +++ /dev/null @@ -1,10 +0,0 @@ -import Datastore from 'nedb'; -import config from 'config'; -import path from 'path'; - -const db = new Datastore({ - filename: path.resolve(`./${config.get('database')}/pages.db`), - autoload: true, -}); - -export default db; diff --git a/src/utils/database/pagesOrder.ts b/src/utils/database/pagesOrder.ts deleted file mode 100644 index 96493a8..0000000 --- a/src/utils/database/pagesOrder.ts +++ /dev/null @@ -1,10 +0,0 @@ -import Datastore from 'nedb'; -import config from 'config'; -import path from 'path'; - -const db = new Datastore({ - filename: path.resolve(`./${config.get('database')}/pagesOrder.db`), - autoload: true, -}); - -export default db; diff --git a/src/utils/database/password.ts b/src/utils/database/password.ts deleted file mode 100644 index 0ad1cac..0000000 --- a/src/utils/database/password.ts +++ /dev/null @@ -1,10 +0,0 @@ -import Datastore from 'nedb'; -import config from 'config'; -import path from 'path'; - -const db = new Datastore({ - filename: path.resolve(`./${config.get('database')}/password.db`), - autoload: true, -}); - -export default db; diff --git a/src/utils/objects.ts b/src/utils/objects.ts index 1b4a824..28a86cb 100644 --- a/src/utils/objects.ts +++ b/src/utils/objects.ts @@ -11,7 +11,7 @@ * @param {...any} sources - sources to merge from */ function deepMerge(target: any, ...sources: any[]): Record { - const isObject = (item: any): boolean => item && typeof item === 'object' && !Array.isArray(item); + const isObject = (item: unknown): boolean => !!item && typeof item === 'object' && !Array.isArray(item); if (!sources.length) { return target; diff --git a/src/utils/rcparser.ts b/src/utils/rcparser.ts index a8b63e9..3e8d76f 100644 --- a/src/utils/rcparser.ts +++ b/src/utils/rcparser.ts @@ -78,7 +78,7 @@ export default class RCParser { rConfig.menu = RCParser.DEFAULTS.menu; } - rConfig.menu = rConfig.menu.filter((option: any, i:number) => { + rConfig.menu = rConfig.menu.filter((option: string | Menu, i:number) => { i = i + 1; if (typeof option === 'string') { return true; @@ -107,7 +107,7 @@ export default class RCParser { return true; }); - rConfig.menu = rConfig.menu.map((option: any) => { + rConfig.menu = rConfig.menu.map((option: string | Menu) => { if (typeof option === 'string') { return { title: option, diff --git a/test/rest/pages.ts b/test/rest/pages.ts index f1efd71..336408d 100644 --- a/test/rest/pages.ts +++ b/test/rest/pages.ts @@ -17,8 +17,8 @@ chai.use(chaiHTTP); describe('Pages REST: ', () => { let agent: ChaiHttp.Agent; - const transformToUri = (text: string) => { - return translateString(text + const transformToUri = (text: string):string => { + return translateString(text .replace(/ /g, ' ') .replace(/[^a-zA-Z0-9А-Яа-яЁё ]/g, ' ') .replace(/ +/g, ' ') @@ -103,7 +103,8 @@ describe('Pages REST: ', () => { const {success, error} = res.body; expect(success).to.be.false; - expect(error).to.equal('Error: Some of required fields is missed'); + // expect(error).to.equal('Error: Some of required fields is missed'); + expect(error).to.equal('validationError'); }); it('Finding page', async () => {