mirror of
https://github.com/codex-team/codex.docs.git
synced 2025-08-07 14:35:26 +02:00
db drives updated + fixed User model
This commit is contained in:
parent
e538a5edf8
commit
2ed19f6a40
18 changed files with 133 additions and 141 deletions
|
@ -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');
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -50,16 +50,15 @@ class Pages {
|
|||
public static async getAllExceptChildren(parent: string): Promise<Page[]> {
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<User>}
|
||||
* @returns {Promise<UserData>}
|
||||
*/
|
||||
public static async get(): Promise<User|Error> {
|
||||
const userDoc = await Model.get();
|
||||
|
||||
return userDoc;
|
||||
public static get(): Promise<UserData> {
|
||||
return new Promise((resolve, reject) => {
|
||||
Model.get()
|
||||
.then( userDoc => {
|
||||
resolve(userDoc);
|
||||
})
|
||||
.catch( (e) => {
|
||||
reject(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<User>}
|
||||
*/
|
||||
public static async get(): Promise<User|Error> {
|
||||
const data = await db.findOne({});
|
||||
public static async get(): Promise<User> {
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<void> {
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -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<Object|Error>} - inserted doc or Error object
|
||||
*/
|
||||
public async insert(doc: object): Promise<object | Error> {
|
||||
public async insert(doc: object): Promise<object> {
|
||||
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<Array<Object>|Error>} - found docs or Error object
|
||||
*/
|
||||
public async find(query: object, projection?: object): Promise<Array<object> | Error> {
|
||||
public async find(query: object, projection?: object): Promise<Array<object>> {
|
||||
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<Object|Error>} - found doc or Error object
|
||||
*/
|
||||
public async findOne(query: object, projection?: object): Promise<object | Error> {
|
||||
public async findOne(query: object, projection?: object): Promise<object> {
|
||||
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|Error>} - number of removed rows or Error object
|
||||
*/
|
||||
public async remove(query: object, options: Options = {}): Promise<number|Error> {
|
||||
public async remove(query: object, options: Options = {}): Promise<number> {
|
||||
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')),
|
||||
};
|
||||
|
|
15
src/utils/database/initDb.ts
Normal file
15
src/utils/database/initDb.ts
Normal file
|
@ -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,
|
||||
});
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -11,7 +11,7 @@
|
|||
* @param {...any} sources - sources to merge from
|
||||
*/
|
||||
function deepMerge(target: any, ...sources: any[]): Record<string, unknown> {
|
||||
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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue