const User = require('../../../models/User'); const secret = require('../../../secret'); const config = require('../../../config'); const jwt = require('jsonwebtoken'); const siolib = require('socket.io') class GatewayServer { constructor(httpServer) { this._io = siolib(httpServer); this._gateway = this._io.of('/gateway'); this.eventSetup(); } } GatewayServer.prototype.authDisconnect = function(socket, callback) { console.log('[E] [gateway] [handshake] User disconnected due to failed authentication'); socket.isConnected = false; socket.disconnect(); socket.disconnect(true); callback(new Error('ERR_GATEWAY_AUTH_FAIL')); }; GatewayServer.prototype.eventSetup = function() { this._gateway.use((socket, callback) => { console.log('[*] [gateway] [handshake] User authentication attempt'); socket.isConnected = false; setTimeout(() => { if (socket.isConnected) return; console.log('[*] [gateway] [handshake] User still not connected after timeout, removing...'); socket.disconnect(); socket.disconnect(true); }, config.gatewayStillNotConnectedTimeoutMS); // TODO: Maybe passing the token in the query is not the best idea? const token = socket.handshake.query.token; if (!token) return this.authDisconnect(socket, callback); jwt.verify(token, secret.jwtPrivateKey, {}, async (err, data) => { if (err) return this.authDisconnect(socket, callback); if (!data) return this.authDisconnect(socket, callback); if (!data.username) return this.authDisconnect(socket, callback); const user = await User.findByUsername(data.username); if (!user) return this.authDisconnect(socket, callback); let permissionLevel = config.roleMap[user.role]; if (!permissionLevel) { permissionLevel = 0; } if (permissionLevel < config.roleMap.USER) return this.authDisconnect(socket, callback); socket.username = data.username; console.log(`[*] [gateway] [handshake] User ${data.username} has successfully authenticated`); return callback(); }); }); this._gateway.on('connection', (socket) => { console.log(`[*] [gateway] [handshake] User ${socket.username} connected, sending hello and waiting for yoo...`); socket.emit('hello'); socket.once('yoo', () => { console.log(`[*] [gateway] [handshake] Got yoo from ${socket.username}, connection is finally completed!`); socket.isConnected = true; socket.on('message', ({ categoryId, content }) => { // TODO: URGENT: Check if the category exists and if the user has access to it (access coming soon) socket.to(categoryId).emit('message', { username: socket.username, categoryId: categoryId, content: content }); }); socket.on('subscribe', (categories) => { for (let v of categories) { // TODO: URGENT: Check if the category exists and if the user has access to it (access coming soon) socket.join(v); } }); }); }); }; module.exports = GatewayServer;