Advertisement
Guest User

Untitled

a guest
Feb 26th, 2020
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. const fs = require('fs');
  2. var jwt = require('jsonwebtoken');
  3. const File = require(`${__dirlibs}/File`);
  4. const _ = require('lodash');
  5.  
  6. // ----------------------------------------------------------------------------------------------------------
  7.  
  8. var controllers = {}
  9. var routesList = {}
  10.  
  11. // ----------------------------------------------------------------------------------------------------------
  12.  
  13. function loadControllersAndRoutes() {
  14.     fs.readdirSync(`${__dircontrollers}/rest`).forEach(file => {
  15.         let controllerName = file.split('.')[0];
  16.         controllers[controllerName] = new (require(`${__dircontrollers}/rest/${file}`))(controllerName);
  17.     });
  18.    
  19.     fs.readdirSync(`${__dirapp}/routes`).forEach(file => {
  20.         let routeName = file.split('.')[0];
  21.         routesList[routeName] = require(`${__dirapp}/routes/${file}`);
  22.     });
  23. }
  24.  
  25. // ----------------------------------------------------------------------------------------------------------
  26.  
  27. class Router {
  28.     constructor() {
  29.         if(!Object.keys(controllers).length)
  30.             loadControllersAndRoutes();
  31.        
  32.         return (req, res, next) => {
  33.             if(req.method == 'OPTIONS') return res.status(200);
  34.  
  35.             res.success       = (data) => { res.status(200).send({status: 200, data: data}).end() };
  36.             res.accessDenied  = (data) => { res.status(403).send({status: 403, data: data}).end() };
  37.             res.notFound      = (data) => { res.status(404).send({status: 404}).end() };
  38.             res.error         = (data) => { LOGGER.error(JSON.stringify(data)); res.status(400).send({status: 400, data: data}).end() };
  39.             res.answer        = ({status: status, data: data}) => { res.status(status).send(data) };
  40.  
  41.             this.setHeaders(req, res);
  42.             this.handleRequest(req, res);
  43.         }
  44.     }
  45.  
  46.     setHeaders(req, res) {
  47.         res.setHeader('Access-Control-Allow-Origin', '*');
  48.         res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT, DELETE');
  49.         res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Token');
  50.         res.setHeader('Access-Control-Expose-Headers', 'X-Token');
  51.         // res.setHeader('Access-Control-Max-Age', config.maxAge);
  52.     }
  53.  
  54.     checkBodyParams(req, routes, route) {
  55.         for(let param in routes[route].body) {
  56.             if(req.body.hasOwnProperty(param)) {
  57.                 if(routes[route].body[param].regex) {
  58.                     if(!req.body[param].match(routes[route].body[param].regex)) {
  59.                         return {
  60.                             status: false,
  61.                             error: routes[route].body[param].err ? routes[route].body[param].err : `wrong  ${param} format!`
  62.                         };
  63.                     }
  64.                 }
  65.             } else {
  66.                 return {status: false, error: `${param} param is required!`};
  67.             }
  68.         }
  69.  
  70.         return {status:true};
  71.     }
  72.  
  73.     checkQueryParams(actualParams, validParams) {
  74.         let diff = _.differenceWith(_.keys(actualParams), validParams, _.isEqual);
  75.  
  76.         return {status: diff.length == 0, error: 'Unacceptable params ' + diff};
  77.     }
  78.  
  79.     checkFiles(actualFiles, validFiles) {
  80.         let result = {status: true};
  81.  
  82.         for(let file in validFiles) {
  83.             if(validFiles[file].required && !_.keys(actualFiles).includes(file)) {
  84.                 result.status = false;
  85.                 result.error = `No required file with name = "${file}" found!`;
  86.                 break;
  87.             }
  88.  
  89.             if(validFiles[file].maxSize && _.keys(actualFiles).includes(file)) {
  90.                 let maxSize = File.size(validFiles[file].maxSize);
  91.  
  92.                 if(actualFiles[file].size >= maxSize) {
  93.                     result.status = false;
  94.                     result.error = `The size of the file "${file}" is greater than ${validFiles[file].maxSize}!`;
  95.                     break;
  96.                 }
  97.             }
  98.         }
  99.  
  100.         return result;
  101.     }
  102.  
  103.     __validateJWT(token) {
  104.         if(token.match(/^Bearer.+/))
  105.             token = token.replace(/^Bearer /i, '');
  106.            
  107.         try {
  108.             return {validated:true, decoded: jwt.verify(token, __config.secretSalt)}
  109.         } catch (e) {
  110.             return {validated:false, err: e}
  111.         }
  112.     }
  113.  
  114.     __getQueryDict(route, reqPath) {
  115.         let queryKeys = route.match(/(:\w+)/gi)||[];
  116.         let splitedRoute = route.split('/');
  117.         let splitedPath = reqPath.split('/');
  118.         let indexes = queryKeys.map(__ => splitedRoute.indexOf(__))
  119.         let queryDict = {};
  120.        
  121.         for(let i in queryKeys)
  122.             queryDict[queryKeys[i].substr(1, queryKeys[i].length)] = splitedPath[indexes[i]];
  123.     }
  124.  
  125.     async handleRequest(req, res) {
  126.         LOGGER.route(req);
  127.  
  128.         for(let controllerName in controllers) {
  129.             let routes = routesList[controllerName];
  130.  
  131.             for(let route in routes.routes) {
  132.                 // REPLACE IN-PATH VARIABLES(LIKE: /user/:id/update) WITH REGEX PATTERNS FOR FURTHER MATCHING
  133.                 let r = route.replace(new RegExp(':\\w+', 'g'), '(\\w+)');
  134.  
  135.                 // IF PATH DID MATCH
  136.                 if((req.method + ':' + req.path).match(new RegExp('^'+r+'$', 'gi'))) {
  137.                     let decodedJWTData = null;
  138.                     let token = req.header('Authorization') || req.cookies.Authorization || req.query.Authorization;
  139.                    
  140.                     // IF ROUTE REQUIRES TOKEN SO CHECK ONE
  141.                     if(routes.requireToken) {
  142.                         let JWTToken = this.__validateJWT(token);
  143.  
  144.                         if(!JWTToken.validated)
  145.                             return res.accessDenied();
  146.  
  147.                         decodedJWTData = JWTToken.decoded;
  148.                     }
  149.  
  150.                     // MERGE IN-PATH VARIABLES TO REQ.QUERY OBJECT
  151.                     _.merge(req.query, this.__getQueryDict(route, req.path));
  152.  
  153.                     // CHECK QUERY RULES IF THEY EXIST IN ROUTE DECLARATION
  154.                     if(routes.routes[route].query) {
  155.                         let checkedQueryParams = this.checkQueryParams(req.query, routes.routes[route].query);
  156.  
  157.                         if(!checkedQueryParams.status)
  158.                             return res.error(checkedQueryParams.error);
  159.                     }
  160.                    
  161.                     // CHECK BODY RULES IF THEY EXIST IN ROUTE DECLARATION
  162.                     if(routes.routes[route].body) {
  163.                         let checkedBodyParams = this.checkBodyParams(req, routes.routes, route);
  164.  
  165.                         if(!checkedBodyParams.status)
  166.                             return res.error(checkedBodyParams.error);
  167.                     }
  168.  
  169.                     // CHECK FILES RULES IF THEY EXIST IN ROUTE DECLARATION
  170.                     if(routes.routes[route].files) {
  171.                         let checkedFiles = this.checkFiles(req.files, routes.routes[route].files);
  172.  
  173.                         if(!checkedFiles.status)
  174.                             return res.error(checkedFiles.error);
  175.                     }
  176.  
  177.                     controllers[controllerName].user = decodedJWTData;
  178.                        
  179.                     controllers[controllerName].req = req;
  180.                     controllers[controllerName].res = res;
  181.  
  182.                     return controllers[controllerName][routes.routes[route].action](req,res);
  183.                 }
  184.             }
  185.         }
  186.  
  187.         this.throw404(req, res)
  188.     }
  189.  
  190.     throw404 (req, res) {
  191.         return res.error('404');
  192.     }
  193. }
  194.  
  195. module.exports = Router;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement