189 lines
5.3 KiB
JavaScript
189 lines
5.3 KiB
JavaScript
/* eslint-disable no-param-reassign */
|
|
// ABOUT
|
|
// Runs the SyncLounge Web App - handles serving the static web content and link shortening services
|
|
// Port defaults to 8088
|
|
// REQUIRED: Access URL must be set. See documentation for how to set this.
|
|
|
|
const express = require('express');
|
|
const path = require('path');
|
|
const cors = require('cors');
|
|
const bodyParser = require('body-parser');
|
|
const Waterline = require('waterline');
|
|
const SailsMysql = require('sails-mysql');
|
|
const SailsDisk = require('sails-disk');
|
|
|
|
const { readSettings } = require('./SettingsHelper');
|
|
|
|
const settings = readSettings();
|
|
|
|
const bootstrap = () => {
|
|
if (!settings.accessUrl) {
|
|
console.log(
|
|
'Missing required argument `accessUrl`. This URL is used for redirecting invite links. See documentation for how to set this',
|
|
);
|
|
return Promise.reject(new Error('Missing URL for invite links'));
|
|
}
|
|
|
|
const baseSettings = require('./waterline_settings.json');
|
|
// console.log('Basesettings', baseSettings);
|
|
baseSettings.waterline.adapters = {
|
|
'sails-mysql': SailsMysql,
|
|
'sails-disk': SailsDisk,
|
|
};
|
|
|
|
baseSettings.waterline.datastores = baseSettings.database.datastores;
|
|
baseSettings.waterline.models.invite.beforeCreate = (data, cb) => {
|
|
console.log('Creating Invite', data);
|
|
const params = {
|
|
server: data.server,
|
|
room: data.room,
|
|
owner: data.owner,
|
|
};
|
|
if (data.password) {
|
|
params.password = data.password;
|
|
}
|
|
|
|
const query = Object.entries(params)
|
|
.map(([key, value]) => `${encodeURIComponent(key)}=${value}`)
|
|
.join('&');
|
|
|
|
// TODO: ask why we require accessUrl and not just redirect relatively
|
|
const fullUrl = `${settings.accessUrl}/#/join?${query}`;
|
|
data.fullUrl = fullUrl;
|
|
// eslint-disable-next-line no-bitwise
|
|
data.code = (0 | (Math.random() * 9e6)).toString(36);
|
|
cb();
|
|
};
|
|
|
|
return new Promise((resolve, reject) => {
|
|
Waterline.start(baseSettings.waterline, (err, orm) => {
|
|
if (err) {
|
|
return reject(err);
|
|
}
|
|
return resolve(orm);
|
|
});
|
|
});
|
|
};
|
|
|
|
const webApp = async (orm) => {
|
|
const app = express();
|
|
const router = express.Router();
|
|
|
|
// Setup our web app
|
|
app.use(cors());
|
|
|
|
// Allow body to be json or urlencoded
|
|
app.use(bodyParser.json());
|
|
app.use(
|
|
bodyParser.urlencoded({
|
|
extended: true,
|
|
}),
|
|
);
|
|
|
|
app.use(settings.webroot, router);
|
|
|
|
router.use('/', express.static(path.join(__dirname, 'dist')));
|
|
|
|
// Invite handling
|
|
router.get('/invite/:id', async (req, res) => {
|
|
console.log('handling an invite', req.params.id);
|
|
const shortObj = await Waterline.getModel('invite', orm).findOne({ code: req.params.id });
|
|
console.log('Invite data', shortObj);
|
|
if (!shortObj) {
|
|
return res.redirect(settings.accessUrl + settings.webroot);
|
|
}
|
|
console.log('Redirecting an invite link', shortObj);
|
|
return res.redirect(shortObj.fullUrl);
|
|
});
|
|
|
|
router.post('/invite', async (req, res) => {
|
|
res.setHeader('Content-Type', 'application/json');
|
|
if (!req.body) {
|
|
return res
|
|
.send({
|
|
success: false,
|
|
msg: 'ERR: You did not send any POST data',
|
|
})
|
|
.end();
|
|
}
|
|
|
|
const fields = ['server', 'room', 'password', 'owner'];
|
|
|
|
const missingField = fields.find((field) => req.body[field] === undefined);
|
|
if (missingField !== undefined) {
|
|
return res
|
|
.send({
|
|
success: false,
|
|
msg: `ERR: You did not specify ${missingField}`,
|
|
field: missingField,
|
|
})
|
|
.end();
|
|
}
|
|
|
|
const data = fields.reduce((dataAcc, field) => {
|
|
dataAcc[field] = req.body[field];
|
|
return dataAcc;
|
|
}, {});
|
|
|
|
const result = await Waterline.getModel('invite', orm)
|
|
.create({ ...data })
|
|
.fetch();
|
|
|
|
return res
|
|
.send({
|
|
url: `${settings.accessUrl}/invite/${result.code}`,
|
|
success: true,
|
|
generatedAt: new Date().getTime(),
|
|
details: result,
|
|
})
|
|
.end();
|
|
});
|
|
|
|
// Config handling
|
|
router.get('/config', (req, res) => {
|
|
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
|
|
res.header('Expires', '-1');
|
|
res.header('Pragma', 'no-cache');
|
|
res.send(settings);
|
|
});
|
|
|
|
// Catch anything else and redirect to the base URL
|
|
router.get('*', (req, res) => {
|
|
console.log('Catch all:', req.url);
|
|
return res.redirect(`${settings.webroot}/`);
|
|
});
|
|
|
|
app.listen(settings.webapp_port, () => {
|
|
console.log('SyncLounge WebApp successfully started on port ', settings.webapp_port);
|
|
});
|
|
|
|
|
|
console.log('Running with base URL: ', settings.webroot);
|
|
|
|
if (settings.accessUrl) {
|
|
console.log(`Access URL is ${settings.accessUrl}`);
|
|
if (settings.webroot && !settings.accessUrl.includes(settings.webroot)) {
|
|
console.log('- WARNING: Your Access URL does not contain your webroot/WEBROOT setting: ',
|
|
settings.webroot, '. Invite URLs may not work properly.');
|
|
}
|
|
}
|
|
|
|
if (settings.authentication && settings.authentication.mechanism !== 'none') {
|
|
console.log('Authentication:', settings.authentication);
|
|
}
|
|
|
|
if (settings.servers) {
|
|
console.log('Servers List:', settings.servers);
|
|
} else if (settings.custom_server) {
|
|
console.log('Custom Server List:', settings.custom_server);
|
|
}
|
|
};
|
|
|
|
bootstrap()
|
|
.then((orm) => {
|
|
webApp(orm);
|
|
})
|
|
.catch((e) => {
|
|
console.log('Error bootstrapping webapp:', e);
|
|
});
|