From dabd104b3a7126d3b25c486d818c5bbc4f499d74 Mon Sep 17 00:00:00 2001 From: Reaby Date: Tue, 14 May 2019 19:38:43 +0300 Subject: [PATCH] Notice: breaking changes for configs so reconfigure needed, run npm install again as well! Added proper authentication Started to add permissions for ui Added unload webpage from the layer when it hides Added autosense for language based on browser preferred lang --- README.md | 1 - app.js | 71 ++++++++++++++++++++++++++-- config-default.js | 76 +++++++++++++++++++++++++++--- data/default/bundle.json | 2 +- data/meta.json | 30 ------------ locales/en/translation.json | 6 +++ locales/fi/translation.json | 6 +++ modules/admin.js | 4 +- modules/auth.js | 28 ----------- modules/db.js | 27 +++++++++++ modules/display.js | 9 ++-- modules/websocket.js | 10 ++-- package-lock.json | 93 +++++++++++++++++++++++++++++++------ package.json | 4 ++ public/js/display.js | 5 +- routes/admin.js | 29 +++++++----- routes/auth.js | 32 +++++++++++++ routes/index.js | 28 ++++++----- views/admin/dashboard.twig | 24 ++++++---- views/auth/login.twig | 44 ++++++++++++++++++ views/layout/auth.twig | 12 +++++ 21 files changed, 411 insertions(+), 130 deletions(-) delete mode 100644 data/meta.json create mode 100644 modules/db.js create mode 100644 routes/auth.js create mode 100644 views/auth/login.twig create mode 100644 views/layout/auth.twig diff --git a/README.md b/README.md index cd30711..1411ca0 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ Usage is very easy after you have setup the server at local network. The viewer 1. npm install 2. copy `config-default.js` to `config.js` 3. check config settings and if you don't need local rtmp media server, set `mediaServer` to `false` -4. (edit `/data/meta.json`, add, remove or rename the displays you need or use the defaults) 5. npm start # Default usage diff --git a/app.js b/app.js index 51e9784..8257721 100644 --- a/app.js +++ b/app.js @@ -1,9 +1,10 @@ let express = require('express'); let createError = require('http-errors'); -let path = require('path'); let cookieParser = require('cookie-parser'); let logger = require('morgan'); let lessMiddleware = require('less-middleware'); +let path = require('path'); + const EventEmitter = require('events'); let config = require("./config.js"); @@ -19,6 +20,29 @@ let i18next = require("i18next"); let FilesystemBackend = require("i18next-node-fs-backend"); let i18nextMiddleware = require("i18next-express-middleware"); +let passport = require('passport'); +let LocalStrategy = require('passport-local').Strategy; +let User = require("./modules/db.js"); + +passport.use(new LocalStrategy( + { + + }, + function (username, password, cb) { + User.findByUsername(username, function (err, user) { + if (err) { + return cb(err); + } + if (!user) { + return cb(null, false); + } + if (user.password != password) { + return cb(null, false); + } + return cb(null, user); + }); + })); + if (config.mediaServer) { const {NodeMediaServer} = require('node-media-server'); @@ -40,6 +64,18 @@ if (config.mediaServer) { nms.run(); } +passport.serializeUser(function(user, cb) { + cb(null, user.id); +}); + +passport.deserializeUser(function(id, cb) { + User.findById(id, function (err, user) { + if (err) { return cb(err); } + cb(null, user); + }); +}); + + i18next .use(FilesystemBackend) .use(i18nextMiddleware.LanguageDetector) @@ -50,7 +86,27 @@ i18next }, fallbackLng: config.defaultLocale, preload: ['en', 'fi'], - saveMissing: true + saveMissing: true, + detection: { + // order and from where user language should be detected + order: [/*'path', 'session', */ 'querystring', 'cookie', 'header'], + + // keys or params to lookup language from + lookupQuerystring: 'lng', + lookupCookie: 'i18next', + lookupHeader: 'accept-language', + lookupSession: 'lng', + lookupPath: 'lng', + lookupFromPathIndex: 0, + + // cache user language + caches: false, // ['cookie'] + + // optional expire and domain for set cookie + // cookieExpirationDate: new Date(), + // cookieDomain: 'myDomain', + // cookieSecure: true // if need secure cookie + } }); // view engine setup @@ -63,16 +119,23 @@ app.use(express.json()); app.use(express.urlencoded({extended: false})); app.use(cookieParser()); app.use(lessMiddleware(path.join(__dirname, 'public'))); - app.use(express.static(path.join(__dirname, 'public'))); +app.use(require('express-session')({ secret: config.sessionKey, resave: false, saveUninitialized: true })); + +// Initialize Passport and restore authentication state, if any, from the +// session. +app.use(passport.initialize()); +app.use(passport.session()); let websocket = require("./modules/websocket")(server, app, io, eventDispatcher); let indexRouter = require('./routes/index.js')(websocket, eventDispatcher); let adminRouter = require('./routes/admin.js')(websocket, eventDispatcher); +let authRouter = require('./routes/auth.js')(websocket, eventDispatcher); -app.use('/', indexRouter); +app.use('/', authRouter); app.use('/admin', adminRouter); +app.use('/', indexRouter); // catch 404 and forward to error handler app.use(function (req, res, next) { diff --git a/config-default.js b/config-default.js index d256154..1079d91 100644 --- a/config-default.js +++ b/config-default.js @@ -1,14 +1,76 @@ module.exports = { "serverListenPort": process.env.PORT || 8000, - "serverHost": process.env.HOST || "localhost", - "serverUrl": "http://" + (process.env.HOST || "localhost"), + "serverHost": process.env.HOST || "127.0.0.1", + "serverUrl": "http://" + (process.env.HOST || "127.0.0.1"), // used for web client + "sessionKey": "generateRandomStringForSecret", + "secureViews": false, // set true to use password also for viewing info screen content + "useLocalAssets": false, // used to load javascript libraries locally from /public/assets + "mediaServer": false, // local streaming server for rtmp, see docs how to use + "defaultLocale": "en", + + /* + * Administrators + */ + "admins": [ { - "name": process.env.ADMIN_USER || "admin", - "pass": process.env.ADMIN_PASS || "admin" + "id": 1, + "displayName": "Administrator", + "username": "admin", + "password": "admin", + "permissions": { + "isAdmin": true, + "dashboard": { + "addBundle": true, + "addSlides": true, + "addWebPage": true, + } + } + }, + { + "id": 2, + "displayName": "Display Operator", + "username": "operator", + "password": "operator", + "permissions": { + "isAdmin": true, + "dashboard": { + "addBundle": false, + "addSlides": true, + "addWebPage": false, + } + } + }, + { + "id": 3, + "displayName": "Display Viewer", + "username": "view", + "password": "view", + "permissions": { + "isAdmin": false, + } } ], - "mediaServer": false, - "useLocalAssets": false, - "defaultLocale": "en" + /* + * Displays + * If needed, define more screens + */ + + "displays": [ + { + "id": 1, + "name": "Big Screen", + "bundle": "default" + }, + { + "id": 2, + "name": "Secondary Screen", + "bundle": "set1" + }, + { + "id": 3, + "name": "Kiosk", + "bundle": "default" + } + ] }; diff --git a/data/default/bundle.json b/data/default/bundle.json index 6666645..b1d262d 100644 --- a/data/default/bundle.json +++ b/data/default/bundle.json @@ -1,7 +1,7 @@ { "displayName": "default", "background": "bg.jpg", - "duration": 0, + "duration": 30, "transition": "tiles3d", "useWebFonts": false, "displayTime": true, diff --git a/data/meta.json b/data/meta.json deleted file mode 100644 index 160cebb..0000000 --- a/data/meta.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "bundleNames": [ - { - "dir": "default", - "name": "default" - } - ], - "displays": [ - { - "name": "main screen", - "bundle": "default" - }, - { - "name": "2nd screen", - "bundle": "set1" - }, - { - "name": "3rd screen", - "bundle": "default" - }, - { - "name": "4th screen", - "bundle": "set1" - }, - { - "name": "5th screen", - "bundle": "default" - } - ] -} \ No newline at end of file diff --git a/locales/en/translation.json b/locales/en/translation.json index e6be4d8..c21026e 100644 --- a/locales/en/translation.json +++ b/locales/en/translation.json @@ -1,5 +1,11 @@ { "infoscreen": "InfoScreen3", + "auth": { + "userName": "Username", + "password": "Password", + "login": "Login", + "logout": "Logout" + }, "actions": { "upload": "Upload", "uploadScale": "Upload and scale 16:9", diff --git a/locales/fi/translation.json b/locales/fi/translation.json index 78781ba..e9d98e8 100644 --- a/locales/fi/translation.json +++ b/locales/fi/translation.json @@ -1,5 +1,11 @@ { "infoscreen": "InfoScreen3", + "auth": { + "userName": "Käyttäjätunnus", + "password": "Salasana", + "login": "Kirjaudu", + "logout": "Kirjaudu ulos" + }, "actions": { "upload": "Lataa", "uploadScale": "Lataa ja skaalaa 16:9", diff --git a/modules/admin.js b/modules/admin.js index a729c39..0deea15 100644 --- a/modules/admin.js +++ b/modules/admin.js @@ -540,13 +540,13 @@ class admin { previewInstances.push({adminId: socket.id, preview: {}, currentView: {}}); let serverOptions = getView(displayId).serverOptions; let bundleDirs = self.bundleManager.getBundleInfos(); - let meta = JSON.parse(fs.readFileSync("./data/meta.json").toString()); + socket.emit("callback.dashboard.sync", { displayId: displayId, bundleDirs: bundleDirs, serverOptions: serverOptions, - displays: meta.displays + displays: config.displays }); } diff --git a/modules/auth.js b/modules/auth.js index be973a3..e69de29 100644 --- a/modules/auth.js +++ b/modules/auth.js @@ -1,28 +0,0 @@ - -let basicAuth = require("basic-auth"); -let config = require("../config.js"); - -module.exports = function (req, res, next) { - function unauthorized(res) { - res.set("WWW-Authenticate", "Basic realm=Authorization Required"); - return res.sendStatus(401); - } - - let user = basicAuth(req); - - if (!user || !user.name || !user.pass) { - return unauthorized(res); - } - - for (let i in config.admins) { - let admin = config.admins[i]; - if (user.name === admin.name && user.pass === admin.pass) { - return next('route'); - } - } - - return unauthorized(res); -}; - - - diff --git a/modules/db.js b/modules/db.js new file mode 100644 index 0000000..be8d84a --- /dev/null +++ b/modules/db.js @@ -0,0 +1,27 @@ +var records = require("../config.js").admins; +module.exports = { + + findById: function(id, cb) { + process.nextTick(function () { + var idx = id - 1; + if (records[idx]) { + cb(null, records[idx]); + } else { + cb(new Error('User ' + id + ' does not exist')); + } + }); + }, + + findByUsername: function(username, cb) { + process.nextTick(function () { + for (var i = 0, len = records.length; i < len; i++) { + var record = records[i]; + if (record.username === username) { + return cb(null, record); + } + } + return cb(null, null); + }); + } + +}; diff --git a/modules/display.js b/modules/display.js index 29e5041..5c526b8 100644 --- a/modules/display.js +++ b/modules/display.js @@ -5,19 +5,19 @@ let bundleManager = require('./bundleManager.js'); /** * handles one display instance - * @module infoscreen3/display + * @module infoscreen/display */ class display { /** * @param {object} sharedIO - socketIO * @param {object} dispatcher - dispatcher - * @param {object} meta - reads from ./data/meta.json --> as display[displayId] + * @param {object} meta - reads from config.displays * @param {number} displayId - this display instances id * @param {object} bundleManager */ constructor(sharedIO, dispatcher, meta, displayId, bundleManager) { - cli.info("Starting display" + displayId + ": " + meta.name + "..."); + cli.info("Starting display with id " + displayId + " ..."); /** @property {Array} timeoutId - holds setTimeout id's for mainLoop */ this.timeoutId = []; @@ -104,7 +104,7 @@ class display { }); // io this.init(meta); - cli.info("done."); + cli.success(meta.name + " started with '" + meta.bundle + "'"); } // display @@ -236,4 +236,5 @@ class display { } } +/** @exports display */ module.exports = display; \ No newline at end of file diff --git a/modules/websocket.js b/modules/websocket.js index 185ab4f..35a60f0 100644 --- a/modules/websocket.js +++ b/modules/websocket.js @@ -1,4 +1,4 @@ -let meta = require("../data/meta.json"); +let availableDisplays = require("../config.js").displays; let display = require("./display.js"); let admin = require("./admin.js"); let cli = require('./cli.js'); @@ -8,12 +8,12 @@ let fs = require('fs'); /** * - * @type {module:infoscreen3/display[]} + * @type {display[]} */ let screenView = []; /** - * @exports infoscreen3/websocket + * @exports websocket */ module.exports = function (server, app, io, dispatcher) { console.log(chalk.green(">> ") + "InfoScreen3" + chalk.green("<<")); @@ -53,7 +53,7 @@ module.exports = function (server, app, io, dispatcher) { cli.info("Starting websocket backends..."); let screenId = 0; - for (let metadata of meta.displays) { + for (let metadata of availableDisplays) { screenView.push(new display(io, dispatcher, metadata, screenId, bundleManager)); screenId += 1; } @@ -80,7 +80,7 @@ module.exports = function (server, app, io, dispatcher) { previewImages.push("/img/nopreview.png"); } } - socket.emit("callback.displays", {displays: meta.displays, previewImages: previewImages}); + socket.emit("callback.displays", {displays: availableDisplays, previewImages: previewImages}); }); }); diff --git a/package-lock.json b/package-lock.json index 00534e6..1d79b63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -82,8 +82,7 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "optional": true + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "async-limiter": { "version": "1.0.0", @@ -253,7 +252,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "optional": true, "requires": { "delayed-stream": "~1.0.0" } @@ -286,6 +284,11 @@ "busboy": "*" } }, + "connect-ensure-login": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/connect-ensure-login/-/connect-ensure-login-0.1.1.tgz", + "integrity": "sha1-F03MUSQ7nqwj+NmCFa62aU4uihI=" + }, "content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -363,8 +366,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "optional": true + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "depd": { "version": "1.1.2", @@ -541,6 +543,33 @@ } } }, + "express-session": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.16.1.tgz", + "integrity": "sha512-pWvUL8Tl5jUy1MLH7DhgUlpoKeVPUTe+y6WQD9YhcN0C5qAhsh4a8feVjiUXo3TFhIy191YGZ4tewW9edbl2xQ==", + "requires": { + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.2", + "safe-buffer": "5.1.2", + "uid-safe": "~2.1.5" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + } + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -550,8 +579,7 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "optional": true + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { "version": "2.0.1", @@ -790,8 +818,7 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "json-schema": { "version": "0.2.3", @@ -920,7 +947,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" @@ -1038,11 +1065,38 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" }, + "passport": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz", + "integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=", + "requires": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + } + }, + "passport-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", + "integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=", + "requires": { + "passport-strategy": "1.x.x" + } + }, + "passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -1090,6 +1144,11 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, + "random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" + }, "range-parser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", @@ -1153,8 +1212,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "optional": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", @@ -1372,8 +1430,7 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "twig": { "version": "0.10.3", @@ -1394,6 +1451,14 @@ "mime-types": "~2.1.18" } }, + "uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "requires": { + "random-bytes": "~1.0.0" + } + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", diff --git a/package.json b/package.json index 0367f3c..addd321 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,12 @@ "basic-auth": "^2.0.1", "chalk": "^2.4.2", "connect-busboy": "0.0.2", + "connect-ensure-login": "^0.1.1", "cookie-parser": "^1.4.4", "cors": "^2.8.5", "debug": "~2.6.9", "express": "^4.16.4", + "express-session": "^1.16.1", "http-errors": "~1.6.2", "i18next": "^15.1.0", "i18next-express-middleware": "^1.8.0", @@ -21,6 +23,8 @@ "morgan": "~1.9.0", "node-media-server": "^1.4.15", "node.extend": ">=2.0.1", + "passport": "^0.4.0", + "passport-local": "^1.0.0", "socket.io": "^2.2.0", "twig": "~0.10.3" } diff --git a/public/js/display.js b/public/js/display.js index 353606b..32d0e9e 100644 --- a/public/js/display.js +++ b/public/js/display.js @@ -447,7 +447,10 @@ function getWebLayer(offset) { function clearIFrame(elementId) { var frame = document.getElementById(elementId); - frame.contentWindow.location.href = "/empty"; + + if (frame.contentWindow.location.href !== document.location.origin + "/empty") { + frame.contentWindow.location.href = "/empty"; + } } diff --git a/routes/admin.js b/routes/admin.js index 7c50ca4..b0f7a02 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -1,5 +1,4 @@ let express = require('express'); -let authMiddleWare = require('../modules/auth.js'); let router = express.Router(); let cli = require("../modules/cli.js"); let fs = require('fs'); @@ -7,14 +6,28 @@ let path = require('path'); let config = require("../config.js"); let busboy = require("connect-busboy"); +function ensureIsAdmin(req, res, next) { + + if (!req.isAuthenticated || !req.isAuthenticated()) { + req.session.location = "/admin"; + return res.redirect("/login"); + } else { + if (!req.user.permissions.isAdmin) { + cli.error(req.user.displayName + " has tried to access admin!", "permission error"); + return res.redirect("/login"); + } + } + next(); +} + module.exports = function (websocket, dispatcher) { var bundleManager = websocket.bundleManager; - router.use(authMiddleWare); + router.use(ensureIsAdmin); router.use(busboy({immediate: true})); router.get('/', function (req, res, next) { - res.render('admin/dashboard', {config: config}); + res.render('admin/dashboard', {config: config, permission: req.user.permissions}); }); router.get('/preview', function (req, res, next) { @@ -100,14 +113,12 @@ module.exports = function (websocket, dispatcher) { router.get('/edit/bundleSlides', function (req, res, next) { - // let bundles = getDirectories("./data"); var bundle = {}; try { bundle = bundleManager.getBundle(req.query['bundle']); } catch (err) { - + cli.error(err, "can't find bundle"); } - console.log(bundle); res.render('admin/editBundleSlides', {config: config, bundle: bundle}); }); @@ -129,11 +140,5 @@ module.exports = function (websocket, dispatcher) { res.render('ajax/bundleImageList', {bundleImages: output}); }); - function getDirectories(path) { - return fs.readdirSync(path).filter(function (file) { - return fs.statSync(path + '/' + file).isDirectory(); - }); - } - return router; }; diff --git a/routes/auth.js b/routes/auth.js new file mode 100644 index 0000000..0a302fd --- /dev/null +++ b/routes/auth.js @@ -0,0 +1,32 @@ +let router = require('express').Router(); +let passport = require("passport"); + +module.exports = function (websocket, dispatcher) { + + router.get('/login', function (req, res, next) { + console.log(req.session); + + res.render('auth/login'); + }); + + router.post('/login', + passport.authenticate('local', {failureRedirect: '/login'}), + function (req, res) { + if (req.session.location) { + return res.redirect(req.session.location); + } + return res.redirect("/"); + }); + + router.get('/logout', + function (req, res) { + req.logout(); + res.redirect('/'); + }); + + router.get('/empty', function (req, res, next) { + res.render('empty'); + }); + + return router; +}; \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index bad0869..44ae80c 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,34 +1,38 @@ let express = require('express'); -let authMiddleWare = require('../modules/auth.js'); let router = express.Router(); let fs = require("fs"); let config = require("../config.js"); -let displayMeta = require("../data/meta.json"); +let availableDisplays = config.displays; const cli = require('../modules/cli.js'); +function ensureIsAdmin(req, res, next) { + if (!req.isAuthenticated || !req.isAuthenticated()) { + req.session.location = "/"; + console.log(req.session); + return res.redirect("/login"); + } + return next(); +} + module.exports = function (websocket, dispatcher) { - - router.use(authMiddleWare); - + if (config.secureViews) { + router.use(ensureIsAdmin); + } router.get('/', function (req, res, next) { res.header('Access-Control-Allow-Origin', '*'); res.render('index', {config: config}); }); - router.get('/empty', function (req, res, next) { - res.render('empty'); - }); - router.get('/display/:id/lite', function (req, res, next) { res.header('Access-Control-Allow-Origin', '*'); let idx = parseInt(req.params.id); - res.render('liteDisplay', {config: config, display: displayMeta.displays[idx], displayId: idx}); + res.render('liteDisplay', {config: config, display: availableDisplays[idx], displayId: idx}); }); router.get('/display/:id', function (req, res, next) { res.header('Access-Control-Allow-Origin', '*'); let idx = parseInt(req.params.id); - res.render('display', {config: config, display: displayMeta.displays[idx], displayId: idx}); + res.render('display', {config: config, display: availableDisplays[idx], displayId: idx}); }); router.get('/images/:dir/:name', function (req, res, next) { @@ -77,7 +81,7 @@ module.exports = function (websocket, dispatcher) { } }; - res.sendFile("display_"+req.params.displayId+".png", options, function (err) { + res.sendFile("display_" + req.params.displayId + ".png", options, function (err) { if (err) { cli.error(err); res.end(); diff --git a/views/admin/dashboard.twig b/views/admin/dashboard.twig index 4e60d1a..4dd3bc9 100644 --- a/views/admin/dashboard.twig +++ b/views/admin/dashboard.twig @@ -45,7 +45,9 @@ @@ -57,9 +59,10 @@

{{ t("admin.dashboard.allBundles") }}

- - + {% if permission.dashboard.addBundle %} + + {% endif %}
@@ -69,11 +72,14 @@

{{ t("admin.dashboard.slidesInRotation") }}

- - - - + {% if permission.dashboard.addSlides %} + + {% endif %} + {% if permission.dashboard.addWebPage %} + + {% endif %}
diff --git a/views/auth/login.twig b/views/auth/login.twig new file mode 100644 index 0000000..5eaafe2 --- /dev/null +++ b/views/auth/login.twig @@ -0,0 +1,44 @@ +{% extends 'layout/auth.twig' %} + +{% block header %} + +{% endblock %} + +{% block body %} +
+
+

+ InfoScreen3 +

+
+
+
+
+ + +
+
+
+
+ + +
+
+ +
+
+
+
+{% endblock %} diff --git a/views/layout/auth.twig b/views/layout/auth.twig new file mode 100644 index 0000000..6348590 --- /dev/null +++ b/views/layout/auth.twig @@ -0,0 +1,12 @@ + + + + InfoScreen3 - Auth + + {% include "assets.twig" %} + {% block header %}{% endblock %} + + +{% block body %}{% endblock %} + +