Files
OpenNoodl/packages/noodl-parse-dashboard/Parse-Dashboard/index.js
Michael Cartner b9c60b07dc Initial commit
Co-Authored-By: Eric Tuvesson <eric.tuvesson@gmail.com>
Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com>
Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com>
Co-Authored-By: Anders Larsson <64838990+anders-topp@users.noreply.github.com>
Co-Authored-By: Johan  <4934465+joolsus@users.noreply.github.com>
Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com>
Co-Authored-By: victoratndl <99176179+victoratndl@users.noreply.github.com>
2024-01-26 11:52:55 +01:00

199 lines
7.9 KiB
JavaScript

/*
* Copyright (c) 2016-present, Parse, LLC
* All rights reserved.
*
* This source code is licensed under the license found in the LICENSE file in
* the root directory of this source tree.
*/
// Command line tool for npm start
'use strict'
const path = require('path');
const fs = require('fs');
const express = require('express');
const parseDashboard = require('./app');
const CLIHelper = require('./CLIHelper.js');
const program = require('commander');
program.option('--appId [appId]', 'the app Id of the app you would like to manage.');
program.option('--masterKey [masterKey]', 'the master key of the app you would like to manage.');
program.option('--serverURL [serverURL]', 'the server url of the app you would like to manage.');
program.option('--graphQLServerURL [graphQLServerURL]', 'the GraphQL server url of the app you would like to manage.');
program.option('--dev', 'Enable development mode. This will disable authentication and allow non HTTPS connections. DO NOT ENABLE IN PRODUCTION SERVERS');
program.option('--appName [appName]', 'the name of the app you would like to manage. Optional.');
program.option('--config [config]', 'the path to the configuration file');
program.option('--host [host]', 'the host to run parse-dashboard');
program.option('--port [port]', 'the port to run parse-dashboard');
program.option('--mountPath [mountPath]', 'the mount path to run parse-dashboard');
program.option('--allowInsecureHTTP [allowInsecureHTTP]', 'set this flag when you are running the dashboard behind an HTTPS load balancer or proxy with early SSL termination.');
program.option('--sslKey [sslKey]', 'the path to the SSL private key.');
program.option('--sslCert [sslCert]', 'the path to the SSL certificate.');
program.option('--trustProxy [trustProxy]', 'set this flag when you are behind a front-facing proxy, such as when hosting on Heroku. Uses X-Forwarded-* headers to determine the client\'s connection and IP address.');
program.option('--cookieSessionSecret [cookieSessionSecret]', 'set the cookie session secret, defaults to a random string. You should set that value if you want sessions to work across multiple server, or across restarts');
program.option('--createUser', 'helper tool to allow you to generate secure user passwords and secrets. Use this on trusted devices only.');
program.option('--createMFA', 'helper tool to allow you to generate multi-factor authentication secrets.');
program.parse(process.argv);
const options = program.opts();
for (const key in options) {
const func = CLIHelper[key];
if (func && typeof func === 'function') {
func();
return;
}
}
const host = options.host || process.env.HOST || '0.0.0.0';
const port = options.port || process.env.PORT || 4040;
const mountPath = options.mountPath || process.env.MOUNT_PATH || '/';
const allowInsecureHTTP = options.allowInsecureHTTP || process.env.PARSE_DASHBOARD_ALLOW_INSECURE_HTTP;
const cookieSessionSecret = options.cookieSessionSecret || process.env.PARSE_DASHBOARD_COOKIE_SESSION_SECRET;
const trustProxy = options.trustProxy || process.env.PARSE_DASHBOARD_TRUST_PROXY;
const dev = options.dev;
if (trustProxy && allowInsecureHTTP) {
console.log('Set only trustProxy *or* allowInsecureHTTP, not both. Only one is needed to handle being behind a proxy.');
process.exit(-1);
}
let explicitConfigFileProvided = !!options.config;
let configFile = null;
let configFromCLI = null;
let configServerURL = options.serverURL || process.env.PARSE_DASHBOARD_SERVER_URL;
let configGraphQLServerURL = options.graphQLServerURL || process.env.PARSE_DASHBOARD_GRAPHQL_SERVER_URL;
let configMasterKey = options.masterKey || process.env.PARSE_DASHBOARD_MASTER_KEY;
let configAppId = options.appId || process.env.PARSE_DASHBOARD_APP_ID;
let configAppName = options.appName || process.env.PARSE_DASHBOARD_APP_NAME;
let configUserId = options.userId || process.env.PARSE_DASHBOARD_USER_ID;
let configUserPassword = options.userPassword || process.env.PARSE_DASHBOARD_USER_PASSWORD;
let configSSLKey = options.sslKey || process.env.PARSE_DASHBOARD_SSL_KEY;
let configSSLCert = options.sslCert || process.env.PARSE_DASHBOARD_SSL_CERT;
function handleSIGs(server) {
const signals = {
'SIGINT': 2,
'SIGTERM': 15
};
function shutdown(signal, value) {
server.close(function () {
console.log('server stopped by ' + signal);
process.exit(128 + value);
});
}
Object.keys(signals).forEach(function (signal) {
process.on(signal, function () {
shutdown(signal, signals[signal]);
});
});
}
if (!options.config && !process.env.PARSE_DASHBOARD_CONFIG) {
if (configServerURL && configMasterKey && configAppId) {
configFromCLI = {
data: {
apps: [
{
appId: configAppId,
serverURL: configServerURL,
masterKey: configMasterKey,
appName: configAppName,
},
]
}
};
if (configGraphQLServerURL) {
configFromCLI.data.apps[0].graphQLServerURL = configGraphQLServerURL;
}
if (configUserId && configUserPassword) {
configFromCLI.data.users = [
{
user: configUserId,
pass: configUserPassword,
}
];
}
} else if (!configServerURL && !configMasterKey && !configAppName) {
configFile = path.join(__dirname, 'parse-dashboard-config.json');
}
} else if (!options.config && process.env.PARSE_DASHBOARD_CONFIG) {
configFromCLI = {
data: JSON.parse(process.env.PARSE_DASHBOARD_CONFIG)
};
} else {
configFile = options.config;
if (options.appId || options.serverURL || options.masterKey || options.appName || options.graphQLServerURL) {
console.log('You must provide either a config file or other CLI options (appName, appId, masterKey, serverURL, and graphQLServerURL); not both.');
process.exit(3);
}
}
let config = null;
let configFilePath = null;
if (configFile) {
try {
config = {
data: JSON.parse(fs.readFileSync(configFile, 'utf8'))
};
configFilePath = path.dirname(configFile);
} catch (error) {
if (error instanceof SyntaxError) {
console.log('Your config file contains invalid JSON. Exiting.');
process.exit(1);
} else if (error.code === 'ENOENT') {
if (explicitConfigFileProvided) {
console.log('Your config file is missing. Exiting.');
process.exit(2);
} else {
console.log('You must provide either a config file or required CLI options (app ID, Master Key, and server URL); not both.');
process.exit(3);
}
} else {
console.log('There was a problem with your config. Exiting.');
process.exit(-1);
}
}
} else if (configFromCLI) {
config = configFromCLI;
} else {
//Failed to load default config file.
console.log('You must provide either a config file or an app ID, Master Key, and server URL. See parse-dashboard --help for details.');
process.exit(4);
}
config.data.apps.forEach(app => {
if (!app.appName) {
app.appName = app.appId;
}
});
if (config.data.iconsFolder && configFilePath) {
config.data.iconsFolder = path.join(configFilePath, config.data.iconsFolder);
}
const app = express();
if (allowInsecureHTTP || trustProxy || dev) app.enable('trust proxy');
config.data.trustProxy = trustProxy;
let dashboardOptions = { allowInsecureHTTP, cookieSessionSecret, dev };
app.use(mountPath, parseDashboard(config.data, dashboardOptions));
let server;
if(!configSSLKey || !configSSLCert){
// Start the server.
server = app.listen(port, host, function () {
console.log(`The dashboard is now available at http://${server.address().address}:${server.address().port}${mountPath}`);
});
} else {
// Start the server using SSL.
var privateKey = fs.readFileSync(configSSLKey);
var certificate = fs.readFileSync(configSSLCert);
server = require('https').createServer({
key: privateKey,
cert: certificate
}, app).listen(port, host, function () {
console.log(`The dashboard is now available at https://${server.address().address}:${server.address().port}${mountPath}`);
});
}
handleSIGs(server);