2nd
This commit is contained in:
+167
@@ -0,0 +1,167 @@
|
||||
module.exports.methods = {
|
||||
|
||||
/* Creates (predictable) peer-to-peer chan if necessary, or check for lobby existence, then subscribe to it.
|
||||
Request:
|
||||
{
|
||||
"action": "STARTCHAT",
|
||||
"payload": "P" // or "C" => "P" = Peer-to-peer, "C" = (chat) Channel
|
||||
}
|
||||
reply:
|
||||
{
|
||||
"action": "STARTCHAT",
|
||||
"success": true,
|
||||
"payload" : "dynamically created chan"
|
||||
}
|
||||
*/
|
||||
action_STARTCHAT(action, payload, reqid){
|
||||
if(typeof(payload)!='string'){
|
||||
this.sendErr(action, 'Invalid payload', reqid);
|
||||
return;
|
||||
};
|
||||
let recipientId = payload.substring(2);
|
||||
let chan;
|
||||
if(payload[0]=='P') {
|
||||
chan = (this.userId<recipientId) ? 'userchans:'+this.userId+'|'+recipientId : 'userchans:'+recipientId+'|'+this.userId;
|
||||
} else if(payload[0]=='C') {
|
||||
chan = 'lobbies:'+recipientId;
|
||||
} else {
|
||||
this.sendErr(action, 'Bad chat destination', reqid);
|
||||
return;
|
||||
}
|
||||
// subscribe this connexion
|
||||
if(!(chan in this.rediscnx.subscriptions)) this.rediscnx.subscriptions[chan] = [];
|
||||
if(this.rediscnx.subscriptions[chan].indexOf(this.uuid)<0) {
|
||||
this.rediscnx.subscriptions[chan].push(this.uuid);
|
||||
if(this.debug) console.log('Subscribed to chat chan: ',chan);
|
||||
}
|
||||
// other connexion of this user might be on different chat, so don't subscribe them
|
||||
let reply = {
|
||||
'action': action,
|
||||
'payload': chan,
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
/* Send human-message in chat chan.
|
||||
Request:
|
||||
{
|
||||
"action": "SENDCHAT",
|
||||
"payload": "P" // or "C" => "P" = Peer-to-peer, "C" = (chat) Channel
|
||||
}
|
||||
reply:
|
||||
{
|
||||
"action": "SENDCHAT",
|
||||
"success": true,
|
||||
"payload" : null
|
||||
}
|
||||
*/
|
||||
action_SENDCHAT(action, payload, reqid){
|
||||
//TODO: prevent unauthorized recipient !!
|
||||
let recipientId = payload.recipient.substring(2);
|
||||
let chan;
|
||||
payload.event = 'CHATMSG'
|
||||
if(payload.recipient[0]=='P') {
|
||||
chan = (this.userId<recipientId) ? 'userchans:'+this.userId+'|'+recipientId : 'userchans:'+recipientId+'|'+this.userId;
|
||||
} else if(payload.recipient[0]=='C') {
|
||||
chan = 'lobbies:'+recipientId;
|
||||
} else {
|
||||
this.sendErr(action, 'Bad chat destination', reqid);
|
||||
return;
|
||||
}
|
||||
if(this.debug) console.log('Publishing to chat chan: ',chan, payload.msg);
|
||||
|
||||
//NIKE TODO: be coherent, 'sender' is app-level, therefore should be inside payload, not outside !!!
|
||||
// (see remark in Protocol description in FE MessageBus class)
|
||||
|
||||
this.rediscnx.redisPublish(chan, {
|
||||
'sender': this.userId,
|
||||
'msg' : payload.msg
|
||||
});
|
||||
let reply = {
|
||||
'action': action,
|
||||
'payload': null,
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
/* Send human-message in chat chan.
|
||||
Request:
|
||||
{
|
||||
"action": "ISONLINE",
|
||||
"payload": "P" // or "C" => "P" = Peer-to-peer, "C" = (chat) Channel
|
||||
}
|
||||
reply:
|
||||
{
|
||||
"action": "ISONLINE",
|
||||
"success": true,
|
||||
"payload" :
|
||||
}
|
||||
*/
|
||||
// You can only ask the satus of a list of usernames you know (and have the right to)
|
||||
action_ISONLINE(action, payload, reqid){
|
||||
//TODO: can you really ask about those users ? (but that might cost too much time, because => ML?)
|
||||
if(!Array.isArray(payload)){
|
||||
this.sendErr(action, 'Invalid payload', reqid);
|
||||
return;
|
||||
};
|
||||
let onlineUsers = Object.keys(this.wssSrv.getOnlineUsers());
|
||||
let reply = {
|
||||
'action': action,
|
||||
'payload': payload.filter((x) => (onlineUsers.indexOf(x)>-1)),
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
// Same as ISONLINE, but subscribe to watch changes
|
||||
action_WATCHUSERS(action, payload, reqid){
|
||||
if(!Array.isArray(payload)){
|
||||
this.sendErr(action, 'Invalid payload', reqid);
|
||||
return;
|
||||
}
|
||||
//TODO: can you really ask about those users ? (but that might cost too much time, because => ML?)
|
||||
this.usersWatched = payload;
|
||||
let reply = {
|
||||
'action': action,
|
||||
'payload': null,
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
/*
|
||||
Request:
|
||||
{
|
||||
"action": "CHANLST",
|
||||
"payload": { "filter": "ChatRoom*" }
|
||||
}
|
||||
reply:
|
||||
{
|
||||
"action": "CHANLST",
|
||||
"success": true,
|
||||
"payload" : ["ChatRoom1","ChatRoom2","ChatRoom_Experts"]
|
||||
}
|
||||
*/
|
||||
action_CHANLST(action, payload, reqid){
|
||||
//TODO : Filter based on user rights!!
|
||||
//
|
||||
let reply = {
|
||||
'action': action,
|
||||
'payload': [
|
||||
this.config.redis.basePrefix+"onlineUsers",
|
||||
this.config.redis.basePrefix+"system:chan1",
|
||||
this.config.redis.basePrefix+"proposals:updates"
|
||||
],//this.config.redis.watchChannels,
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
module.exports.methods = {}
|
||||
Object.assign(module.exports.methods, require('./utilities').methods )
|
||||
Object.assign(module.exports.methods, require('./pubSub').methods )
|
||||
Object.assign(module.exports.methods, require('./store').methods )
|
||||
Object.assign(module.exports.methods, require('./sessions').methods )
|
||||
Object.assign(module.exports.methods, require('./notifications').methods )
|
||||
Object.assign(module.exports.methods, require('./chat').methods )
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
module.exports.methods = {
|
||||
|
||||
async action_NOTIFS(action, payload, reqid){
|
||||
let reply = {
|
||||
'action': action,
|
||||
'payload': await this.getAwaitingNotifs(),
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
module.exports.methods = {
|
||||
/* Request:
|
||||
{
|
||||
"action": "SUB",
|
||||
"payload" : ["chan1","chan2","unauthorized"]
|
||||
}
|
||||
Reply: (returns all active subscriptions after this SUB)
|
||||
{
|
||||
"action": "SUB",
|
||||
"success": true,
|
||||
"payload" : ["chan1","chan2","wasalreadysubscribed"]
|
||||
}
|
||||
*/
|
||||
action_SUB(action, payload, reqid){
|
||||
if(!Array.isArray(payload)){
|
||||
this.sendErr(action, 'Invalid payload', reqid);
|
||||
return;
|
||||
};
|
||||
|
||||
for(var chan of payload){
|
||||
if((!chan) || (typeof(chan)!='string')) continue
|
||||
if(!this.accessRights.canSubscribe(this.userId, this.roles, chan)) continue
|
||||
// Chat chans are forbidden here
|
||||
if((chan.substr(0,8) == 'userchans') || (chan.substr(0,9) == 'lobbychans')) continue;
|
||||
|
||||
if(!chan.startsWith(this.config.redis.basePrefix)) chan = this.config.redis.basePrefix + chan
|
||||
if(this.subscriptions.indexOf(chan)<0) {
|
||||
this.subscriptions.push(chan);
|
||||
}
|
||||
if(!(chan in this.rediscnx.subscriptions)) this.rediscnx.subscriptions[chan] = [];
|
||||
if(this.rediscnx.subscriptions[chan].indexOf(this.uuid)<0) {
|
||||
this.rediscnx.subscriptions[chan].push(this.uuid);
|
||||
}
|
||||
}
|
||||
|
||||
let shortChans = this.subscriptions.map(item => (
|
||||
item.startsWith(this.config.redis.basePrefix) ? item.substr(this.config.redis.basePrefix.length) : item
|
||||
))
|
||||
|
||||
let reply = {
|
||||
'action': action,
|
||||
'payload': shortChans,
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
/*
|
||||
Request:
|
||||
{
|
||||
"action":"UNSUB",
|
||||
"payload" : ["chan1","notsubscribed_chan","mandatory_chan"]
|
||||
}
|
||||
reply:
|
||||
{
|
||||
"action":"UNSUB",
|
||||
"success": true,
|
||||
"payload" : ["chan1"]
|
||||
}
|
||||
*/
|
||||
action_UNSUB(action, payload, reqid){
|
||||
if(!Array.isArray(payload)){
|
||||
this.sendErr(action, 'Invalid payload', reqid);
|
||||
return;
|
||||
};
|
||||
|
||||
for(var chan of payload){
|
||||
if((!chan) || (typeof(chan)!='string')) continue
|
||||
if(this.accessRights.isMandatory(this.userId, this.roles, chan)) continue
|
||||
|
||||
// Chat chans are forbidden here
|
||||
if((chan.substr(0,8) == 'userchans') || (chan.substr(0,9) == 'lobbychans')) continue;
|
||||
|
||||
if(!chan.startsWith(this.config.redis.basePrefix)) chan = this.config.redis.basePrefix + chan
|
||||
if(this.subscriptions.indexOf(chan)>-1) {
|
||||
this.subscriptions.splice(this.subscriptions.indexOf(chan), 1);
|
||||
}
|
||||
if((chan in this.rediscnx.subscriptions) && (this.rediscnx.subscriptions[chan].indexOf(this.uuid)>-1)) {
|
||||
this.rediscnx.subscriptions[chan].splice(this.rediscnx.subscriptions[chan].indexOf(this.uuid), 1) ;
|
||||
}
|
||||
}
|
||||
|
||||
let shortChans = this.subscriptions.map(item => (
|
||||
item.startsWith(this.config.redis.basePrefix) ? item.substr(this.config.redis.basePrefix.length) : item
|
||||
))
|
||||
let reply = {
|
||||
'action': action,
|
||||
'payload': shortChans,
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
/*
|
||||
Request:
|
||||
{
|
||||
"action": "SUBLST",
|
||||
}
|
||||
reply:
|
||||
{
|
||||
"action": "SUBLST",
|
||||
"success": true,
|
||||
"payload" : ["chan1","chan2","mandatory_chan"]
|
||||
}
|
||||
*/
|
||||
action_SUBLST(action, payload, reqid){
|
||||
let shortChans = this.subscriptions.map(item => (
|
||||
item.startsWith(this.config.redis.basePrefix) ? item.substr(this.config.redis.basePrefix.length) : item
|
||||
))
|
||||
let reply = {
|
||||
'action': action,
|
||||
'payload': shortChans,
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
/*
|
||||
Request:
|
||||
{
|
||||
"action": "PUB",
|
||||
"payload" : { 'chan':'chan1', 'msg':'Hello folks !'}
|
||||
}
|
||||
reply:
|
||||
{
|
||||
"action": "PUB",
|
||||
"success": true,
|
||||
}
|
||||
*/
|
||||
async action_PUB(action, payload, reqid){
|
||||
if((typeof(payload)!='object') || (typeof(payload.chan)!='string') || (typeof(payload.msg)!='string')){
|
||||
this.sendErr(action, 'Invalid payload', reqid);
|
||||
if(this.debug) console.log('PUB: Invalid payload')
|
||||
return;
|
||||
};
|
||||
// Chat chans are forbidden here
|
||||
if((payload.chan.substr(0,8) == 'userchans') || (payload.chan.substr(0,9) == 'lobbychans')){
|
||||
this.sendErr(action, 'Forbidden chan', reqid);
|
||||
if(this.debug) console.log('PUB: Forbidden chan')
|
||||
return;
|
||||
};
|
||||
|
||||
if( (!this.accessRights.canPublish(this.userId, this.roles, payload.chan)) &&
|
||||
(! this.rediscnx.redPillsUuids.includes(this.uuid)) ) {
|
||||
this.sendErr(action, 'Unauthorized chan !', reqid);
|
||||
if(this.debug) console.log('PUB: Unauthorized chan', payload.chan)
|
||||
return
|
||||
}
|
||||
|
||||
let msgO
|
||||
try { msgO = JSON.parse(payload.msg) } catch(err) { msgO = {'err':err} }
|
||||
|
||||
let histId = null
|
||||
if(this.rediscnx.isHistorizedChan(payload.chan)) { // historize first to add the histId
|
||||
let shortChan = payload.chan.startsWith(this.config.redis.basePrefix) ? payload.chan.substr(this.config.redis.basePrefix.length) : payload.chan
|
||||
histId = await this.rediscnx.redisXadd(this.config.redis.basePrefix+this.config.redis.historizePrefix + shortChan, payload.msg, this.config.redis.historizeMax);
|
||||
if( !histId) {
|
||||
this.sendErr(action, 'Could not historize, aborted event publish !', reqid);
|
||||
console.error(`Could not historize for "${shortChan}", aborted event publish !`)
|
||||
return
|
||||
}
|
||||
msgO.histId = histId
|
||||
}
|
||||
|
||||
msgO.sender = this.userId
|
||||
try { payload.msg = JSON.stringify(msgO) } catch(err) {payload.msg = `{"err":"${err}}"` }
|
||||
this.rediscnx.redisPublish(payload.chan, payload.msg)
|
||||
|
||||
let reply = {
|
||||
'action': action,
|
||||
'payload': null,
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
/*
|
||||
Request:
|
||||
{
|
||||
"action": "CHANHIST",
|
||||
"payload": {
|
||||
"chan": "aze",
|
||||
"from": "123456879-0", //Histid or seconds since epoch
|
||||
"to": "987654321-1" // Optional
|
||||
}
|
||||
}
|
||||
reply:
|
||||
{
|
||||
"action": "CHANHIST",
|
||||
"success": true,
|
||||
"payload" : [
|
||||
"123456879-1": { payload },
|
||||
"123456885-0": { payload },
|
||||
"123456890-0": { payload }
|
||||
]
|
||||
}
|
||||
*/
|
||||
async action_CHANHIST(action, payload, reqid){
|
||||
if((!payload.channel) || (typeof(payload.channel)!='string') || (!payload.from) || (typeof(payload.from)!='string') || (payload.to && (typeof(payload.to)!='string'))){
|
||||
this.sendErr(action, 'Invalid payload', reqid)
|
||||
return
|
||||
}
|
||||
if( (!payload.from.match(/^(\d{13,})-(\d+)$/)) && (!payload.from.match(/^(\d{10,})$/)) ){
|
||||
this.sendErr(action, 'Invalid payload', reqid)
|
||||
return
|
||||
}
|
||||
if(payload.to && (!payload.to.match(/^(\d{13,})-(\d+)$/)) && (!payload.to.match(/^(\d{10,})$/)) ){
|
||||
this.sendErr(action, 'Invalid payload', reqid)
|
||||
return
|
||||
}
|
||||
|
||||
if( (!this.accessRights.canSubscribe(this.userId, this.roles, payload.channel)) &&
|
||||
(! this.rediscnx.redPillsUuids.includes(this.uuid)) ) {
|
||||
this.sendErr(action, 'Unauthorized channel !', reqid)
|
||||
return
|
||||
}
|
||||
|
||||
if(!this.rediscnx.isHistorizedChan(payload.channel)){
|
||||
this.sendErr(action, 'Not an historized channel !', reqid)
|
||||
return
|
||||
}
|
||||
|
||||
let from = (payload.from.indexOf('-')>-1) ? payload.from : 1000*payload.from
|
||||
let to = '+'
|
||||
if(payload.to) to = (payload.to.indexOf('-')>-1) ? payload.to : 1000*payload.to
|
||||
let streamName = payload.channel.startsWith(this.config.redis.basePrefix) ? this.config.redis.historizePrefix+payload.channel.substr(this.config.redis.basePrefix.length) : this.config.redis.historizePrefix + payload.channel
|
||||
let respPayload = await this.rediscnx.redisXrange(streamName, from, to);
|
||||
|
||||
let reply = {
|
||||
'action': action,
|
||||
'payload': respPayload,
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
module.exports.methods = {
|
||||
|
||||
/* Request payload : null
|
||||
Reply:
|
||||
{
|
||||
"action": "GETACTIVEUSERS",
|
||||
"payload": [
|
||||
{
|
||||
"uid": "steinic",
|
||||
"email": "Nicolas.STEIN@ext.ec.europa.eu",
|
||||
"given_name": "Nicolas",
|
||||
"family_name": "STEIN",
|
||||
"userRoles": [
|
||||
"BP_PO",
|
||||
"SP_Admin",
|
||||
"Org_Member",
|
||||
"Org_Pending",
|
||||
"EIC_Dev"
|
||||
],
|
||||
"sessionExpire": 3594,
|
||||
"busConnected": true
|
||||
}
|
||||
],
|
||||
"success": true,
|
||||
"reqid": "df58a401-4ed2-4908-a2b1-8bae155e413a"
|
||||
}
|
||||
*/
|
||||
async action_GETACTIVEUSERS(action, payload, reqid){
|
||||
if(!this.accessRights.canDo(this.roles, 'getActiveUsers')) {
|
||||
this.sendErr(action, 'Unauthorized action !', reqid);
|
||||
return
|
||||
}
|
||||
|
||||
//TODO: take from new config key instead of hardcded
|
||||
const iterOptions = {
|
||||
TYPE: 'string',
|
||||
MATCH: 'authorizer:sessid_*'
|
||||
}
|
||||
|
||||
let activeUsers = []
|
||||
for await (const key of this.rediscnx.redisClient.scanIterator(iterOptions)) {
|
||||
let sess = null
|
||||
try{ sess = JSON.parse(await this.rediscnx.redisGet(key, '')) }
|
||||
catch(err) { console.log('bad sess info')}
|
||||
if((!sess) || (!sess.isAuthenticated) || (!sess.sessionID)
|
||||
|| (!sess.userInfo) || (!sess.userInfo.userRoles) || (!sess.userInfo.euLoginId)){
|
||||
continue
|
||||
}
|
||||
|
||||
let ttl = await this.rediscnx.redisGetTtl(key, '')
|
||||
activeUsers.push({
|
||||
uid: sess.userInfo.euLoginId,
|
||||
email: sess.userInfo.email,
|
||||
given_name: sess.userInfo.given_name,
|
||||
family_name: sess.userInfo.family_name,
|
||||
userRoles: sess.userInfo.userRoles,
|
||||
sessionExpire: ttl,
|
||||
busConnected: this.wssSrv.sessionConnected(sess.sessionID),
|
||||
})
|
||||
}
|
||||
var reply = {
|
||||
'action': action,
|
||||
'payload': activeUsers,
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
/*
|
||||
* payload: {
|
||||
uids: [ 'fallimi' ],
|
||||
notRoles : ['EIC_ADMIN', 'EIC_Dev' ],
|
||||
ttl: 0
|
||||
}
|
||||
=> Both conditions must be met (here nothing gets done as fallimi is EIC_Dev)
|
||||
|
||||
Any uid, but not some roles :
|
||||
{
|
||||
uids: null,
|
||||
notRoles : ['EIC_ADMIN', 'EIC_Dev' ],
|
||||
ttl: 0
|
||||
}
|
||||
|
||||
Some uids, don't care their roles in 30 seconds :
|
||||
{
|
||||
uids: [ 'infosca', 'nz01234' ],
|
||||
notRoles : [],
|
||||
ttl: 30
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* Request payload : { "uid":"steinni" }
|
||||
Reply:
|
||||
{
|
||||
"action": "GETUSERSTATUS",
|
||||
"payload":
|
||||
{
|
||||
"uid": "steinic",
|
||||
"email": "Nicolas.STEIN@ext.ec.europa.eu",
|
||||
"given_name": "Nicolas",
|
||||
"family_name": "STEIN",
|
||||
"sessionExpire": 3594,
|
||||
"busConnected": true
|
||||
},
|
||||
"success": true,
|
||||
"reqid": "df58a401-4ed2-4908-a2b1-8bae155e413a"
|
||||
}
|
||||
*/
|
||||
async action_GETUSERSTATUS(action, payload, reqid){
|
||||
if(!this.accessRights.canDo(this.roles, 'getUserStatus')) {
|
||||
this.sendErr(action, 'Unauthorized action !', reqid);
|
||||
return
|
||||
}
|
||||
|
||||
const iterOptions = {
|
||||
TYPE: 'string',
|
||||
MATCH: 'authorizer:sessid_*'
|
||||
}
|
||||
|
||||
let user = {
|
||||
uid: payload.uid,
|
||||
email: null,
|
||||
given_name: null,
|
||||
family_name: null,
|
||||
sessionExpire: null,
|
||||
busConnected: null,
|
||||
}
|
||||
|
||||
for await (const key of this.rediscnx.redisClient.scanIterator(iterOptions)) {
|
||||
let sess = null
|
||||
try{ sess = JSON.parse(await this.rediscnx.redisGet(key, '')) }
|
||||
catch(err) { console.log('bad sess info')}
|
||||
|
||||
if((!sess) || (!sess.isAuthenticated) || (!sess.sessionID)
|
||||
|| (!sess.userInfo) || (!sess.userInfo.userRoles) || (!sess.userInfo.euLoginId)
|
||||
|| (sess.userInfo.euLoginId != payload.uid)
|
||||
) {
|
||||
continue
|
||||
} else {
|
||||
let ttl = await this.rediscnx.redisGetTtl(key, '')
|
||||
user={
|
||||
uid: sess.userInfo.euLoginId,
|
||||
email: sess.userInfo.email,
|
||||
given_name: sess.userInfo.given_name,
|
||||
family_name: sess.userInfo.family_name,
|
||||
sessionExpire: ttl,
|
||||
busConnected: this.wssSrv.sessionConnected(sess.sessionID),
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var reply = {
|
||||
'action': action,
|
||||
'payload': user,
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
async action_KILLSESSION(action, payload, reqid){
|
||||
if(!this.accessRights.canDo(this.roles, 'killSessions')) {
|
||||
this.sendErr(action, 'Unauthorized action !', reqid);
|
||||
return
|
||||
}
|
||||
if( (!payload.notRoles) || (!Array.isArray(payload.notRoles)) || (payload.uids && (!Array.isArray(payload.uids))) ){
|
||||
this.sendErr(action, 'Bad payload !', reqid);
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
//TODO: take from new config key instead of hardcded
|
||||
const iterOptions = {
|
||||
TYPE: 'string',
|
||||
MATCH: 'authorizer:sessid_*'
|
||||
}
|
||||
|
||||
for await (const key of this.rediscnx.redisClient.scanIterator(iterOptions)) {
|
||||
if(key.endsWith('_cookie')) continue
|
||||
let sess = null
|
||||
try{ sess = JSON.parse(await this.rediscnx.redisGet(key, '')) }
|
||||
catch(err) { console.log('bad sess info')}
|
||||
if((!sess) || (!sess.isAuthenticated)) continue
|
||||
|
||||
if(payload.uids && (payload.uids.indexOf(sess.userInfo['euLoginId'])<0)) continue
|
||||
let intersect = payload.notRoles.filter(value => sess.userInfo.userRoles.includes(value));
|
||||
if(intersect.length>0) continue
|
||||
|
||||
if((!payload.ttl) || (typeof(payload.ttl)!= number) || (payload.ttl<0) || (payload.ttl>3600)) payload.ttl=0
|
||||
let ttl = await this.rediscnx.redisSetTtl(key, payload.ttl, '')
|
||||
|
||||
}
|
||||
var reply = {
|
||||
'action': action,
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
/* Request: (curtain down, except for devs & admins)
|
||||
{
|
||||
"action": "SETSPARCSTATE",
|
||||
"payload" : {
|
||||
blockedUids: [],
|
||||
allowedRoles : ['EIC_Admin', 'EIC_Dev'],
|
||||
},
|
||||
}
|
||||
|
||||
Request: (curtain up, for everyone)
|
||||
{
|
||||
"action": "SETSPARCSTATE",
|
||||
"payload" : {
|
||||
blockedUids: [],
|
||||
allowedRoles : '*',
|
||||
},
|
||||
}
|
||||
|
||||
Request: (curtain up, block some bad-guys)
|
||||
{
|
||||
"action": "SETSPARCSTATE",
|
||||
"payload" : {
|
||||
blockedUids: ['hacker1', 'hacker2'],
|
||||
allowedRoles : '*',
|
||||
},
|
||||
}
|
||||
|
||||
Reply:
|
||||
{
|
||||
"success": true,
|
||||
"reqid": "6az5e4r6a",
|
||||
"payload": { the accessrights }
|
||||
}
|
||||
*/
|
||||
async action_SETPLATFORMMODE(action, payload, reqid){
|
||||
if(!this.accessRights.canDo(this.roles, 'setPlatformState')) {
|
||||
this.sendErr(action, 'Unauthorized action !', reqid);
|
||||
return
|
||||
}
|
||||
if((typeof(payload)!='object') || (!Array.isArray(payload.blockedUUIDs)) ||
|
||||
( (typeof(payload.platformRestrictions)=='object') && (!Array.isArray(payload.platformRestrictions.allowedRoles)) )
|
||||
){
|
||||
this.sendErr(action, 'Invalid payload', reqid)
|
||||
return
|
||||
}
|
||||
|
||||
if(typeof(payload.platformRestrictions)=='object'){ // curtain down
|
||||
if(!payload.platformRestrictions.allowedRoles.includes('EIC_Dev')){ // anti-shoot-your-foot
|
||||
payload.platformRestrictions.allowedRoles.push('EIC_Dev')
|
||||
}
|
||||
} else { // curtain up
|
||||
//force-in an example
|
||||
payload.XX_platformRestrictions = { "allowedRoles":["EIC_Admin","EIC_Dev"],"allowedUUIDs":["valentin"] }
|
||||
}
|
||||
|
||||
|
||||
|
||||
await this.rediscnx.redisSet(this.config.redis.platformStateKey,
|
||||
payload,
|
||||
0,
|
||||
''
|
||||
)
|
||||
|
||||
var reply = {
|
||||
'action': action,
|
||||
'success': true
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
|
||||
/* Request:
|
||||
{
|
||||
"action": "GETSPARCMODE"
|
||||
"payload": {
|
||||
"key": "keyname"
|
||||
}
|
||||
"reqid": "6az5e4r6a"
|
||||
}
|
||||
Reply:
|
||||
{
|
||||
"action":"STORE",
|
||||
"success":true,
|
||||
"payload": {
|
||||
...the sparc mode
|
||||
}
|
||||
"reqid": reqid
|
||||
}
|
||||
*/
|
||||
async action_GETPLATFORMMODE(action, payload, reqid){
|
||||
if(!this.accessRights.canDo(this.roles, 'getPlatformState')) {
|
||||
this.sendErr(action, 'Unauthorized action !', reqid);
|
||||
return
|
||||
}
|
||||
|
||||
let rawVal = await this.rediscnx.redisGet(this.config.redis.platformStateKey, '')
|
||||
let val = null
|
||||
try { val = JSON.parse(rawVal)}
|
||||
catch(err) { console.error('Action GETSPARCMODE: Not a json !? ', rawVal) }
|
||||
|
||||
var reply = {
|
||||
'action': action,
|
||||
'payload': val,
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
module.exports.methods = {
|
||||
|
||||
/* Request:
|
||||
{
|
||||
"action": "SET"
|
||||
"payload": {
|
||||
"key": "keyname",
|
||||
"value": "stringifiedvalue", // If null : deletes the key
|
||||
"expire": 60 // if present & non zero, expires the key in x seconds.
|
||||
// if absent or zero, we force a TTL of 2 years = 63072000 sec.
|
||||
"observe": true // if true: make it an observable key & subscribe to it
|
||||
}
|
||||
"reqid": "6az5e4r6a"
|
||||
}
|
||||
Reply:
|
||||
{
|
||||
"action":"SET",
|
||||
"success":true,
|
||||
"reqid": reqid
|
||||
}
|
||||
*/
|
||||
async action_SET(action, payload, reqid){
|
||||
//TODO : observable...
|
||||
if((typeof(payload)!='object') || (typeof(payload.key)!='string') ||
|
||||
((typeof(payload.value)!='object') && (payload.value!==null)) ||
|
||||
(payload.expire && (typeof(payload.expire)!='number')) ||
|
||||
(payload.observe && (typeof(payload.observe)!='boolean'))
|
||||
){
|
||||
this.sendErr(action, 'Invalid payload', reqid)
|
||||
return
|
||||
}
|
||||
|
||||
if(!this.accessRights.canSet(this.userId, this.roles, payload.key)){
|
||||
this.sendErr(action, 'Unauthorized key !', reqid);
|
||||
return
|
||||
}
|
||||
|
||||
if(payload.value) {
|
||||
let val = null
|
||||
try { val = JSON.stringify(payload.value)}
|
||||
catch(err) {
|
||||
this.sendErr(action, 'Cannot stringify value object !', reqid);
|
||||
return
|
||||
}
|
||||
if(val.length > this.config.redis.storeMaxSize){
|
||||
this.sendErr(action, 'value too large !', reqid);
|
||||
return
|
||||
}
|
||||
let exp = ((payload.expire>0) && (payload.expire<63072000)) ? payload.expire : 63072000
|
||||
await this.rediscnx.redisSet(payload.key, val, exp, this.config.redis.storePrefix)
|
||||
} else {
|
||||
await this.rediscnx.redisDel(payload.key, this.config.redis.storePrefix)
|
||||
}
|
||||
var reply = {
|
||||
'action': action,
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
/* Request:
|
||||
{
|
||||
"action": "GET"
|
||||
"payload": {
|
||||
"key": "keyname"
|
||||
}
|
||||
"reqid": "6az5e4r6a"
|
||||
}
|
||||
Reply:
|
||||
{
|
||||
"action":"GET",
|
||||
"success":true,
|
||||
"payload": {
|
||||
"key" : key,
|
||||
"value": value
|
||||
}
|
||||
"reqid": reqid
|
||||
}
|
||||
*/
|
||||
async action_GET(action, payload, reqid){
|
||||
//TODO : observable...
|
||||
if((typeof(payload)!='object') || (typeof(payload.key)!='string')){
|
||||
this.sendErr(action, 'Invalid payload', reqid);
|
||||
return;
|
||||
};
|
||||
|
||||
if(!this.accessRights.canGet(this.userId, this.roles, payload.key)) {
|
||||
this.sendErr(action, 'Unauthorized key !', reqid);
|
||||
return
|
||||
}
|
||||
|
||||
let rawVal = await this.rediscnx.redisGet(payload.key, this.config.redis.storePrefix)
|
||||
let val = null
|
||||
try { val = JSON.parse(rawVal)}
|
||||
catch(err) { console.error('Action GET: Not a json !? ', rawVal) }
|
||||
var reply = {
|
||||
'action': action,
|
||||
'payload': {
|
||||
'key': payload.key,
|
||||
'value': val
|
||||
},
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
module.exports.methods = {
|
||||
|
||||
/* Request:
|
||||
{
|
||||
"action": "PING"
|
||||
}
|
||||
Reply:
|
||||
{
|
||||
"action": "PONG",
|
||||
}
|
||||
*/
|
||||
action_PONG(action, payload){
|
||||
clearTimeout(this.keepAliveBomb);
|
||||
this.keepAliveNextTimeout = setTimeout(this.keepAlive.bind(this),this.config.server.keepAliveInterval*1000);
|
||||
},
|
||||
|
||||
|
||||
/* Request:
|
||||
{
|
||||
"action": "TIME"
|
||||
"reqid": "6az5e4r6a"
|
||||
}
|
||||
Reply:
|
||||
{
|
||||
"action": "TIME",
|
||||
"success": true,
|
||||
"payload" : {
|
||||
wssGatewayTime: "2022-09-01T14:42:22.603Z",
|
||||
redisTime: "2022-09-01T14:42:22.603Z"
|
||||
},
|
||||
"reqid": "6az5e4r6a"
|
||||
}
|
||||
*/
|
||||
action_TIME(action, payload, reqid){
|
||||
var tmstp =new Date().toISOString();
|
||||
var reply = {
|
||||
'action': action,
|
||||
'payload': {
|
||||
wssGatewayTime: tmstp,
|
||||
redisTime: this.rediscnx.redisClient.time()
|
||||
},
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
|
||||
/* Request:
|
||||
{
|
||||
"action": "RELOADACCESSRIGHTS"
|
||||
}
|
||||
Reply:
|
||||
{
|
||||
"success": true,
|
||||
"reqid": "6az5e4r6a"
|
||||
}
|
||||
*/
|
||||
action_RELOADACCESSRIGHTS(action, payload, reqid){
|
||||
if(!this.accessRights.canDo(this.roles, 'reloadAccessRights')) {
|
||||
this.sendErr(action, 'Unauthorized action !', reqid);
|
||||
return
|
||||
}
|
||||
this.wssSrv.reloadAccessRights()
|
||||
var reply = {
|
||||
'action': action,
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
/* Request:
|
||||
{
|
||||
"action": "GETACCESSRIGHTS"
|
||||
}
|
||||
Reply:
|
||||
{
|
||||
"success": true,
|
||||
"reqid": "6az5e4r6a",
|
||||
"payload": { the accessrights }
|
||||
}
|
||||
|
||||
Kept for backward compatibility : GETCONFIG gets everything !
|
||||
*/
|
||||
action_GETACCESSRIGHTS(action, payload, reqid){
|
||||
if(!this.accessRights.canDo(this.roles, 'reloadAccessRights')) {
|
||||
this.sendErr(action, 'Unauthorized action !', reqid);
|
||||
return
|
||||
}
|
||||
|
||||
var reply = {
|
||||
'action': action,
|
||||
'success': true,
|
||||
'payload': this.wssSrv.wssGatewayConfig.accessRights
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
/* Request:
|
||||
{
|
||||
"action": "GETCONFIG"
|
||||
}
|
||||
Reply:
|
||||
{
|
||||
"success": true,
|
||||
"reqid": "6az5e4r6a",
|
||||
"payload": { the config }
|
||||
}
|
||||
*/
|
||||
action_GETCONFIG(action, payload, reqid){
|
||||
if(!this.accessRights.canDo(this.roles, 'reloadAccessRights')) {
|
||||
this.sendErr(action, 'Unauthorized action !', reqid);
|
||||
return
|
||||
}
|
||||
|
||||
var reply = {
|
||||
'action': action,
|
||||
'success': true,
|
||||
'payload': this.wssSrv.wssGatewayConfig
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
|
||||
/* Request:
|
||||
{
|
||||
"action": "GETPROCESSINFO"
|
||||
}
|
||||
Reply:
|
||||
{
|
||||
"success": true,
|
||||
"reqid": "6az5e4r6a",
|
||||
"payload": { the result of redis INFO command }
|
||||
}
|
||||
*/
|
||||
action_GETPROCESSINFO(action, payload, reqid){
|
||||
if(!this.accessRights.canDo(this.roles, 'getProcessInfo')) {
|
||||
this.sendErr(action, 'Unauthorized action !', reqid);
|
||||
return
|
||||
}
|
||||
|
||||
var reply = {
|
||||
'action': action,
|
||||
'success': true,
|
||||
'payload': this.rediscnx.getProcessInfo
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
action_REDPILL(action, payload, reqid){
|
||||
if(!this.accessRights.canDo(this.roles, 'REDPILL', this.userId)) {
|
||||
this.sendErr(action, 'Unauthorized action', reqid);
|
||||
return;
|
||||
};
|
||||
|
||||
if(!this.rediscnx.redPillsUuids.includes(this.uuid)) {
|
||||
this.rediscnx.redPillsUuids.push(this.uuid)
|
||||
setTimeout(() => {
|
||||
if(this.rediscnx.redPillsUuids.includes(this.uuid)){ // could have been removed meanwhile & splice(-1) would remove the last !!!
|
||||
this.rediscnx.redPillsUuids.splice(this.rediscnx.redPillsUuids.indexOf(this.uuid),1)
|
||||
}
|
||||
let reply = {
|
||||
'action': 'BLUEPILL',
|
||||
'payload': {},
|
||||
'success': true,
|
||||
};
|
||||
this.send(JSON.stringify(reply));
|
||||
}, 600000) // Back to blupill after 10min
|
||||
}
|
||||
|
||||
let reply = {
|
||||
'action': action,
|
||||
'payload': {},
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
action_BLUEPILL(action, payload, reqid){
|
||||
if(!this.accessRights.canDo(this.roles, 'BLUEPILL', this.userId)) {
|
||||
this.sendErr(action, 'Unauthorized action', reqid);
|
||||
return;
|
||||
};
|
||||
|
||||
if(this.rediscnx.redPillsUuids.includes(this.uuid)) {
|
||||
this.rediscnx.redPillsUuids.splice(this.rediscnx.redPillsUuids.indexOf(this.uuid),1)
|
||||
}
|
||||
|
||||
let reply = {
|
||||
'action': action,
|
||||
'payload': {},
|
||||
'success': true,
|
||||
};
|
||||
if(reqid) reply.reqid = reqid;
|
||||
this.send(JSON.stringify(reply));
|
||||
},
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user