From 046b4d2b01b00797711b4a9e45babf34d756e9fd Mon Sep 17 00:00:00 2001 From: hippoz Date: Mon, 16 Nov 2020 21:16:25 +0200 Subject: [PATCH] add basic gateway connection functionality --- api/v1/content.js | 15 ++++-- api/v1/gateway/index.js | 69 +++++++++++++++++++++++++ api/v1/users.js | 3 +- apitest.rest | 16 +++--- app/app.html | 1 + app/resources/js/app.js | 49 +++++++++++++++++- config.js | 3 +- index.js | 7 ++- package-lock.json | 111 ++++++++++++++++++++++++++++++++++++++++ package.json | 3 +- 10 files changed, 261 insertions(+), 16 deletions(-) create mode 100644 api/v1/gateway/index.js diff --git a/api/v1/content.js b/api/v1/content.js index 6fbae23..f4326a5 100755 --- a/api/v1/content.js +++ b/api/v1/content.js @@ -43,7 +43,8 @@ app.post('/category/create', [ category: { title: category.title, creator: category.creator, - posts: category.posts + posts: category.posts, + _id: category._id } }); }, undefined, config.roleMap.USER)); @@ -86,7 +87,10 @@ app.post('/post/create', [ res.status(200).json({ error: false, - message: 'SUCCESS_POST_CREATED' + message: 'SUCCESS_POST_CREATED', + post: { + _id: post._id + } }); }, undefined, config.roleMap.USER)); @@ -101,6 +105,9 @@ app.get('/category/:category/info', [ const categoryId = req.params.category; const category = await Category.findById(categoryId).populate('posts.creator', 'username _id'); + + // TODO: Implement subscribing to a channel and stuff + const users = await User.find().sort({ _id: -1 }).limit(50).select('username _id') if (!category) { res.status(404).json({ @@ -116,7 +123,9 @@ app.get('/category/:category/info', [ category: { title: category.title, creator: category.creator, - posts: category.posts + posts: category.posts, + users: users, + usersListLimit: 50 } }); })); diff --git a/api/v1/gateway/index.js b/api/v1/gateway/index.js new file mode 100644 index 0000000..d4c504f --- /dev/null +++ b/api/v1/gateway/index.js @@ -0,0 +1,69 @@ +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) { + socket.isConnected = false; + socket.disconnect(true); + callback(new Error('ERR_GATEWAY_AUTH_FAIL')); +}; + +GatewayServer.prototype.eventSetup = function() { + this._gateway.use((socket, callback) => { + console.log('[*] [gateway] User authentication attempt'); + socket.isConnected = false; + + setTimeout(() => { + console.log('[*] [gateway] User still not connected after timeout, removing...'); + 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] User ${data.username} has successfully authenticated`); + return callback(); + }); + }); + + this._gateway.on('connection', (socket) => { + console.log(`[*] [gateway] User ${socket.username} connected, sending hello and waiting for yoo...`); + socket.emit('hello'); + socket.once('yoo', () => { + console.log(`[*] [gateway] Got yoo from ${socket.username}, connection is finally completed!`); + socket.isConnected = true; + }); + }); +}; + +module.exports = GatewayServer; \ No newline at end of file diff --git a/api/v1/users.js b/api/v1/users.js index 665d231..1589781 100755 --- a/api/v1/users.js +++ b/api/v1/users.js @@ -148,7 +148,8 @@ app.get('/current/info', authenticateEndpoint((req, res, user) => { username: user.username, email: user.email, role: user.role, - permissionLevel: config.roleMap[user.role] + permissionLevel: config.roleMap[user.role], + token: req.cookies.token // TODO: Passing the token like this is *terribly* insecure }, }); }, undefined, 0)); diff --git a/apitest.rest b/apitest.rest index a7f6798..9cc7424 100755 --- a/apitest.rest +++ b/apitest.rest @@ -20,34 +20,34 @@ Content-Type: application/json ### GET http://localhost:3000/api/v1/users/current/info -Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJpYXQiOjE2MDA1MTA2MTEsImV4cCI6MTYwMDUyMTQxMX0.q85p94FLPR4fxZ4O5pmalEEjU9Hyr9js63u6LgoCQCw +Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJpYXQiOjE2MDU0ODI5NjgsImV4cCI6MTYwNTQ5Mzc2OH0.BjZEnI1v7XCYpEqyBub7uFrTtfQUZ7_PukP4sgcEzB0.eyJ1c2VybmFtZSI6InRlc3QiLCJpYXQiOjE2MDA1MTA2MTEsImV4cCI6MTYwMDUyMTQxMX0.q85p94FLPR4fxZ4O5pmalEEjU9Hyr9js63u6LgoCQCw ### POST http://localhost:3000/api/v1/content/category/create -Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJpYXQiOjE2MDA1MTA2MTEsImV4cCI6MTYwMDUyMTQxMX0.q85p94FLPR4fxZ4O5pmalEEjU9Hyr9js63u6LgoCQCw +Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJpYXQiOjE2MDU0ODI5NjgsImV4cCI6MTYwNTQ5Mzc2OH0.BjZEnI1v7XCYpEqyBub7uFrTtfQUZ7_PukP4sgcEzB0 Content-Type: application/json { - "name": "testing1" + "title": "testing1" } ### POST http://localhost:3000/api/v1/content/post/create -Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJpYXQiOjE2MDA1MTA2MTEsImV4cCI6MTYwMDUyMTQxMX0.q85p94FLPR4fxZ4O5pmalEEjU9Hyr9js63u6LgoCQCw +Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJpYXQiOjE2MDU0ODI5NjgsImV4cCI6MTYwNTQ5Mzc2OH0.BjZEnI1v7XCYpEqyBub7uFrTtfQUZ7_PukP4sgcEzB0 Content-Type: application/json { - "category": "5f65e1f05c3cdd86400f43ec", + "category": "5fb1ba3eb04f2b3356aa2e58", "title": "Test title", - "content": "Test content!!!" + "body": "Test content!!!" } ### -GET http://localhost:3000/api/v1/content/category/5f65e1f05c3cdd86400f43ec/info -Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJpYXQiOjE2MDA1MTA2MTEsImV4cCI6MTYwMDUyMTQxMX0.q85p94FLPR4fxZ4O5pmalEEjU9Hyr9js63u6LgoCQCw +GET http://localhost:3000/api/v1/content/category/5fb1ba3eb04f2b3356aa2e58/info +Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJpYXQiOjE2MDU0ODI5NjgsImV4cCI6MTYwNTQ5Mzc2OH0.BjZEnI1v7XCYpEqyBub7uFrTtfQUZ7_PukP4sgcEzB0 Content-Type: application/json ### diff --git a/app/app.html b/app/app.html index 78998a6..121f5eb 100755 --- a/app/app.html +++ b/app/app.html @@ -11,6 +11,7 @@ +