'use strict'; const express = require('express'); const path = require('path'); const Authentication = require('./Authentication.js'); var fs = require('fs'); var newFeaturesInLatestVersion = []; function getMount(mountPath) { mountPath = mountPath || ''; if (!mountPath.endsWith('/')) { mountPath += '/'; } return mountPath; } function checkIfIconsExistForApps(apps, iconsFolder) { for (var i in apps) { var currentApp = apps[i]; var iconName = currentApp.iconName; var path = iconsFolder + '/' + iconName; fs.stat(path, function(err) { if (err) { if ('ENOENT' == err.code) {// file does not exist console.warn('Icon with file name: ' + iconName +' couldn\'t be found in icons folder!'); } else { console.log( 'An error occurd while checking for icons, please check permission!'); } } else { //every thing was ok so for example you can read it and send it to client } } ); } } module.exports = function(config, options) { options = options || {}; var app = express(); // Serve public files. app.use(express.static(path.join(__dirname,'parse-dashboard-public'))); // Allow setting via middleware if (config.trustProxy && app.disabled('trust proxy')) { app.enable('trust proxy'); } // wait for app to mount in order to get mountpath app.on('mount', function() { const mountPath = getMount(app.mountpath); const users = config.users; const useEncryptedPasswords = config.useEncryptedPasswords ? true : false; const authInstance = new Authentication(users, useEncryptedPasswords, mountPath); authInstance.initialize(app, { cookieSessionSecret: options.cookieSessionSecret }); // Serve the configuration. app.get('/parse-dashboard-config.json', function(req, res) { let apps = config.apps.map((app) => Object.assign({}, app)); // make a copy let response = { apps: apps, newFeaturesInLatestVersion: newFeaturesInLatestVersion, }; //Based on advice from Doug Wilson here: //https://github.com/expressjs/express/issues/2518 const requestIsLocal = req.connection.remoteAddress === '127.0.0.1' || req.connection.remoteAddress === '::ffff:127.0.0.1' || req.connection.remoteAddress === '::1'; if (!options.dev && !requestIsLocal) { if (!req.secure && !options.allowInsecureHTTP) { //Disallow HTTP requests except on localhost, to prevent the master key from being transmitted in cleartext return res.send({ success: false, error: 'Parse Dashboard can only be remotely accessed via HTTPS' }); } if (!users) { //Accessing the dashboard over the internet can only be done with username and password return res.send({ success: false, error: 'Configure a user to access Parse Dashboard remotely' }); } } const authentication = req.user; const successfulAuth = authentication && authentication.isAuthenticated; const appsUserHasAccess = authentication && authentication.appsUserHasAccessTo; const isReadOnly = authentication && authentication.isReadOnly; // User is full read-only, replace the masterKey by the read-only one if (isReadOnly) { response.apps = response.apps.map((app) => { app.masterKey = app.readOnlyMasterKey; if (!app.masterKey) { throw new Error('You need to provide a readOnlyMasterKey to use read-only features.'); } return app; }); } if (successfulAuth) { if (appsUserHasAccess) { // Restric access to apps defined in user dictionary // If they didn't supply any app id, user will access all apps response.apps = response.apps.filter(function (app) { return appsUserHasAccess.find(appUserHasAccess => { const isSame = app.appId === appUserHasAccess.appId; if (isSame && appUserHasAccess.readOnly) { app.masterKey = app.readOnlyMasterKey; } return isSame; }) }); } // They provided correct auth return res.json(response); } if (users) { //They provided incorrect auth return res.sendStatus(401); } //They didn't provide auth, and have configured the dashboard to not need auth //(ie. didn't supply usernames and passwords) if (requestIsLocal || options.dev) { //Allow no-auth access on localhost only, if they have configured the dashboard to not need auth return res.json(response); } //We shouldn't get here. Fail closed. res.send({ success: false, error: 'Something went wrong.' }); }); // Serve the app icons. Uses the optional `iconsFolder` parameter as // directory name, that was setup in the config file. // We are explicitly not using `__dirpath` here because one may be // running parse-dashboard from globally installed npm. if (config.iconsFolder) { try { var stat = fs.statSync(config.iconsFolder); if (stat.isDirectory()) { app.use('/appicons', express.static(config.iconsFolder)); //Check also if the icons really exist checkIfIconsExistForApps(config.apps, config.iconsFolder); } } catch (e) { // Directory doesn't exist or something. console.warn('Iconsfolder at path: ' + config.iconsFolder + ' not found!'); } } app.get('/login', function(req, res) { if (!users || (req.user && req.user.isAuthenticated)) { return res.redirect(`${mountPath}apps`); } let errors = req.flash('error'); if (errors && errors.length) { errors = `
` } res.send(`