aboutsummaryrefslogtreecommitdiffstats
path: root/server/src/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/scripts')
-rw-r--r--server/src/scripts/configLib/SetupWizard.js107
-rw-r--r--server/src/scripts/configure.js14
-rw-r--r--server/src/scripts/setupSchema/Banner.js28
-rw-r--r--server/src/scripts/setupSchema/Footer.js7
-rw-r--r--server/src/scripts/setupSchema/Questions.js55
5 files changed, 203 insertions, 8 deletions
diff --git a/server/src/scripts/configLib/SetupWizard.js b/server/src/scripts/configLib/SetupWizard.js
new file mode 100644
index 0000000..339878d
--- /dev/null
+++ b/server/src/scripts/configLib/SetupWizard.js
@@ -0,0 +1,107 @@
+/**
+ * Server setup wizard, quick server setup and all that jazz. . .
+ *
+ * Version: v2.0.0
+ * Developer: Marzavec ( https://github.com/marzavec )
+ * License: WTFPL ( http://www.wtfpl.net/txt/copying/ )
+ *
+ */
+
+const fse = require('fs-extra');
+const prompt = require('prompt');
+const path = require('path');
+
+class SetupWizard {
+ /**
+ * Create a `SetupWizard` instance for initializing the server's config.json
+ *
+ * @param {Object} serverConfig reference to the server config class
+ */
+ constructor (serverConfig) {
+ this.serverConfig = serverConfig;
+ }
+
+ /**
+ * Roll a d20 and begin the wizarding process
+ *
+ */
+ async start () {
+ // load the current config to use as defaults, if available
+ let currentConfig = await this.serverConfig.load() || {};
+
+ // auto generate the salt if not currrently created
+ currentConfig.tripSalt = currentConfig.tripSalt ||
+ [...Array(Math.floor(Math.random()*1024)+1024)].map(i=>(~~(Math.random()*36)).toString(36)).join('');
+
+ // load the setup questions & set their defaults
+ let questions = require('../setupSchema/Questions.js');
+ questions.properties = this.setQuestionDefaults(questions.properties, currentConfig);
+
+ // force password re-entry
+ questions.properties.adminTrip.default = '';
+ questions.properties.adminTrip.required = true;
+
+ // output the packages setup banner
+ require('../setupSchema/Banner.js');
+
+ // let's start playing 20 questions
+ prompt.start();
+ prompt.get(questions, (err, result) => this.finalize(err, result));
+ }
+
+ /**
+ * Compares the currently loaded config with the stock questions, adds a default
+ * and required option to the question
+ *
+ * @param {Object} questions the set of questions from /setupSchema
+ * @param {Object} currentConfig the current server options
+ */
+ setQuestionDefaults (questions, currentConfig) {
+ Object.keys(questions).forEach(qName => {
+ if (typeof currentConfig[qName] !== 'undefined') {
+ questions[qName].default = currentConfig[qName];
+ questions[qName].required = false;
+ } else {
+ questions[qName].required = true;
+ }
+ });
+
+ return questions;
+ }
+
+ /**
+ * Looks like all the questions have been answered, check for errors or save
+ * the new config file
+ *
+ * @param {Object} err any errors generated by Prompt
+ * @param {Object} result the answers / new config setup
+ */
+ async finalize (err, result) {
+ // output errors and die if needed
+ if (err) {
+ console.error(err);
+ process.exit(0);
+ }
+
+ // initialize default mods config
+ if (typeof result.mods === 'undefined') {
+ result.mods = [];
+ }
+
+ // finally create the actual JSON file
+ try {
+ this.serverConfig.config = result;
+ await this.serverConfig.save();
+ } catch (e) {
+ console.error(`Couldn't write config to ${this.serverConfig.configPath}
+ ${e.stack}`);
+ }
+
+ // output the packages final notice before quitting
+ require('../setupSchema/Footer.js');
+
+ process.exit(0);
+ }
+}
+
+module.exports = SetupWizard;
diff --git a/server/src/scripts/configure.js b/server/src/scripts/configure.js
index 0ecd858..d7f2bf2 100644
--- a/server/src/scripts/configure.js
+++ b/server/src/scripts/configure.js
@@ -1,5 +1,5 @@
/**
- * Server configuration script, used reconfiguring server options
+ * Server configuration script, to (re)configure server options
*
* Version: v2.0.0
* Developer: Marzavec ( https://github.com/marzavec )
@@ -11,13 +11,11 @@
// import required classes
const path = require('path');
-const ImportsManager = require('../managers/imports-manager');
-const ConfigManager = require('../managers/config');
+const ConfigManager = require('../serverLib/ConfigManager');
+const SetupWizard = require('./configLib/SetupWizard');
// import and initialize configManager & dependencies
-const importManager = new ImportsManager(null, path.join(__dirname, '../..'));
-importManager.init();
-const configManager = new ConfigManager(null, path.join(__dirname, '../..'), importManager);
+const serverConfig = new ConfigManager(path.join(__dirname, '../..'));
+const setup = new SetupWizard(serverConfig);
-// execute config load with `reconfiguring` flag set to true
-configManager.load(true);
+setup.start();
diff --git a/server/src/scripts/setupSchema/Banner.js b/server/src/scripts/setupSchema/Banner.js
new file mode 100644
index 0000000..823f0fe
--- /dev/null
+++ b/server/src/scripts/setupSchema/Banner.js
@@ -0,0 +1,28 @@
+/**
+ * This script will be run before the package starts asking for the config data,
+ * used to output a simple guide for the coming questions, or to spam some sexy
+ * ascii art at the user.
+ *
+ */
+
+const stripIndents = require('common-tags').stripIndents;
+const chalk = require('chalk');
+
+// gotta have that sexy console
+console.log(stripIndents`
+ ${chalk.magenta('°º¤ø,¸¸,ø¤º°`°º¤ø,¸,ø¤°º¤ø,¸¸,ø¤º°`°º¤ø,¸°º¤ø,¸¸,ø¤º°`°º¤ø')}
+ ${chalk.gray('--------------(') + chalk.white(' HackChat Setup Wizard v2.0 ') + chalk.gray(')--------------')}
+ ${chalk.magenta('°º¤ø,¸¸,ø¤º°`°º¤ø,¸,ø¤°º¤ø,¸¸,ø¤º°`°º¤ø,¸°º¤ø,¸¸,ø¤º°`°º¤ø')}
+
+ For advanced setup, see the documentation at:
+ ${chalk.green('https://github.com/hack-chat/main/tree/master/documentation')}
+
+ ${chalk.white('Note:')} ${chalk.green('npm/yarn run config')} will re-run this utility.
+
+ You will now be asked for the following:
+ - ${chalk.magenta(' Salt')}, the salt for username trip
+ - ${chalk.magenta('Admin Name')}, the initial admin username
+ - ${chalk.magenta('Admin Pass')}, the initial admin password
+ - ${chalk.magenta(' Port')}, the port for the websocket
+ \u200b
+`);
diff --git a/server/src/scripts/setupSchema/Footer.js b/server/src/scripts/setupSchema/Footer.js
new file mode 100644
index 0000000..d2ee14f
--- /dev/null
+++ b/server/src/scripts/setupSchema/Footer.js
@@ -0,0 +1,7 @@
+/**
+ * This script will be run once all questions have finished and no errors have
+ * occured. You can congratulate the user on their fine choice in software usage
+ *
+ */
+
+console.log('Config generated! You may now start the server normally.');
diff --git a/server/src/scripts/setupSchema/Questions.js b/server/src/scripts/setupSchema/Questions.js
new file mode 100644
index 0000000..f84d32f
--- /dev/null
+++ b/server/src/scripts/setupSchema/Questions.js
@@ -0,0 +1,55 @@
+/**
+ * This object contains Prompt ( https://www.npmjs.com/package/prompt ) style
+ * questions that the SetupWizard will require an answer to. Questions are asked
+ * in the order they are specified here.
+ *
+ * The resulting config.json file will be used by the server, accessed by the
+ * name specified. IE, a valid use is; config.adminName
+ *
+ */
+
+const Questions = {
+ properties: {
+ tripSalt: {
+ description: 'Salt (leave as default)',
+ type: 'string',
+ hidden: true,
+ replace: '*',
+ before: value => {
+ salt = value;
+ return value;
+ }
+ },
+
+ adminName: {
+ description: 'Admin Nickname',
+ pattern: /^"?[a-zA-Z0-9_]+"?$/,
+ type: 'string',
+ message: 'Nicks can only contain letters, numbers and underscores',
+ before: value => value.replace(/"/g, '')
+ },
+
+ adminTrip: {
+ type: 'string',
+ hidden: true,
+ replace: '*',
+ description: 'Admin Password',
+ message: 'You must enter or re-enter a password',
+ before: value => {
+ const crypto = require('crypto');
+ let sha = crypto.createHash('sha256');
+ sha.update(value + salt);
+ return sha.digest('base64').substr(0, 6);
+ }
+ },
+
+ websocketPort: {
+ type: 'integer',
+ message: 'The port may only be a number!',
+ description: 'Websocket Port',
+ default: '6060'
+ }
+ }
+}
+
+module.exports = Questions;