'use strict' /** * Copyright (c) 2017~2020, OBCon Inc. * All rights reserved. */ /** * @file * @copyright 2017~2020, OBCon Inc. * @author gye hyun james kim [pnuskgh@gmail.com] */ const fs = require('fs'); const path = require('path'); const moment = require('moment'); //--- 시나리오 //--- 로그인이 완료되면, 사용자의 authorization을 설정하여 세션에 저장 한다. //--- 일정 주기마다 //--- 권한 확인이 필요한 경우, 세션에 저장된 authorization을 사용하여 권한 확인을 한다. class Authorization { constructor() { this._folder = utils.getPath('files', 'settings', config.service.name, 'roles'); this._filePrefix = 'authorization_'; //--- ${this._filePrefix}${roleId}.json this._authorization = null; //--- 권한 this._duration = 30 * 60; //--- 세션에서 authorization 갱신 주기 (30분) this._init(); } get authorization() { return this._authorization; } set authorization(newValue) { this._authorization = newValue; } _init() { let paths = [ utils.getPath('files'), utils.getPath('files', 'settings'), utils.getPath('files', 'settings', config.service.name), utils.getPath('files', 'settings', config.service.name, 'roles') ]; for (let idx = 0; idx < paths.length; idx++) { let path = paths[idx]; if (fs.existsSync(path) == false) { fs.mkdirSync(path); } }; } //--- Default Authorization을 반환 한다. //--- 개별 장비별 설정은 포함하지 않는다. _getDefaultAuthorization(req) { let version = '0.01'; //--- 디폴트 설정 let versionDate = '2020-08-19'; //--- 디폴트 설정 let showHide = 'show'; //--- 디폴트 설정 let authorization = { version: version, //--- Authorization 설정의 버전 versionDate: versionDate, //--- Authorization 설정의 버전 시작일 createDate : moment(), //--- Authorization 생성 일시 modules: { //--- Reserved, 모듈에 대한 일반적인 권한 설정 devices: this._getDefaultModuleAuthorization() } }; //--- 모듈별 개별 설정 authorization.devices = { //--- 장비 모듈. ${modules} showHide: showHide, //--- 보여 주기 전체 설정 : show (Default). 모든 장비를 보여 준다. hide. 모든 장비를 보여주지 않는다. types: { //--- 장비 타입별 담당자 설정 // ${type_1}: { // title: '정류기', //--- modules.devices.setting.getSettings().types 참조 // use: false, //--- modules.devices.setting.getSettings().types 참조 후 site별 settings 값 반영 // //--- none(Default). 설정 없음, show. 모두 보이기, hide. 모두 감추기 // //--- none인 경우, showHide 설정을 따른다. // showHide: 'none' // } }, show: [], //--- 화면에 표시할 장비 ID 목록 hide: [] //--- 화면에 표시하지 않을 장비 ID 목록 }; //--- modules.devices.setting.getSettings().types을 반영 한다. let deviceSettings = modules.devices.setting.getSettings(); for (let idx = 0; idx < deviceSettings.types.length; idx++) { let type = deviceSettings.types[idx]; let roleType = {}; roleType.title = type.title; roleType.use = type.use; roleType.showHide = 'none'; authorization.devices.types[`type_${type.name}`] = roleType; } //--- site의 디바이스 설정을 읽어서 반영한다. let types = settingSync.getSetting(req.session.site.siteKey, 'devices', 'types', []); for (let idx = 0; idx < types.length; idx++) { let type = types[idx]; authorization.devices.types[`type_${type.name}`].use = type.use; } //--- types별 값을 지정하는 로직을 추가할 것 return authorization; } resetAuthorization(req, callback) { let diff = moment().diff(req.session.authorization.createDate) / 1000 / 60; //--- 분 if (this._duration < diff) { let query = { where: { site: req.session.site.id, id: req.session.user.id, deleted: false } }; modules.users.model.table.findOne(query) .then(function(user) { req.session.user = user; this.setAuthorization(req, user, function(auth) { req.session.authorization = auth; callback(); }.bind(this)); }.bind(this)).catch(function(err) { callback(); }); } else { callback(); } } //--- 특정 사용자의 권한 정보를 확인 한다. setAuthorization(req, user=null, callback=null) { logger.info('Start setAuthorization'); let params = { roles: [], authorizations: [], authorization: null }; if (user == null) { user = req.session.user; //--- 로그인한 사용자의 권한 정보를 확인 한다. } logger.info(`${user.name} user : role - ${user.role}, group - ${user.group}`); //--- 1. 역할(roles) 목록을 가져온다. let myPromise = new Promise(function(resolve, reject) { //--- 1-1. 사용자의 role을 가져 온다. if (user.role == -1) { resolve(); } else { let query = { where: { site: user.site, id: user.role, deleted: false } }; modules.roles.model.table.findOne(query) .then(function(role) { if (role != null) { params.roles.push(role); } resolve(); }.bind(this)).catch(reject); } }.bind(this)); myPromise = myPromise.then(function() { return new Promise(function(resolve, reject) { //--- 1-2. 사용자가 속한 그룹의 role을 가져 온다. if (user.group == -1) { resolve(); } else { let query = { where: { site: user.site, id: user.group, deleted: false } }; modules.groups.model.table.findOne(query) .then(function(group) { if (group == null) { resolve(); } else { if (group.role == -1) { resolve(); } else { query = { where: { site: user.site, id: group.role, deleted: false } }; modules.roles.model.table.findOne(query) .then(function(role) { if (role != null) { params.roles.push(role); } resolve(); }.bind(this)).catch(reject); } } }.bind(this)).catch(reject); } }.bind(this)); }.bind(this)); myPromise = myPromise.then(function() { return new Promise(function(resolve, reject) { //--- 4. 장비 정보를 읽어 권한을 최종 확정 한다. let query = { where: { site: user.site, deleted: false } }; modules.devices.model.table.findAll(query) .then(function(devices) { // logger.info('ppp devices count ' + devices.length); //--- 2. 역할별로 권한을 가져 온다. for (let idx = 0; idx < params.roles.length; idx++) { let auth = this.readAuthorization(req, params.roles[idx]); params.authorizations.push(this.updateDevices(devices, auth)); } //--- 3. 권한을 조합하여 하나의 권한을 생성 한다. params.authorization = this._mergeAuthorizations(req, params.authorizations); this._authorization = params.authorization; if (callback !== null) { callback(this._authorization); } }.bind(this)).catch(reject); }.bind(this)); }.bind(this)); myPromise = myPromise.catch(function(err) { //--- reject() 함수에서 에러 처리를 위해 호출 한다. //--- 권한을 instance와 session에 저장 한다. this._authorization = null; }.bind(this)); } //--- role에 해당하는 권한 정보를 가져 온다. readAuthorization(req, role) { if (role == null) { return this._getDefaultAuthorization(req); } let roleId = role.id; let filename = `${this._folder}${path.sep}${this._filePrefix}${roleId}.json`; let authorization = null; if (fs.existsSync(filename)) { let buf = fs.readFileSync(filename, { encoding: 'utf8' }); authorization = this._mergeAuthorizations(req, [ JSON.parse(buf) ]); } else { authorization = this._getDefaultAuthorization(req); } return authorization; } //--- Reserved, 모듈의 디폴트 권한 설정 반환 _getDefaultModuleAuthorization() { return { access: 'Not Set', //--- 접속 권한 : Enable, Not Set (Default), Disabled list: 'Not Set', //--- 목록 조회 권한 : All, Group, Owner, Not Set (Default), None view: 'Not Set', //--- 조회 권한 : All, Group, Owner, Not Set (Default), None edit: 'Not Set', //--- 등록/수정 권한 : All, Group, Owner, Not Set (Default), None delete: 'Not Set', //--- 삭제 권한 : All, Group, Owner, Not Set (Default), None import: 'Not Set', //--- 목록 조회 권한 : All, Not Set (Default), None export: 'Not Set' //--- 목록 조회 권한 : All, Group, Owner, Not Set (Default), None }; } //--- Reserved, 모듈의 디폴트 권한 설정 2개를 병합하여 반환 한다. _mergeDefaultModuleAuthorization(auth1, auth2) { let auth = {}; let data = [ 'access', 'list', 'view', 'edit', 'delete', 'import', 'export' ]; for (let idx = 0; idx < data.length; idx++) { let item = data[idx]; let access1 = auth1[item]; let access2 = auth2[item]; let access = 'Not Set'; switch(item) { case 'access': if (access1 == 'Enable') { access = 'Enable'; } else if (access1 = 'Not Set') { access = access2; } else { //--- access1 = 'Disabled' if (access2 == 'Enable') { access = 'Enable'; } else if (access2 = 'Not Set') { access = access1; } else { //--- access2 = 'Disabled' access = 'Disabled'; } } break; case 'import': if (access1 == 'Enable') { access = 'Enable'; } else if (access1 = 'Not Set') { access = access2; } else { //--- access1 = 'None' if (access2 == 'Enable') { access = 'Enable'; } else if (access2 = 'Not Set') { access = access1; } else { //--- access2 = 'None' access = 'None'; } } break; case 'list': case 'view': case 'edit': case 'delete': case 'export': default: if (access1 == 'All') { access = 'All'; } else if (access1 = 'Group') { if (access2 == 'All') { access = 'All'; } else if (access2 = 'Group') { access = 'Group'; } else if (access2 = 'Owner') { access = 'Group'; } else if (access2 = 'Not Set') { access = access1; } else { //--- access2 = 'None' access = 'Group'; } } else if (access1 = 'Owner') { if (access2 == 'All') { access = 'All'; } else if (access2 = 'Group') { access = 'Group'; } else if (access2 = 'Owner') { access = 'Owner'; } else if (access2 = 'Not Set') { access = access1; } else { //--- access2 = 'None' access = 'Owner'; } } else if (access1 = 'Not Set') { access = access2; } else { //--- access1 = 'None' if (access2 == 'All') { access = 'All'; } else if (access2 = 'Group') { access = 'Group'; } else if (access2 = 'Owner') { access = 'Owner'; } else if (access2 = 'Not Set') { access = access1; } else { //--- access2 = 'None' access = 'None'; } } break; } auth[item] = access; } return auth; } //--- Authorizations을 하나로 병합 한다. //--- 값이 없는 경우에는 디폴트 값으로 채운다. _mergeAuthorizations(req, authorizations) { if (authorizations.length == 0) { return this._getDefaultAuthorization(req); } let rtAuthorization = authorizations[0]; for (let idx = 1; idx < authorizations.length; idx++) { let authorization = authorizations[idx]; rtAuthorization.version = (rtAuthorization.version < authorization.version) ? authorization.version: rtAuthorization.version; rtAuthorization.versionDate = (rtAuthorization.versionDate < authorization.versionDate) ? authorization.versionDate: rtAuthorization.versionDate; rtAuthorization.modules.devices = this._mergeDefaultModuleAuthorization(rtAuthorization.modules.devices, authorization.modules.devices); if ((rtAuthorization.devices.showHide == 'show') || (authorization.devices.showHide == 'show')) { rtAuthorization.devices.showHide = 'show'; } else { rtAuthorization.devices.showHide = 'hide'; } let deviceSettings = modules.devices.setting.getSettings(); for (let idx = 0; idx < deviceSettings.types.length; idx++) { let type = deviceSettings.types[idx]; let name = `type_${type.name}`; let roleType = {}; roleType.title = type.title; roleType.use = ((rtAuthorization.devices.types[name].use) || ((authorization.devices.types[name].use))); if (rtAuthorization.devices.types[name].showHide == 'none') { roleType.showHide = authorization.devices.types[name].showHide; } else if (rtAuthorization.devices.types[name].showHide == 'show') { roleType.showHide = 'show'; } else { //--- rtAuthorization.devices.types[name].showHide == 'hide' if (authorization.devices.types[name].showHide == 'none') { roleType.showHide = 'hide'; } else if (authorization.devices.types[name].showHide == 'show') { roleType.showHide = 'show'; } else { //--- authorization.devices.types[name].showHide == 'hide' roleType.showHide = 'hide'; } } rtAuthorization.devices.types[name] = roleType; } //--- site의 디바이스 설정을 읽어서 반영한다. let types = settingSync.getSetting(req.session.site.siteKey, 'devices', 'types', []); for (let idx = 0; idx < types.length; idx++) { let type = types[idx]; rtAuthorization.devices.types[`type_${type.name}`].use = type.use; } for (let idx = 0; idx < authorization.devices.show.length; idx++) { let deviceId = authorization.devices.show[idx]; if (rtAuthorization.devices.show.includes(deviceId) == false) { rtAuthorization.devices.show.push(deviceId); } } for (let idx = 0; idx < authorization.devices.hide.length; idx++) { let deviceId = authorization.devices.hide[idx]; if (rtAuthorization.devices.hide.includes(deviceId) == false) { rtAuthorization.devices.hide.push(deviceId); } } } let hides = []; for (let idx = 0; idx < rtAuthorization.devices.hide.length; idx++) { let deviceId = rtAuthorization.devices.hide[idx]; if (rtAuthorization.devices.show.includes(deviceId) == false) { hides.push(deviceId); } } rtAuthorization.createDate = moment(); return rtAuthorization; } //--- 전체 장비 목록을 받아 권한 설정을 최신화 한다. updateDevices(devices, authorization=null) { let flagUpdate = false; if (authorization == null) { authorization = this._authorization; flagUpdate = true; } if (authorization == null) { console.log('pppppppppp updateDevices'); } let show = []; let hide = []; for (let idx = 0; idx < devices.length; idx++) { let device = devices[idx]; let authType = authorization.devices.types[`type_${device.type}`]; if (authType == 'show') { show.push(device.id); } else if (authType == 'hide') { hide.push(device.id); } else { if (authorization.devices.showHide == 'show') { if (authorization.devices.hide.includes(device.id)) { hide.push(device.id); } else { show.push(device.id); } } else { if (authorization.devices.show.includes(device.id)) { show.push(device.id); } else { hide.push(device.id); } } } } authorization.devices.show = show; authorization.devices.hide = hide; if (flagUpdate) { this._authorization = authorization; } return authorization; } //--- 하나의 role에 해당하는 권한 파일을 생성 한다. writeAuthorization(roleId, authorization) { let filename = `${this._folder}${path.sep}${this._filePrefix}${roleId}.json`; fs.writeFileSync(filename, JSON.stringify(authorization), { encoding: 'utf8' }); } //--- 전체 장비 목록을 받아 조회 권한이 있는 장비 목록만 반환 한다. getAuthorizedDevices(devices) { let rtDevices = []; let auth = this.updateDevices(devices); let show = auth.devices.show; for (let idx = 0; idx < devices.length; idx++) { let device = devices[idx]; if (show.includes(device.id)) { rtDevices.push(device); } } return rtDevices; } //--- 전체 알람 목록을 받아 조회 권한이 있는 알람 목록만 반환 한다. getAuthorizedNotifications(notifications) { let rtNotifications = []; let show = this._authorization.devices.show; for (let idx = 0; idx < notifications.length; idx++) { let notification = notifications[idx]; if (show.includes(notification.device)) { rtNotifications.push(notification); } } return rtNotifications; } //--- 역할 등록/수정 화면에서 전달된 데이터를 반영 한다. updateUserRole(role) { let deviceSettings = modules.devices.setting.getSettings(); for (let idx = 0; idx < deviceSettings.types.length; idx++) { let typeName = `type_${deviceSettings.types[idx].name}`; this._authorization.devices.types[typeName].showHide = role.types[typeName]; } this._authorization.devices.show = role.show; this._authorization.devices.hide = role.hide; // let newHide = []; // let hide = this._authorization.devices.hide; // for (let idx = 0; idx < hide.length; idx++) { // let deviceId = hide[idx]; // if (role.show.includes(deviceId) == false) { // newHide.push(deviceId); // } // } // this._authorization.devices.hide = newHide; } } module.exports = Authorization;