export class AccesRights { constructor(config, debug){ this.debug = debug this.config = config this.rights = config.accessRights } refreshAccessRights(config){ this.rights = config.accessRights } expandPattern(pattern, uid, cnxId=null) { if(/\[CNXID\]/.test(pattern) && !cnxId) return(null) let item = pattern.replace(/\[UID\]/g, uid) if(cnxId) item = item.replace(/\[CNXID\]/g, cnxId) return(item) } expandPatterns(patterns, uid, cnxId=null) { return(patterns.map(item => this.expandPattern(item, uid, cnxId)).filter(item => item != null)) } mustSubscribe(uid, roles, cnxId=null) { if(roles.indexOf('*')<0) roles.push('*') let chans = [] for(let myRole of roles){ for(let rightBlock of this.rights) { if(!rightBlock.mustSubscribe) continue if((rightBlock.roles=='*') || (rightBlock.roles.indexOf(myRole)>-1)) { chans = this.merge(chans, this.expandPatterns(rightBlock.mustSubscribe, uid, cnxId)) } } } return(chans) } isMandatory(uid, roles, chan, cnxId=null){ return(this.mustSubscribe(uid, roles, cnxId).filter(this.chanMatch.bind(this, chan)).length>0) } canSubscribe(uid, roles, myChan, cnxId=null) { if(roles.indexOf('*')<0) roles.push('*') for(let myRole of roles){ for(let rightBlock of this.rights) { if(!rightBlock.canSubscribe) continue if((rightBlock.roles=='*') || (rightBlock.roles.indexOf(myRole)>-1)) { let canSubList = this.expandPatterns(rightBlock.canSubscribe, uid, cnxId) if(canSubList.find(this.chanMatch.bind(this, myChan))) return(true) } } } //if(this.debug) console.log(`Roles : ${roles} cannot subscribe on ${myChan}`) return(false) } canPublish(uid, roles, myChan, cnxId=null) { if(roles.indexOf('*')<0) roles.push('*') for(let myRole of roles){ for(let rightBlock of this.rights) { if(!rightBlock.canPublish) continue if((rightBlock.roles=='*') || (rightBlock.roles.indexOf(myRole)>-1)) { let canPubList = this.expandPatterns(rightBlock.canPublish, uid, cnxId) if(canPubList.find(this.chanMatch.bind(this, myChan))) return(true) } } } //if(this.debug) console.log(`Roles : ${roles} cannot publish on ${myChan}`) return(false) } canSet(uid, roles, myKey, cnxId=null){ if(roles.indexOf('*')<0) roles.push('*') for(let myRole of roles){ for(let rightBlock of this.rights) { if(!rightBlock.canSet) continue if((rightBlock.roles=='*') || (rightBlock.roles.indexOf(myRole)>-1)) { let canSetList = this.expandPatterns(rightBlock.canSet, uid, cnxId) if(canSetList.find(this.chanMatch.bind(this, myKey))) return(true) } } } //if(this.debug) console.log(`Roles : ${roles} cannot set ${myKey}`) return(false) } canGet(uid, roles, myKey, cnxId=null){ if(roles.indexOf('*')<0) roles.push('*') for(let myRole of roles){ for(let rightBlock of this.rights) { if(!rightBlock.canGet) continue if((rightBlock.roles=='*') || (rightBlock.roles.indexOf(myRole)>-1)) { let canGetList = this.expandPatterns(rightBlock.canGet, uid, cnxId) if(canGetList.find(this.chanMatch.bind(this, myKey))) return(true) } } } //if(this.debug) console.log(`Roles : ${roles} cannot get ${myKey}`) return(false) } canDo(roles, action, uid=null){ if(roles.indexOf('*')<0) roles.push('*') for(let myRole of roles){ for(let rightBlock of this.rights) { if(!rightBlock.canDo) continue if((rightBlock.roles=='*') || (rightBlock.roles.indexOf(myRole)>-1)) { if(rightBlock.canDo.indexOf(action)>-1) { if((rightBlock.uuids) && Array.isArray((rightBlock.uuids))) { // !!! Separate condition so if rightBlock.uuids but not uid in it, we don't give access ! if(rightBlock.uuids.includes(uid)) return(true) // null should never be in config uuids => old style calls are safe } else { // no uuid block => role is sufficient to give access return(true) } } } } } //Anti-shoot-your-foot if((action=='reloadAccessRights') && (roles.includes('EIC_Dev'))) { console.error('Prevented you from shooting your foot ! \nPlease keep least EIC_Dev in reload access rights !') return(true) } //if(this.debug) console.log(`Roles : ${roles} cannot do ${action}`) return(false) } chanMatch(myChan, configChan) { if((!myChan) || (typeof(myChan)!='string')) return(false) let re = new RegExp('^'+configChan.replace(/\*/g,'(.+)')+'$','g') return(myChan.match(re)!=null) } merge(x, y) { let tmp = x for(let yitem of y) if(tmp.indexOf(yitem)<0) tmp.push(yitem) return(tmp) } }