Skip to content

Commit

Permalink
- Reldens - v4.0.0 - Installer WIP.
Browse files Browse the repository at this point in the history
  • Loading branch information
damian-pastorini committed Nov 25, 2023
1 parent 87b9866 commit 77caed7
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 80 deletions.
32 changes: 28 additions & 4 deletions install/css/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ $cWhite: #fff;
$cLightGrey: #ccc;
$cBlack: #000;
$cRed: #ff0000;
$titleBackground: #f2f2f2;
$boxBackground: rgba(255, 255, 255, 0.6);

body, html {
height: 100%;
Expand Down Expand Up @@ -164,7 +166,7 @@ input[type="submit"] {
max-width: 500px;
margin: 0 auto 10px;
padding: 0;
background-color: rgba(255, 255, 255, 0.6);
background-color: $boxBackground;
border: 1px solid #ccc;
box-shadow: 10px 10px 14px 2px rgba(0, 0, 0, 0.6);

Expand Down Expand Up @@ -225,7 +227,7 @@ input[type="submit"] {

h3.form-title {
text-align: center;
background: #f2f2f2;
background: $titleBackground;
padding: 10px 0;
}

Expand All @@ -241,7 +243,7 @@ form {
&.db-basic-config {
display: flex;
flex-direction: column;
background: rgba(255,255,255,0.6);
background: $boxBackground;
margin-bottom: 0;

label {
Expand Down Expand Up @@ -284,7 +286,7 @@ form {
justify-content: end;
margin-top: 4px;
padding: 0 0 6px 0;
background: rgba(255, 255, 255, 0.6);
background: $boxBackground;

label {
width: auto;
Expand Down Expand Up @@ -329,3 +331,25 @@ form {
}

}

.installation-successful {
display: block;
padding: 10px;
background: $boxBackground;
text-align: center;
text-decoration: none;
font-size: 2em;
color: #000;
}

.app-error, .db-error {
p {
display: none;
width: 100%;
padding: 2%;
background: $boxBackground;
font-size: 12px;
font-weight: bold;
color: $cRed;
}
}
23 changes: 16 additions & 7 deletions install/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ <h1 class="title">
<h3 class="form-title">- App -</h3>
<div class="input-box app-host">
<label for="app-host">Host</label>
<input type="text" name="app-host" id="app-host" class="required" required/>
<input type="text" name="app-host" id="app-host" value="http://localhost" class="required" required/>
</div>
<div class="input-box app-port">
<label for="app-port">Port</label>
<input type="text" name="app-port" id="app-port" class="required" required/>
<input type="text" name="app-port" id="app-port" value="8080" class="required" required/>
</div>
<div class="input-box app-admin-path">
<label for="app-admin-path">Admin Panel path (default /reldens-admin)</label>
Expand All @@ -45,6 +45,9 @@ <h3 class="form-title">- App -</h3>
<label for="app-admin-hot-plug">Hot-Plug</label>
<input type="checkbox" value="1" name="app-admin-hot-plug" id="app-admin-hot-plug" checked/>
</div>
<div class="input-box app-error">
<p class="installation-process-failed">There was an error during the installation process.</p>
</div>

<!-- HTTPS -->
<div class="input-box app-use-https">
Expand Down Expand Up @@ -90,23 +93,23 @@ <h3 class="form-title">- App -</h3>
<h3 class="form-title">- Storage -</h3>
<div class="input-box db-storage-driver">
<label for="db-storage-driver">Storage Driver (objection-js, mikro-orm)</label>
<input type="text" value="objection-js" name="db-storage-driver" id="db-storage-driver" class="required" required/>
<input type="text" name="db-storage-driver" id="db-storage-driver" value="objection-js" class="required" required/>
</div>
<div class="input-box db-client">
<label for="db-client">Client (mysql / 3306, mongodb / 27017)</label>
<input type="text" value="mysql" name="db-client" id="db-client" class="required" required/>
<input type="text" name="db-client" id="db-client" value="mysql" class="required" required/>
</div>
<div class="input-box db-host">
<label for="db-host">Host</label>
<input type="text" name="db-host" id="db-host" class="required" required/>
<input type="text" name="db-host" id="db-host" value="localhost" class="required" required/>
</div>
<div class="input-box db-port">
<label for="db-port">Port</label>
<input type="text" name="db-port" id="db-port" class="required" required/>
<input type="text" name="db-port" id="db-port" value="3306" class="required" required/>
</div>
<div class="input-box db-name">
<label for="db-name">Database Name</label>
<input type="text" name="db-name" id="db-name" class="required" required/>
<input type="text" name="db-name" id="db-name" value="{{db-name}}" class="required" required/>
</div>
<div class="input-box db-username">
<label for="db-username">Username</label>
Expand All @@ -116,6 +119,12 @@ <h3 class="form-title">- Storage -</h3>
<label for="db-password">Password</label>
<input type="password" name="db-password" id="db-password" class="required" required/>
</div>
<div class="input-box db-error">
<p class="connection-failed">Connection failed, please check the storage configuration.</p>
<p class="invalid-driver">Invalid storage driver.</p>
<p class="raw-query-not-found">Method "rawQuery" not found in the specified storage driver.</p>
<p class="db-installation-process-failed">There was an error during the installation process.</p>
</div>
<div class="input-box db-basic-config">
<div class="db-basic-config-checkbox">
<label for="db-basic-config">Install minimal configuration</label>
Expand Down
16 changes: 16 additions & 0 deletions install/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,20 @@ window.addEventListener('load', () => {
});
}

let urlParams = new URL(window.location.href).searchParams;
if('1' === urlParams.get('success')){
document.querySelector('.forms-container').style.display = 'none';
let newLink = document.createElement('a');
newLink.href = '/?ready=1';
newLink.target = '_blank';
newLink.innerHTML = 'Installation successful, click here to open your game!';
newLink.classList.add('installation-successful');
document.querySelector('.content').append(newLink);
}

let errorCode = (urlParams.get('error') || '').toString();
if('' !== errorCode){
document.querySelector('.'+errorCode).style.display = 'block';
}

});
8 changes: 5 additions & 3 deletions lib/game/server/app-server-factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,16 @@ class AppServerFactory
app.use('/', (req, res, next) => {
if('/' === req._parsedUrl.pathname){
let languageParam = req.query.lang || '';
if('' !== languageParam){
Logger.info('Selected language: '+languageParam);
}
let indexPath = path.join(distPath, languageParam+'-'+GameConst.STRUCTURE.INDEX);
let defaultIndexPath = path.join(distPath, GameConst.STRUCTURE.INDEX);
let filePath = '' !== languageParam && fs.existsSync(indexPath) ? indexPath : defaultIndexPath;
Logger.info('Loading language: '+languageParam, filePath);
Logger.info('Loading index: '+filePath);
// @TODO - BETA - Move the rendering process outside this AppServerFactory.
let html = fs.readFileSync(filePath, this.encoding);

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
res.send(TemplateEngine.render(html, {}));
return;
return res.send(TemplateEngine.render(html, {}));
}
next();
});

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
a file system access
, but is not rate-limited.
This route handler performs
a file system access
, but is not rate-limited.
Expand Down
148 changes: 85 additions & 63 deletions lib/game/server/installer.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,74 +45,75 @@ class Installer
Logger.info('Re-building installer.');
await this.themeManager.buildInstaller();
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static(this.themeManager.installerPath));
app.use(session({secret: this.secretKey, resave: true, saveUninitialized: true}));
app.use((req, res, next) => {
if(this.isInstalled()){
return next();
}
if('' === req.originalUrl || '/' === req.originalUrl){
if(req.session.templateVariables){
let installerIndexTemplate = fs.readFileSync(
this.themeManager.installerPathIndex,
{encoding: this.encoding()}
);
TemplateEngine.render(installerIndexTemplate, req.session.templateVariables);
return res.send(installerIndexTemplate);
app.use(express.static(
this.themeManager.installerPath,
{
index: false,
filter: (req, file) => {
return '.html' !== path.extname(file);
}
return res.sendFile(this.themeManager.installerPathIndex);
}
next();
));
app.use(session({secret: this.secretKey, resave: true, saveUninitialized: true}));

Check warning

Code scanning / CodeQL

Clear text transmission of sensitive cookie Medium

Sensitive cookie sent without enforcing SSL encryption.
app.use((req, res, next) => {
return this.executeForEveryRequest(next, req, res);
});
app.post('/install', async (req, res) => {
let templateVariables = req.body;
this.setCheckboxesMissingValues(templateVariables);
req.session.templateVariables = templateVariables;
let selectedDriver = DriversMap[templateVariables['db-storage-driver']];
if(!selectedDriver){
Logger.critical('Invalid storage driver: '+templateVariables['db-storage-driver']);
return res.redirect('/?error=invalid-driver');
}
let dbConfig = {
client: templateVariables['db-client'],
config: {
host: templateVariables['db-host'],
port: Number(templateVariables['db-port']),
database: templateVariables['db-name'],
user: templateVariables['db-username'],
password: templateVariables['db-password'],
multipleStatements: true
},
debug: '1' === process?.env?.RELDENS_DEBUG_QUERIES
};
let dbDriver = new selectedDriver(dbConfig);
if (!await dbDriver.connect()){
Logger.critical('Connection failed, please check the storage configuration.');
return res.redirect('/?error=connection-failed');
}
if(!sc.isObjectFunction(dbDriver, 'rawQuery')){
Logger.critical('Method "rawQuery" not found in the specified storage driver.');
return res.redirect('/?error=rawQuery-not-found');
}
try {
let migrationsPath = path.join(this.themeManager.reldensModulePath, 'migrations', 'production');
await this.executeQueryFile(migrationsPath, dbDriver, 'reldens-install-v4.0.0.sql');
Logger.info('Installed tables.');
if('1' === templateVariables['db-basic-config']){
await this.executeQueryFile(migrationsPath, dbDriver, 'reldens-basic-config-v4.0.0.sql');
Logger.info('Installed basic-config.');
}
if('1' === templateVariables['db-sample-data']){
await this.executeQueryFile(migrationsPath, dbDriver, 'reldens-sample-data-v4.0.0.sql');
Logger.info('Installed sample-data.');
}
} catch (err) {
Logger.critical('There was an error during the installation process.', err);
return res.redirect('/?error=installation-process-failed');
return await this.executeInstallProcess(req, res);
});
}

async executeInstallProcess(req, res)
{
let templateVariables = req.body;
this.setCheckboxesMissingValues(templateVariables);
req.session.templateVariables = templateVariables;
let selectedDriver = DriversMap[templateVariables['db-storage-driver']];
if(!selectedDriver){
Logger.critical('Invalid storage driver: ' + templateVariables['db-storage-driver']);
return res.redirect('/?error=invalid-driver');
}
let dbConfig = {
client: templateVariables['db-client'],
config: {
host: templateVariables['db-host'],
port: Number(templateVariables['db-port']),
database: templateVariables['db-name'],
user: templateVariables['db-username'],
password: templateVariables['db-password'],
multipleStatements: true
},
debug: '1' === process?.env?.RELDENS_DEBUG_QUERIES
};
let dbDriver = new selectedDriver(dbConfig);
if(!await dbDriver.connect()){
Logger.critical('Connection failed, please check the storage configuration.');
return res.redirect('/?error=connection-failed');
}
if(!sc.isObjectFunction(dbDriver, 'rawQuery')){
Logger.critical('Method "rawQuery" not found in the specified storage driver.');
return res.redirect('/?error=raw-query-not-found');
}
try {
let migrationsPath = path.join(this.themeManager.reldensModulePath, 'migrations', 'production');
await this.executeQueryFile(migrationsPath, dbDriver, 'reldens-install-v4.0.0.sql');
Logger.info('Installed tables.');
if('1' === templateVariables['db-basic-config']){
await this.executeQueryFile(migrationsPath, dbDriver, 'reldens-basic-config-v4.0.0.sql');
Logger.info('Installed basic-config.');
}
if('' === templateVariables['app-admin-path']){
templateVariables['app-admin-path'] = '/reldens-admin';
if('1' === templateVariables['db-sample-data']){
await this.executeQueryFile(migrationsPath, dbDriver, 'reldens-sample-data-v4.0.0.sql');
Logger.info('Installed sample-data.');
}
} catch (err) {
Logger.critical('There was an error during the installation process.', err);
return res.redirect('/?error=db-installation-process-failed');
}
if('' === templateVariables['app-admin-path']){
templateVariables['app-admin-path'] = '/reldens-admin';
}
try {
let envDistTemplate = fs.readFileSync(
this.themeManager.reldensModulePathInstallTemplateEnvDist,
{encoding: this.encoding()}
Expand All @@ -132,7 +133,28 @@ class Installer
await this.startCallback();
}
return res.redirect('/?success=1')

Check notice

Code scanning / CodeQL

Semicolon insertion Note

Avoid automated semicolon insertion (97% of all statements in
the enclosing function
have an explicit semicolon).
});
} catch (err) {
return res.redirect('/?error=installation-process-failed');
}
}

executeForEveryRequest(next, req, res)
{
if(this.isInstalled()){
return res.sendFile(this.themeManager.installerPathIndex);
}
if('' === req._parsedUrl.pathname || '/' === req._parsedUrl.pathname){
let installerIndexTemplate = fs.readFileSync(
this.themeManager.installerPathIndex,
{encoding: this.encoding()}
);
let templateVariables = req?.session?.templateVariables || {};
return res.send(TemplateEngine.render(installerIndexTemplate, templateVariables));
}
if(!req.url.endsWith('.html')){
return express.static(this.themeManager.installerPath)(req, res, next);
}
next();
}

async executeQueryFile(migrationsPath, dbDriver, fileName)
Expand Down
6 changes: 3 additions & 3 deletions lib/game/server/manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
*/

const dotenv = require('dotenv');
const path = require('path');
const { WebSocketTransport } = require('@colyseus/ws-transport');
const ReldensASCII = require('../reldens-ascii');
const PackageData = require('./../../../package.json');
Expand Down Expand Up @@ -52,6 +51,7 @@ class ServerManager
this.dataServerDriver = dataServerDriver;
this.events = eventsManager || EventsManagerSingleton;
this.themeManager = new ThemeManager(config);
dotenv.config({debug: process.env.DEBUG, path: this.themeManager.envFilePath});
this.installer = new Installer({
themeManager: this.themeManager,
startCallback: async () => {
Expand All @@ -77,7 +77,6 @@ class ServerManager
this.configManager = new ConfigManager({events: this.events, customClasses: (config.customClasses || {})});
this.projectRoot = sc.get(config, 'projectRoot', './');
Logger.info('Project root: '+this.projectRoot, 'Module root: '+__dirname);
dotenv.config({debug: process.env.DEBUG, path: this.themeManager.envFilePath});
this.configServer = this.fetchConfigServerFromEnvironmentVariables();
this.isHotPlugEnabled = process.env.RELDENS_HOT_PLUG || false;
}
Expand Down Expand Up @@ -133,6 +132,7 @@ class ServerManager
Logger.info('Starting Server!');
if(this.appServer?.listening){
await this.appServer.close();
Object.assign(this, AppServerFactory.createAppServer());
}
this.setupCustomServerPlugin(this.rawConfig);
await this.themeManager.validateOrCreateTheme();
Expand Down Expand Up @@ -297,7 +297,7 @@ class ServerManager
{
// @TODO - BETA - Extract and pass to the ServerManager in the constructor.
this.mailer = new Mailer();
Logger.info(['Mailer Configured:', this.mailer.isEnabled()]);
Logger.info('Mailer: ' +(this.mailer.isEnabled() ? 'enabled' : 'disabled'));
await ForgotPassword.defineRequestOnServerManagerApp(this);
}

Expand Down

0 comments on commit 77caed7

Please sign in to comment.