UNPKG

openhab-multiuser-proxy

Version:

Multi-User support for openHAB REST API with NGINX.

206 lines (193 loc) 8.65 kB
import logger from './../../logger.js'; import fetch from 'node-fetch'; import { getHeaders, findKeyInObj } from '../../utils.js'; import { itemsOfSitemapDb, sitemapsListDb, sitemapsForUserDb } from '../../db.js'; import { CACHE_TIME, CACHE_TIME_ACL, ADMIN_OU, EVERYONE_OU, ORG_SEPARATOR } from '../../server.js'; /** * Sitemaps backend namespace. Providing access to the openHAB backend. * * @namespace sitemapsBackend */ /** * Get all available Sitemaps. * Utilising LokiJS to cache the Sitemap list for better performance. * * @memberof sitemapsBackend * @param {String} HOST hostname of openHAB server * @param {*} expressReq request object from expressjs * @returns {Array<Object>} array of Sitemaps */ export const getAllSitemaps = async function (HOST, expressReq) { const now = Date.now(); const sitemapsList = sitemapsListDb.findOne({ name: 'list' }); if (sitemapsList) { if (now < sitemapsList.lastupdate + CACHE_TIME) { // Currently stored version not older than CACHE_TIME. logger.debug('getAllSitemaps(): Found in database and not older than CACHE_TIME.'); return sitemapsList.json; } sitemapsListDb.findAndRemove({ name: 'list' }); } const headers = await getHeaders(expressReq); try { const response = await fetch(HOST + '/rest/sitemaps', { headers: headers }); const json = await response.json(); sitemapsListDb.insert({ name: 'list', lastupdate: now, json: json }); const status = response.status; logger.debug(`getAllSitemaps(): Successfully requested backend ${HOST + '/rest/sitemaps'}, HTTP response code ${status}`); return json; } catch (err) { const error = new Error(`getAllSitemaps(): An error occurred while getting all Sitemaps from ${HOST + '/rest/sitemaps'}: ${err}`); logger.error(error); error(); } }; /** * Get a single Sitemap by name. * * @memberof sitemapsBackend * @param {String} HOST hostname of openHAB server * @param {*} expressReq request object from expressjs * @param {String} sitemapname Sitemap name * @returns {Object} Sitemap */ export const getSitemap = async function (HOST, expressReq, sitemapname) { const headers = await getHeaders(expressReq); try { const response = await fetch(HOST + '/rest/sitemaps/' + sitemapname + '?jsoncallback=callback&includeHidden=true', { headers: headers }); const json = await response.json(); const status = response.status; logger.debug(`getSitemap(): Successfully requested backend ${HOST + '/rest/sitemaps/' + sitemapname + '?jsoncallback=callback&includeHidden=true, HTTP response code ${status}'}`); return { json: json, status: status }; } catch (err) { const error = new Error(`getSitemap(): An error occurred when requesting backend ${HOST + '/rest/sitemaps/' + sitemapname + '?jsoncallback=callback&includeHidden=true'}: ${err}`); logger.error(error); error(); } }; /** * Get a single Page of Sitemap by name and pageid. * * @memberof sitemapsBackend * @param {String} HOST hostname of openHAB server * @param {*} expressReq request object from expressjs * @param {String} sitemapname Sitemap name * @param {String} pageid Page id * @returns {Object} Sitemap */ export const getSitemapPage = async function (HOST, expressReq, sitemapname, pageid) { const headers = await getHeaders(expressReq); //process only query parameters defined in API let query = ''; if (expressReq.query.subscriptionid) query = 'subscriptionid=' + expressReq.query.subscriptionid; query = (query) ? '?' + query + '&includeHidden=true' : '?includeHidden=true'; try { const response = await fetch(HOST + '/rest/sitemaps/' + sitemapname + '/' + pageid + query, { headers: headers }); const json = await response.json(); const status = response.status; logger.debug(`getSitemapPage(): Successfully requested backend ${HOST + '/rest/sitemaps/' + sitemapname + '/' + pageid + query}, HTTP response code ${status}'}`); return { json: json, status: status }; } catch (err) { const error = new Error(`getSitemapPage(): An error occurred when requesting backend ${HOST + '/rest/sitemaps/' + sitemapname + '/' + pageid + query}: ${err}`); logger.error(error); error(); } }; /** * Get names of all Items in Sitemap. * Utilising LokiJS to cache the Items for better performance. * * @memberof sitemapsBackend * @param {String} HOST hostname of openHAB server * @param {*} expressReq request object from expressjs * @param {*} sitemapname Sitemap name * @returns {Array<String>} names of all Items in Sitemap */ export const getItemsOfSitemap = async function (HOST, expressReq, sitemapname) { const now = Date.now(); const itemsDb = itemsOfSitemapDb.findOne({ name: sitemapname }); if (itemsDb) { if (now < itemsDb.lastupdate + CACHE_TIME) { // Currently stored version not older than CACHE_TIME. logger.debug(`getItemsOfSitemap(): Items of Sitemap ${sitemapname} found in database and not older than CACHE_TIME.`); return itemsDb.items; } itemsOfSitemapDb.findAndRemove({ name: sitemapname }); } try { const sitemap = await getSitemap(HOST, expressReq, sitemapname); const items = findKeyInObj(sitemap.homepage.widgets, 'item').map(item => item.name); itemsOfSitemapDb.insert({ name: sitemapname, lastupdate: now, items: items }); logger.debug({ sitemap: sitemapname }, `getItemOfSitemap(): Items of Sitemap ${sitemapname} fetched from backend`); return items; } catch (err) { throw Error(err); } }; /** * Gets sitemapnames's of all allowed Sitemaps for a user. * Utilising LokiJS to cache filtered Sitemaps list for better performance. * * @memberof sitemapsBackend * @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>} sitemapname's of sitemaps allowed for a user */ export const getSitemapsForUser = 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 storedSitemaps = sitemapsForUserDb.findOne({ name: user }); if (storedSitemaps) { if (now < storedSitemaps.lastupdate + CACHE_TIME_ACL) { // Currently stored version not older than CACHE_TIME_ACL. logger.debug('getSitemapsForUser(): Found in database and not older than CACHE_TIME_ACL.'); return storedSitemaps.sitemaps; } sitemapsForUserDb.findAndRemove({ name: user }); } const headers = await getHeaders(expressReq); try { const response = await fetch(HOST + '/rest/sitemaps', { headers: headers }); const allSitemaps = await response.json(); let filteredSitemaps = []; for (const i in allSitemaps) { // For Sitemaps created in MainUI strip "uicomponents_" from sitemapname // If Sitemap name includes ORG_SEPARATOR, return string before ORG_SEPARATOR, else return Sitemap name. let nameOfSitemap = ''; let orgOfSitemap = '' if (allSitemaps[i].name.substring(0,13) == "uicomponents_") { nameOfSitemap = allSitemaps[i].name.substring(13); orgOfSitemap = (nameOfSitemap.includes(ORG_SEPARATOR)) ? nameOfSitemap.split(ORG_SEPARATOR)[0] : nameOfSitemap; } else { nameOfSitemap = allSitemaps[i].name; orgOfSitemap = (nameOfSitemap.includes(ORG_SEPARATOR)) ? nameOfSitemap.split(ORG_SEPARATOR)[0] : nameOfSitemap; } logger.trace(`getSitemapsForUser(): Organization of Sitemap ${allSitemaps[i].name} is ${orgOfSitemap}`); if (nameOfSitemap === user || org.includes(orgOfSitemap) || org.includes(ADMIN_OU) || orgOfSitemap === EVERYONE_OU) { //Access allow when sitename is user name, user org or EVERYONE_OU, Member of ADMIN_OU has full access if (!filteredSitemaps.includes(allSitemaps[i].name)) filteredSitemaps.push(allSitemaps[i].name); } } sitemapsForUserDb.insert({ name: user, lastupdate: now, sitemaps: filteredSitemaps }); const status = response.status; logger.debug(`getSitemapsForUser(): Successfully requested backend ${HOST + '/rest/sitemaps'}, HTTP response code ${status}`); return filteredSitemaps; } catch (err) { const error = new Error(`getSitemapsForUser(): An error occurred while getting all Sitemaps from ${HOST + '/rest/sitemaps'}: ${err}`); logger.error(error); error(); } };