const logger = require('./modules/logger'); logger.init(); const winston = require('winston'); const express = require('express'); const mstream = express(); const fs = require('fs'); const fe = require('path'); const bodyParser = require('body-parser'); const dbStuff = require('./modules/db-management/database-master.js'); exports.logit = function (msg) { /* Nothing. This is for electron */ } exports.addresses = { localhost: false, network: false, internet: false } exports.serveit = function (program) { if (program.logs && program.logs.path) { logger.addFileLogger(program.logs.path); } var server; if (program.ssl && program.ssl.cert && program.ssl.key) { try { server = require('https').createServer({ key: fs.readFileSync(program.ssl.key), cert: fs.readFileSync(program.ssl.cert) }); } catch (error) { winston.error('FAILED TO CREATE HTTPS SERVER'); error.code = 'BAD CERTS'; throw error; } } else { server = require('http').createServer(); } // Magic Middleware Things mstream.use(bodyParser.json()); // support json encoded bodies mstream.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies mstream.use((req, res, next) => { // CORS res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); }); // Setup WebApp if (program.userinterface) { // Give access to public folder mstream.use('/public', express.static(fe.join(__dirname, program.userinterface))); // Serve the webapp mstream.get('/', function (req, res) { res.sendFile(fe.join(program.userinterface, 'mstream.html'), { root: __dirname }); }); mstream.get('/j/*', function (req, res) { res.sendFile(fe.join(program.userinterface, 'mstream.html'), { root: __dirname }); }); // It Really Whips The Llama's Ass mstream.get('/winamp', function (req, res) { res.sendFile(fe.join(program.userinterface, 'winamp.html'), { root: __dirname }); }); // Serve Shared Page mstream.all('/shared/playlist/*', function (req, res) { res.sendFile(fe.join(program.userinterface, 'shared.html'), { root: __dirname }); }); // Serve Jukebox Page mstream.all('/remote', function (req, res) { res.sendFile(fe.join(program.userinterface, 'remote.html'), { root: __dirname }); }); } // Setup Album Art if (!program.albumArtDir) { program.albumArtDir = fe.join(__dirname, 'image-cache'); } // This is a convenience function. It gets the vPath from any url string program.getVPathInfo = function (url) { // TODO: Verify user has access to this vpath // remove leading slashes if (url.charAt(0) === '/') { url = url.substr(1); } var fileArray = url.split('/'); var vpath = fileArray.shift(); // Make sure the path exists if (!program.folders[vpath]) { return false; } var baseDir = program.folders[vpath].root; var newPath = ''; for (var dir of fileArray) { if (dir === '') { continue; } newPath += dir + '/'; } // TODO: There's gotta be a better way to construct the relative path if (newPath.charAt(newPath.length - 1) === '/') { newPath = newPath.slice(0, - 1); } return { vpath: vpath, basePath: baseDir, relativePath: newPath, fullPath: fe.join(baseDir, newPath) }; } // Setup Secret for JWT try { // If user entered a filepath if (fs.statSync(program.secret).isFile()) { program.secret = fs.readFileSync(program.secret, 'utf8'); } } catch (error) { if (program.secret) { // just use secret as is program.secret = String(program.secret); } else { // If no secret was given, generate one require('crypto').randomBytes(48, function (err, buffer) { program.secret = buffer.toString('hex'); }); } } // JukeBox const jukebox = require('./modules/jukebox.js'); jukebox.setup2(mstream, server, program); // Shared const sharedModule = require('./modules/shared.js'); sharedModule.setupBeforeSecurity(mstream, program); // Login functionality program.auth = false; if (program.users) { require('./modules/login.js').setup(mstream, program, express); program.auth = true; } else { program.users = { "mstream-user": { vpaths: [], username: "mstream-user", admin: true } } if (program['lastfm-user'] && program['lastfm-password']) { program.users['mstream-user']['lastfm-user'] = program['lastfm-user'] program.users['mstream-user']['lastfm-password'] = program['lastfm-password'] } // Fill iin user vpaths for (var key in program.folders) { program.users['mstream-user'].vpaths.push(key); } // Fill in the necessary middleware mstream.use(function (req, res, next) { req.user = program.users['mstream-user']; next(); }); } // Setup all folders with express static for (var key in program.folders) { mstream.use('/media/' + key + '/', express.static(program.folders[key].root)); } // Album art endpoint mstream.use('/album-art', express.static(program.albumArtDir)); // Download Files API require('./modules/download.js').setup(mstream, program); // File Explorer API require('./modules/file-explorer.js').setup(mstream, program); // Load database dbStuff.setup(mstream, program); // Transcoder // require("./modules/ffmpeg.js").setup(mstream, program); // Scrobbler require('./modules/scrobbler.js').setup(mstream, program); // Finish setting up the jukebox and shared jukebox.setup(mstream, server, program); sharedModule.setupAfterSecurity(mstream, program); // Start the server! // TODO: Check if port is in use before firing up server server.on('request', mstream); server.listen(program.port, () => { let protocol = program.ssl && program.ssl.cert && program.ssl.key ? 'https' : 'http'; exports.addresses.local = protocol + '://localhost:' + program.port; winston.info(`Access mStream locally: ${exports.addresses.local}`); exports.logit(`Access mStream locally: ${exports.addresses.local}`); winston.info(`Try the WinAmp Demo: ${exports.addresses.local}/winamp`); require('internal-ip').v4().then(ip => { exports.addresses.network = protocol + '://' + ip + ':' + program.port; winston.info(`Access mStream on your local network: ${exports.addresses.network}`); exports.logit(`Access mStream on your local network: ${exports.addresses.network}`); }); // Handle Port Forwarding if (program.tunnel) { try { require('./modules/auto-port-forwarding.js').setup(program, function (status) { if (status === true) { require('public-ip').v4().then(ip => { exports.addresses.internet = protocol + '://' + ip + ':' + program.port; winston.info(`Access mStream on your local network:the internet: ${exports.addresses.internet}`); exports.logit(`Access mStream on your local network:the internet: ${exports.addresses.internet}`); }); } else { winston.error('Port Forwarding Failed. The server is running but you will have to configure your own port forwarding'); exports.logit('Port Forwarding Failed. The server is running but you will have to configure your own port forwarding'); } }); } catch (err) { exports.logit('Port Forwarding Failed. The server is running but you will have to configure your own port forwarding'); winston.error('Port Forwarding Failed. The server is running but you will have to configure your own port forwarding'); } } dbStuff.runAfterBoot(program); }); }