/* Copyright (c) 2020, 2023, The Unified Company. This code is part of Unify. This program is free software; you can redistribute it and/or modify it under the terms of the ESA Software Community License - Strong Copyleft LICENSE, as published by the ESA. See the ESA Software Community License - Strong Copyleft LICENSE, for more details. https://unifyjs.org */ //import compression from 'compression'; //import express from 'express'; //import nocache from 'nocache'; //import cors from "cors"; //import bodyParser from 'body-parser'; //import { RateLimiterMemory } from 'rate-limiter-flexible'; import path from 'path'; import https from 'https'; import http from 'http'; import fs from "fs"; import tools from '../unify/tools.js'; import Console from './console.js'; import database from './database.js'; import querySQL from '../unify/querySQL.js'; import mimeLookup from "../../assets/json/mimeTypes.json" assert { type: "json" }; export default class serverManager{ __className = "serverManager"; mode; port = 8070; ssl = false; httpsServer = false; constructor() { //this.initializeRateLimiter(); } createExpressApp() { //this.app = express(); } createHttpsServer( ) { if( this.ssl ) { var privateKey = fs.readFileSync('./sslCertificates/privkey.pem', 'utf8'); var certificate = fs.readFileSync('./sslCertificates/fullchain.pem', 'utf8'); this.httpsServer = https.createServer({ key: privateKey, cert: certificate }, this.app ); } else { this.httpsServer = http.createServer( this.app ); } return this.httpsServer; } createListener( ) { if( this.ssl ) { if( !this.port ) { this.port = 443; } this.httpsServer.listen( this.port ); console.log("\nHttps WebServer started on port: ", this.port); } else { this.httpsServer.listen( this.port ); console.log("\nHttps WebServer started on port: ", 443); } } initializeRateLimiter() { this.rateLimiter = new RateLimiterMemory({ points: 1000, duration: 1, }); } restrictDirectories( app ) { app.all('/sslCertificates/*', function (req,res, next) { res.status(403).send({ message: 'Access Forbidden' }); }); app.all('/storage/*', function (req,res, next) { res.status(403).send({ message: 'Access Forbidden' }); }); } exposeDirectories( app ) { app.use( express.static( path.resolve("") ) ); if( global.mode == "production" ) { app.use( express.static( path.resolve( 'assets/production/') ) ); } else { app.use( express.static( path.resolve( 'assets/development/') ) ); } app.use( express.static( path.resolve('application/') ) ); app.use( express.static( path.resolve('admin/') ) ); app.use( express.static( path.resolve('framework/') , { maxAge: 99999999999 } ) ); if( global.mode == "development" ) { app.use( "/*.html", function ( req, res ) { res.sendFile( path.resolve('assets/development/index.html') );// } ); } else { app.use( "/*.html", function ( req, res ) { res.sendFile( path.resolve( 'assets/production/index.html') ); }); app.use( "/*.json", function ( req, res ) { res.sendFile( path.resolve( 'assets/production/index.json') ); }); } } async rateLimiterCallback( req, res, next ) { var rate = await this.rateLimiter.consume( this.userID, 2 ) .then( () => { return true; }) .catch( () => { return false; }); if( !rate ) { res.writeHead( 429 ); res.end(); return false; } if( next ) { next(); } } usePlugins( app ) { if( global.mode == "development" ) { app.use( nocache() ); } app.use( cors() ); app.use( bodyParser.json() ); app.use( compression() ); app.use( async ( req, res, next ) => { this.rateLimiterCallback( req, res, next ); }); } getExtension(filename) { var ext = path.extname( filename || '' ).split('.'); return "." + ext[ext.length - 1]; } setupServer() { //var app = this.app; //this.usePlugins( app ); //this.restrictDirectories( app ); //this.exposeDirectories( app ); //https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types /* const mimeLookup = { '.js': 'application/javascript', '.html': 'text/html', '.css':'text/css', '.woff':'font/woff', '.woff2':'font/woff2', '.ttf':'font/ttf', '.png':'png' }; */ function send404(response){ response.writeHead(404, {'Content-Type': 'text/plain'}); response.write('Error 404: Resource not found.'); response.end(); } var that = this; /* http.createServer( function( req, res ) { if( req.method == 'GET' ) { let fileurl; var cleanUrl = req.url.split("?")[0]; var fileExt = that.getExtension( cleanUrl ); var mimeType = mimeLookup[ fileExt ]; //console.log("req.url", req.url); //console.log("fileExt", fileExt); if( mimeType == 'text/html' || fileExt == '.' ) { if( global.mode == "development" ) { fileurl = '/assets/development/index.html'; } else { fileurl = '/assets/production/index.html'; } mimeType = "text/html"; } else { if( !mimeType ) { send404(res); return; } fileurl = cleanUrl; } var filepath = path.resolve('./' + fileurl); fs.exists( filepath, ( exists ) => { if( !exists ) { send404(res); return; } res.writeHead( 200, {'Content-Type': mimeType } ); fs.createReadStream( filepath ).pipe( res ); }); } }).listen( 3000 ); */ var reject = new Array(); reject.push( "/framework/cache/platforms/Original/" ); reject.push( "/framework/cache/platforms/Server/" ); reject.push( "/framework/cache/server/" ); reject.push( "/storage/" ); reject.push( "/application/" ); reject.push( "package.json" ); var server = this; this.app = function( req, res ) { //res.setHeader("Content-Security-Policy", "default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests"); //res.setHeader("Content-Security-Policy", "default-src 'self' ws: wss: " + server.serverAddress + " *." + server.serverAddress + "style-src 'self' 'unsafe-inline';" ); if( req.method == 'GET' ) { let fileurl; var cleanUrl = req.url.split("?")[0]; var fileExt = that.getExtension( cleanUrl ); var mimeType = mimeLookup[ fileExt ]; if( mimeType == 'text/html' || fileExt == '.' || fileExt == '.html' || fileExt == '.htm' ) { if( global.mode == "development" ) { fileurl = '/assets/development/index.html'; } else { fileurl = '/assets/production/index.html'; } mimeType = "text/html"; } else { //if( !mimeType ) { // send404(res); // return; //} fileurl = cleanUrl; } //console.log(fileurl); for (var i = 0; i < reject.length; i++) { var rejectURl = reject[i]; if( fileurl.includes( rejectURl ) ) { console.log("Access forbidden, reject url."); send404( res ); return; } } var filepath = path.resolve('./' + fileurl); fs.exists( filepath, ( exists ) => { if( !exists ) { send404(res); return; } //console.log(fileurl, mimeType); res.writeHead( 200, {'Content-Type': mimeType } ); fs.createReadStream( filepath ).pipe( res ); }); } } //.listen( 3000 ); } secureStatic( secure ) { return function ( req, res, next ) { var result = req.url.match(/^\/framework\/db\/.+$/); if ( result ) { return res.status(403).end('403 Forbidden') } else { next(); } } } runAPIServer() { /* var app = this.app; var that = this; app.use( "/api/", function ( req, res ) { const body = JSON.stringify( req.body ); class ajaxSocket{ send( content ) { res.json( content ); } } if( req.body.eventName == "connect" ) { that.socketManager.connection( new ajaxSocket() ); } else { var object = JSON.parse( body ); var clients = that.socketManager.sessionClients; var client = clients[object.sessionKey]; client.socket.send = function( content ) { res.json( content ); } client.message( body ); } }); */ } }