const url = require("url"); const express = require("express"); const { createProxyMiddleware } = require('http-proxy-middleware'); import Arena from 'bull-arena'; import { TF_APPLY_QUEUE, TF_APPLY_QSEOK_QUEUE, TF_DESTROY_QUEUE, STOP_CONTAINER_QUEUE, SYNAPSE_QUEUE } from 'qmi-cloud-common/queues'; const app = express(); const routesApiScenarios = require('./routes/api-scenarios'); const routesApiUsers = require('./routes/api-users'); const routesApiProvisions = require('./routes/api-provisions'); const routesApiDestroyProvisions = require('./routes/api-destroyprovisions'); const routesApiNotifications = require('./routes/api-notifications'); const routesApiDivvy = require('./routes/api-divvy'); const routesApiDeployOpts = require('./routes/api-deployopts'); const routesApiApikeys = require('./routes/api-apikeys'); const routesApiStats = require('./routes/api-stats'); const routesApiTraining = require('./routes/api-training'); const swaggerUi = require('swagger-ui-express'); const swaggerJsdoc = require('swagger-jsdoc'); const cookieParser = require('cookie-parser'); const bodyParser = require('body-parser'); const https = require('https'); const fs = require('fs'); const path = require('path'); const passport = require('./passport-okta'); //const qsProxy = require("./routes/qsProxy"); const BACKEND_LOGS_URL = process.env.BACKEND_LOGS_URL; const QMI_MONGO_URL = process.env.QMI_MONGO_URL; const IS_SECURE = process.env.CERT_PFX_PASSWORD && process.env.CERT_PFX_FILENAME; function _getRedisConfig(redisUrl) { const redisConfig = url.parse(redisUrl); return { host: redisConfig.hostname || 'localhost', port: Number(redisConfig.port || 6379), database: (redisConfig.pathname || '/0').substr(1) || '0', password: redisConfig.auth ? redisConfig.auth.split(':')[1] : undefined }; } app.use('/arena', Arena( { queues: [ { name: TF_APPLY_QUEUE, hostId: 'Worker', redis: _getRedisConfig(process.env.REDIS_URL) }, { name: TF_APPLY_QSEOK_QUEUE, hostId: 'Worker', redis: _getRedisConfig(process.env.REDIS_URL) }, { name: TF_DESTROY_QUEUE, hostId: 'Worker', redis: _getRedisConfig(process.env.REDIS_URL) }, { name: STOP_CONTAINER_QUEUE, hostId: 'Worker', redis: _getRedisConfig(process.env.REDIS_URL) }, { name: SYNAPSE_QUEUE, hostId: 'Worker', redis: _getRedisConfig(process.env.REDIS_URL) } ] }, { basePath: '/', disableListen: true } )); //----------------------------------------------------------------------------- // Config the app, include middlewares //----------------------------------------------------------------------------- //app.set('views', __dirname + '/views'); //app.set('view engine', 'ejs'); app.use(cookieParser()); app.use('/', express.static(__dirname + '/../dist/qmi-cloud')); passport.init(app, IS_SECURE ? true : false); app.use('/guacamole/', passport.ensureAuthenticatedDoLogin, createProxyMiddleware({ target: 'http://qmicloud-dev.qliktech.com:8080/', ws: true, changeOrigin: true, followRedirects: true, secure: false, onProxyReq: function (proxyReq, req, res) { if (req.user && req.user.mail) { proxyReq.setHeader('X-Guaca-Auth', req.user.mail); } } })); app.use(bodyParser.urlencoded({ extended: false })) // parse application/json app.use(bodyParser.json()) app.use("/api/v1/scenarios", routesApiScenarios); app.use("/api/v1/users", routesApiUsers); app.use("/api/v1/provisions", routesApiProvisions); app.use("/api/v1/destroyprovisions", routesApiDestroyProvisions); app.use("/api/v1/notifications", routesApiNotifications); app.use("/api/v1/divvy", routesApiDivvy); app.use("/api/v1/deployopts", routesApiDeployOpts); app.use("/api/v1/apikeys", routesApiApikeys); app.use("/api/v1/stats", routesApiStats); app.use("/api/v1/training", routesApiTraining); //app.use("/qcsproxy", qsProxy.router); function _isAllowedPath(path) { const allowedPaths = ['/api-docs', '/arena', '/costexport', '/backendlogs', '/photos/user/', '/qmimongo', '/guacamole/']; let isAllowed = false; for (let i = 0; i < allowedPaths.length; i++) { if (path.startsWith(allowedPaths[i])) { isAllowed = true; break; } } return isAllowed; } /* Checking allowedPaths */ app.get('/*', (req, res, next) => { if (_isAllowedPath(req.originalUrl)) { return next(); } else if (req.originalUrl.indexOf("oauth-callback.html") !== -1) { res.sendFile(path.join(__dirname, '/../dist/qmi-cloud/oauth-callback.html')); } else { res.sendFile(path.join(__dirname, '/../dist/qmi-cloud/index.html')); } }); /* -----------------------*/ app.get('/backendlogs', function (req, res) { res.redirect(BACKEND_LOGS_URL); res.end(); }); app.get('/qmimongo/*', function (req, res) { let path = req.path.split("/qmimongo")[1]; console.log("QMI-Mongo# Redirect: " + `${QMI_MONGO_URL}${path}`); res.redirect(`${QMI_MONGO_URL}${path}`); res.end(); }); const options = { definition: { openapi: "3.0.3", // Like the one described here: https://swagger.io/specification/#infoObject info: { title: 'QMI Cloud - API', version: '1.0.0', description: 'REST API for QMI Cloud solutions', contact: { "name": "Qlik Presales - Innovation & Excellence Team", "email": "DL-PresalesGlobalInnovation@qlik.com" } }, servers: [{ "url": "/api/v1", "description": "Production Server" }], components: { securitySchemes: { ApiKeyAuth: { type: "apiKey", name: "apiKey", in: "query" } } }, security: [{ ApiKeyAuth: [] }] }, // List of files to be processes. You can also set globs './routes/*.js' apis: [ 'server/routes/api-*.js' ] }; app.use('/costexport*', passport.ensureAuthenticatedAndAdmin, function (req, res) { if (!req.query.file) { res.status(404).send("Not found"); } else { res.header("Content-Type", 'application/json'); res.sendFile(path.resolve(__dirname, '..', 'costexport', req.query.file)); } }); app.use('/photos/user/:oid', passport.ensureAuthenticated, function (req, res) { if (!req.params.oid) { res.status(404).send("Not found"); } else { var pic = path.resolve(__dirname, '..', 'photos', `${req.params.oid}.jpg`); if (fs.existsSync(pic)) { res.sendFile(pic); } else { res.status(404).send(); } } }); const specs = swaggerJsdoc(options); app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs)); /** * Create necessary folders */ var dirs = ['/logs', '/logs/provision', '/logs/destroy', '/costexports', '/photos']; dirs.forEach(d => { if (!fs.existsSync(d)) { console.log(`--- Creating folder '${d}' since it does not exist`); fs.mkdirSync(d); } }); /** * Start App */ const server = app.listen(3000, () => { console.log(`Server listening on port 3000`) }); //qsProxy.init(server); if (IS_SECURE) { var optionsHttps = { pfx: fs.readFileSync(path.resolve(__dirname, 'certs', process.env.CERT_PFX_FILENAME)), passphrase: process.env.CERT_PFX_PASSWORD }; const httpsServer = https.createServer(optionsHttps, app).listen(3100, function () { console.log(`Secure server listening on port 3100`); }); //qsProxy.init(httpsServer); }