all files / cloudsim-grant/ sockets.js

20.45% Statements 18/88
10% Branches 2/20
11.11% Functions 2/18
20.45% Lines 18/88
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157                                                                                                                                                                                                                                                                                     
'use strict';
 
const csgrant = require('./index')
 
const util = require('util');
 
exports.showLog = false
const log = exports.showLog? console.log: ()=>{}
 
// returns true if any of users is in identities
function AnyOfUsersInIdentities(users, identities){
  var intersection = identities.filter(function(n) {
    // true if users has this identity
    return users.indexOf(n) > -1
  })
  // if this array is not empty, we have at least
  // one of the users in the identities list
  return intersection.length > 0
}
 
// Fast lookup of sockets per user.
function SocketDict() {
  // keep a list of active sockets
  this.sockets = []
  // a reference to the socket.io library
  this.io = null;
 
  // add new socket
  this._addSocket = function (socket) {
    // is socket already in the list?
    const index = this.sockets.indexOf(socket)
    if (index > -1)
      return
    // new socket
    this.sockets.push(socket)
    log('add socket: ', this.sockets.length , 'identities:', socket.identities)
  }
 
  // remove socket
  this._removeSocket = function (socket) {
    // is socket already in the list?
    const index = this.sockets.indexOf(socket)
    if (index > -1) {
      // remove
      log('remove socket: ', index)
      this.sockets.splice(index,1)
      return
    }
  }
  // Notifies a list of users, if they are in any socket
  this.notifyUsers = function (users, channel, data) {
    log('\nnotify users:', users, channel, data)
    log('  -# sockets:', this.sockets.length)
    for (let socket of this.sockets) {
      log('  -socket identities:', socket.identities)
      if (AnyOfUsersInIdentities(users, socket.identities)) {
        log('  --notifying', socket.identities)
        csgrant.verifyToken(socket.token, function(err) {
          if (err) {
            console.error('Error verifying token: ' + err )
            return
          }
          log('  --emit channel:', channel, 'data:', data)
          socket.emit(channel, data)
        })
      }
    }
    log('end notify\n')
  }
 
  // Notify everybody....
  this.notifyAll = function (channel, msg) {
    this.io.sockets.emit(channel, msg);
  }
}
 
// Initialise the socket.io library
// server:
exports.init = function(server, events) {
  Eif (!server) {
    log('No server available, socket connections will not be established')
    return
  }
  const io = require('socket.io')(server)
  userSockets.io = io
  log('Init sockets')
  // authorization middleware
  io.use(function(socket, next) {
    const handshakeData = socket.request
    const token = handshakeData._query['token']
    if(!token) {
      const error = 'missing token in the socket'
      console.log(error)
      socket.emit('unauthorized', error, function() {
        socket.disconnect('unauthorized')
        return
      })
    }
    socket.token = token
    csgrant.verifyToken(socket.token, function(err, decoded) {
      // function to call when unauthorized
      var unauthorizedAccess = function(error) {
        console.error('unauthorizedAccess:', error)
        socket.emit('unauthorized', error, function() {
          socket.disconnect('unauthorized');
        });
      }
      // verify the token
      let error
      if (err) {
        console.error('Error: ' + err.message);
        error = {"message": "unauthorized"};
        unauthorizedAccess(error);
        return;
      }
      log(util.inspect(decoded))
      if (!decoded.identities || decoded.identities.length == 0) {
        console.error('Invalid token. No identities provided')
        error = {"message": "no identities provided"}
        unauthorizedAccess(error)
        return
      }
      socket.identities = decoded.identities
      next()
    })
  })
 
  events.on('resource', function(resource, operation, users) {
    const data = {resource: resource, operation: operation}
    // notify the users on sockets with appropriate identities
    userSockets.notifyUsers(users, 'resource', data)
  })
 
  io.on('connection', function (socket) {
    log(' socket connection: ' + socket.identities[0])
    userSockets._addSocket(socket)
 
    socket.on('disconnect', function() {
      log(' socket disconnect: ' + socket.identities[0])
      userSockets._removeSocket(socket)
    })
 
  })
  // allow others to send/receive messages
  return io
}
 
// global variable for list of sockets
const userSockets = new SocketDict()
 
// global function to access sockets
exports.getUserSockets = function () {
  return userSockets
}