UNPKG

openhab-multiuser-proxy

Version:

Multi-User support for openHAB REST API with NGINX.

136 lines (128 loc) 5.81 kB
import logger from './../../logger.js'; import fetch from 'node-fetch'; import { getHeaders } from '../../utils.js'; import { pagesListDb, pagesForUserDb } from '../../db.js'; import { CACHE_TIME, CACHE_TIME_ACL, ADMIN_OU, EVERYONE_OU, ACL_PREFIX } from '../../server.js'; /** * Pages backend namespace. Providing access to the openHAB backend. * * @namespace pagesBackend */ /** * Gets all available Pages. * Utilising LokiJS to cache the Pages list for better performance. * * @memberof pagesBackend * @param {String} HOST hostname of openHAB server * @param {*} expressReq request object from expressjs * @returns {Object} Object: { json: JSON reponse, status: HTTP status code } */ export const getAllPages = async function (HOST, expressReq) { const now = Date.now(); const pagesList = pagesListDb.findOne({ name: 'list' }); if (pagesList) { if (now < pagesList.lastupdate + CACHE_TIME) { // Currently stored version not older than CACHE_TIME. logger.debug('getAllPages(): Found in database and not older than CACHE_TIME.'); return pagesList.json; } pagesListDb.findAndRemove({ name: 'list' }); } const headers = await getHeaders(expressReq); try { const response = await fetch(HOST + '/rest/ui/components/ui%3Apage', { headers: headers }); const json = await response.json(); pagesListDb.insert({ name: 'list', lastupdate: now, json: json }); const status = response.status; logger.debug(`getAllItems(): Successfully requested backend ${HOST + '/rest/ui/components/ui:page'}, HTTP response code ${status}`); return json; } catch (err) { const error = new Error(`getAllPages(): An error occurred while getting all Pages from ${HOST + '/rest/ui/components/ui:page'}: ${err}`); logger.error(error); error(); } }; /** * Get a single Page by uid(name). * * @memberof pagesBackend * @param {String} HOST hostname of openHAB server * @param {*} expressReq request object from expressjs * @param {String} pageUid Uid(name) of page * @returns {Object} Object: { json: JSON reponse, status: HTTP status code } */ export const getPage = async function (HOST, expressReq, pageUid) { const headers = await getHeaders(expressReq); try { const response = await fetch(HOST + '/rest/ui/components/ui%3Apage/' + pageUid, { headers: headers }); const json = await response.json(); const status = response.status; logger.debug(`getPage(): Successfully requested backend ${HOST + '/rest/ui/components/ui:page/' + pageUid}, HTTP response code ${status}`); return { json: json, status: status }; } catch (err) { const error = new Error(`getPage(): An error occurred when requesting backend ${HOST + '/rest/ui/components/ui:page/' + pageUid}: ${err}`); logger.error(error); error(); } }; /** * Gets uid's of all allowed Pages for a user. * Utilising LokiJS to cache filtered Pages list for better performance. * * @memberof pagesBackend * @param {String} HOST hostname of openHAB server * @param {*} expressReq request object from expressjs * @param {String} user username * @param {String|Array<String>} org organizations the user is member of * @returns {Array<String>} uid's of pages allowed for a user */ export const getPagesForUser = async function (HOST, expressReq, user, org) { if (!user) throw Error('Parameter user is required!'); if (!org) org = []; if (typeof org === 'string') org = org.toString().split('.'); const now = Date.now(); const storedPages = pagesForUserDb.findOne({ name: user }); if (storedPages) { if (now < storedPages.lastupdate + CACHE_TIME_ACL) { // Currently stored version not older than CACHE_TIME_ACL. logger.debug('getPagesForUser(): Found in database and not older than CACHE_TIME_ACL.'); return storedPages.pages; } pagesForUserDb.findAndRemove({ name: user }); } const headers = await getHeaders(expressReq); try { const response = await fetch(HOST + '/rest/ui/components/ui%3Apage?summary=true', { headers: headers }); const allPages = await response.json(); let filteredPages = []; for (const i in allPages) { if (allPages[i].uid === 'home' || allPages[i].uid === 'overview') { //Default OH page 'home' and 'overview' is allways allowed, otherwise MainUI does not load filteredPages.push(allPages[i].uid); } else { for (const j in allPages[i].tags) { if (allPages[i].tags[j].startsWith(ACL_PREFIX)) { if (allPages[i].tags[j].substring(ACL_PREFIX.length) === user || org.includes(allPages[i].tags[j].substring(ACL_PREFIX.length)) || org.includes(ADMIN_OU) || allPages[i].tags[j].substring(ACL_PREFIX.length) === EVERYONE_OU) { //Access allow when tags include user name, user org or EVERYONE_OU, Member of ADMIN_OU has full access if (!filteredPages.includes(allPages[i].name)) filteredPages.push(allPages[i].uid); } } } } } pagesForUserDb.insert({ name: user, lastupdate: now, pages: filteredPages }); const status = response.status; logger.debug(`getPagesForUser(): Successfully requested backend ${HOST + '/rest/ui/components/ui:page?summary=true'}, HTTP response code ${status}`); return filteredPages; } catch (err) { const error = new Error(`getPagesForUser(): An error occurred while getting all Pages from ${HOST + '/rest/ui/components/ui:page?summary=true'}: ${err}`); logger.error(error); error(); } };