From 59305f2fc926b265a41dc956080704b1b83fb5dc Mon Sep 17 00:00:00 2001 From: AdamSBlack Date: Sun, 31 Oct 2021 01:53:42 +0100 Subject: [PATCH] unique tagging of athena requests --- Anetha/index.js | 182 +++++++++++---------------- models/athena_returned_data.model.js | 14 ++- models/index.model.js | 3 +- package.json | 2 + routes/api/realtime.js | 19 ++- 5 files changed, 103 insertions(+), 117 deletions(-) diff --git a/Anetha/index.js b/Anetha/index.js index 5e50852..0c4c0e9 100644 --- a/Anetha/index.js +++ b/Anetha/index.js @@ -8,16 +8,19 @@ const authenticationController = require('./../controllers/authentication'); const deviceController = require('./../controllers/devices'); const { ws } = require('../routes/api/realtime'); -let wss; +var abnf = require('abnf'); + +let wss; async function __server() { - wss = new WebSocket.WebSocketServer({ path: '/ws/v2/', port: 4040, handshakeTimeout: 500}); - + wss = new WebSocket.WebSocketServer({ path: '/ws/v2/', port: 4040, handshakeTimeout: 500 }); + console.log("src") const interval = setInterval(function ping() { wss.clients.forEach(function each(ws) { if (ws.isAlive === false) { - _actionLogger(null, null, "ATHENA_DEVICE_TIMEOUT_FORCE_DISCONNECT", null, ws._socket.remoteAddress, null, ws.dongleId); + wss.retropilotFunc.actionLogger(null, null, "ATHENA_DEVICE_TIMEOUT_FORCE_DISCONNECT", null, ws._socket.remoteAddress, null, ws.dongleId); + console.log("TERMINATED", ws.dongleId) return ws.terminate(); } @@ -26,166 +29,123 @@ async function __server() { }); }, 5000); - wss.on('connection', manageConnection) + wss.on('connection', manageConnection) wss.on('close', function close() { clearInterval(interval); }); - } - - -const authenticateDongle = async (ws, res, cookies) => { - unsafeJwt = jsonwebtoken.decode(cookies.jwt); - const device = await deviceController.getDeviceFromDongle(unsafeJwt.identity) - - let verifiedJWT; - - try { - verifiedJWT = jsonwebtoken.verify(cookies.jwt, device.public_key, {ignoreNotBefore: true}); - } catch (err) { - _actionLogger(null, null, "ATHENA_DEVICE_AUTHENTICATE_INVALID", null, ws._socket.remoteAddress, JSON.stringify({jwt: cookies.jwt}), null); - return false; - } - - - if (verifiedJWT.identify === unsafeJwt.identify) { - - ws.dongleId = device.dongle_id - ws.device_id = device.id - console.log("AUTHENTICATED DONGLE", ws.dongleId ) - - _actionLogger(null, device.id, "ATHENA_DEVICE_AUTHENTICATE_SUCCESS", null, ws._socket.remoteAddress, null); - return true; - } else { - console.log("UNAUTHENTICATED DONGLE"); - - _actionLogger(null, device.id, "ATHENA_DEVICE_AUTHENTICATE_FAILURE", null, ws._socket.remoteAddress, JSON.stringify({jwt: cookies.jwt}), null); - return false; - } -} - - -function commandBuilder(method, params) { - return { method, params, "jsonrpc": "2.0", "id": 0 } -} - - async function heartbeat() { - if (this.heartbeat - Date.now() > 300) { deviceController.updateLastPing(this.device_id, this.dongleId); } this.isAlive = true; this.heartbeat = Date.now(); - } -async function _actionLogger(account_id, device_id, action, user_ip, device_ip, meta, dongle_id) { - models.models.athena_action_log.create({ - account_id, device_id, action, user_ip, device_ip, meta, created_at: Date.now(), dongle_id - }) -} - -async function manageConnection(ws, res) { +async function manageConnection(ws, res) { ws.badMessages = 0; ws.isAlive = true; - ws.heartbeat = Date.now(); - ws.on('pong', heartbeat); var cookies = cookie.parse(res.headers.cookie); - - - ws.on('message', function incoming(message) { + ws.on('message', async function incoming(message) { heartbeat.call(ws) - if (!ws.dongleId) { - _actionLogger(null, null, "ATHENA_DEVICE_UNATHENTICATED_MESSAGE", null, ws._socket.remoteAddress, JSON.stringify([message]), ws.dongleId); - console.log("unauthenticated message, discarded"); - return null; + if (!ws.dongleId) { + // wss.retropilotFunc.actionLogger(null, null, "ATHENA_DEVICE_UNATHENTICATED_MESSAGE", null, ws._socket.remoteAddress, JSON.stringify([message]), ws.dongleId); + console.log("unauthenticated message, discarded"); + return null; } + console.log(message); + const json = JSON.parse(message.toString('utf8')) + console.log(json); - models.models.athena_returned_data.create({ - device_id: ws.device_id, - type: "UNKNOWN", - data: JSON.stringify(message), - created_at: Date.now() + console.log({device_id: ws.device_id, uuid: json.id}); - }) + console.log( await models.models.athena_returned_data.update({ + data: JSON.stringify(json), + resolved_at: Date.now() + }, {where: {device_id: ws.device_id, uuid: json.id}})) - _actionLogger(null, null, "ATHENA_DEVICE_MESSAGE_UNKNOWN", null, ws._socket.remoteAddress, JSON.stringify([message]), ws.dongleId); - const buff = Buffer.from(JSON.stringify(message), 'utf-8'); + + wss.retropilotFunc.actionLogger(null, null, "ATHENA_DEVICE_MESSAGE_UNKNOWN", null, ws._socket.remoteAddress, JSON.stringify([message]), ws.dongleId); + + console.log(json) -// decode buffer as UTF-8 - console.log(buff.toString('base64')) }); - - if (await authenticateDongle(ws, res, cookies) === false) { + + if (await wss.retropilotFunc.authenticateDongle(ws, res, cookies) === false) { ws.close(); } //ws.send(JSON.stringify(await commandBuilder('reboot'))) - } + __server(); +wss.retropilotFunc = { + findFromDongle: (dongleId) => { + let websocket = null; + wss.clients.forEach((value) => { + if (value.dongleId === dongleId) { + websocket = value; + } + }) + return websocket; + }, -function _findSocketFromDongle(dongleId) { + authenticateDongle: async (ws, res, cookies) => { + unsafeJwt = jsonwebtoken.decode(cookies.jwt); + const device = await deviceController.getDeviceFromDongle(unsafeJwt.identity) - let websocket = null; - wss.clients.forEach((value) => { - if (value.dongleId === dongleId) { - websocket = value; + let verifiedJWT; + + try { + verifiedJWT = jsonwebtoken.verify(cookies.jwt, device.public_key, { ignoreNotBefore: true }); + } catch (err) { + wss.retropilotFunc.actionLogger(null, null, "ATHENA_DEVICE_AUTHENTICATE_INVALID", null, ws._socket.remoteAddress, JSON.stringify({ jwt: cookies.jwt }), null); + return false; } - }) - return websocket; -} + if (verifiedJWT.identify === unsafeJwt.identify) { + ws.dongleId = device.dongle_id + ws.device_id = device.id + console.log("AUTHENTICATED DONGLE", ws.dongleId) + wss.retropilotFunc.actionLogger(null, device.id, "ATHENA_DEVICE_AUTHENTICATE_SUCCESS", null, ws._socket.remoteAddress, null); + return true; + } else { + console.log("UNAUTHENTICATED DONGLE"); + wss.retropilotFunc.actionLogger(null, device.id, "ATHENA_DEVICE_AUTHENTICATE_FAILURE", null, ws._socket.remoteAddress, JSON.stringify({ jwt: cookies.jwt }), null); + return false; + } + }, -function invoke(command, params, dongleId, accountId) { - const websocket = _findSocketFromDongle(dongleId); + commandBuilder: (method, params, id) => { + return { method, params: params, "jsonrpc": "2.0", "id": id } + }, - if (!websocket) { - _actionLogger(accountId, null, "ATHENA_USER_INVOKE__FAILED_DISCONNECTED", null, null, null, dongleId); - return {connected: false} - } - - _actionLogger(accountId, websocket.device_id, "ATHENA_USER_INVOKE__ISSUED", null, websocket._socket.remoteAddress, JSON.stringify({command, params}), websocket.dongleId); - - websocket.send(JSON.stringify(commandBuilder(command))) - - return {dispatched: true, heartbeat: websocket.heartbeat} + actionLogger: async (account_id, device_id, action, user_ip, device_ip, meta, dongle_id) => { + models.models.athena_action_log.create({ + account_id, device_id, action, user_ip, device_ip, meta, created_at: Date.now(), dongle_id + }) + }, } - -function isDeviceConnected(accountId, deviceId, dongleId ) { - const websocket = _findSocketFromDongle(dongleId); - _actionLogger(accountId, deviceId, "ATHENA_USER_STATUS__IS_CONNECTED", null, websocket ? websocket._socket.remoteAddress : null, JSON.stringify({connected: websocket ? true : false, heartbeat: websocket ? websocket.heartbeat : null}), dongleId); - - if (!websocket) return {connected: false} - - return {connected: true, heartbeat: websocket.heartbeat}; -} +const helpers = require('./helpers')(wss) - - - -module.exports = { - invoke, - isDeviceConnected -} +module.exports = helpers; \ No newline at end of file diff --git a/models/athena_returned_data.model.js b/models/athena_returned_data.model.js index 7f79d6b..88a04ca 100644 --- a/models/athena_returned_data.model.js +++ b/models/athena_returned_data.model.js @@ -9,21 +9,29 @@ module.exports = (sequelize) => { type: DataTypes.INTEGER }, device_id: { - allowNull: false, + allowNull: true, type: DataTypes.INTEGER }, type: { - allowNull: false, + allowNull: true, type: DataTypes.TEXT }, data: { allowNull: true, - type: DataTypes.BLOB + type: DataTypes.TEXT }, created_at: { allowNull: true, type: DataTypes.TEXT }, + uuid: { + allowNull: false, + type: DataTypes.TEXT + }, + resolved_at: { + allowNull: true, + type: DataTypes.INTEGER + } }, { timestamps: false, diff --git a/models/index.model.js b/models/index.model.js index 617a2bf..98521d7 100644 --- a/models/index.model.js +++ b/models/index.model.js @@ -3,7 +3,8 @@ const sequelize = new Sequelize({ dialect: 'sqlite', storage: 'database.sqlite', logQueryParameters: true, - benchmark: true + benchmark: true, + logging: false }); const modelDefiners = [ diff --git a/package.json b/package.json index 957a39f..4b2df6c 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "dependencies": { "@commaai/log_reader": "^0.8.0", "@sendgrid/client": "^7.4.3", + "abnf": "0.0.5", "chai": "^4.3.4", "chai-http": "^4.3.0", "cookie": "^0.4.1", @@ -40,6 +41,7 @@ "sqlite": "^4.0.22", "sqlite3": "^5.0.2", "supertest": "^6.1.3", + "uuid": "^8.3.2", "websocket": "^1.0.34", "ws": "^8.2.3" } diff --git a/routes/api/realtime.js b/routes/api/realtime.js index 8a06aed..2400bea 100644 --- a/routes/api/realtime.js +++ b/routes/api/realtime.js @@ -44,8 +44,7 @@ router.get('/dongle/:dongle_id/connected', async (req, res) => { router.get('/dongle/:dongle_id/send/:method', async (req, res) => { const account = await authenticationController.getAuthenticatedAccount(req, res); if (account == null) { return res.status(403).json({error: true, errorMsg: 'Unauthenticated', errorObject: {authenticated: false}})} - console.log(req.params.method.toLowerCase()); - console.log(whitelistParams[req.params.method.toLowerCase()]) + if (!whitelistParams[req.params.method.toLowerCase()]) { return res.status(409).json({error: true, errorMsg: 'invalid_method'}) } const device = await deviceController.getDeviceFromDongle(req.params.dongle_id); if (!device) {return res.status(400).json({error: true, errorMsg: 'no_dongle', errorObject: {authenticated: true, dongle_exists: false}})} @@ -57,6 +56,8 @@ router.get('/dongle/:dongle_id/send/:method', async (req, res) => { const data = await req.athenaWebsocketTemp.invoke(req.params.method, null, device.dongle_id, account.id); return res.status(200).json({success: true, dongle_id: device.dongle_id, method: req.params.method, data: data}); + + }) router.get('/dongle/:dongle_id/get', async (req, res) => { @@ -71,5 +72,19 @@ router.get('/dongle/:dongle_id/get', async (req, res) => { res.json(await models.models.athena_returned_data.findAll({where: {device_id: device.id}})) }) +router.get('/dongle/:dongle_id/temp/nav/:lat/:long', async (req, res) => { + if (!req.params.lat || !req.params.long) { return res.status(403).json({error: true, errorMsg: 'Malformed_Request', errorObject: {malformed: true}})} + const account = await authenticationController.getAuthenticatedAccount(req, res); + if (account == null) { return res.status(403).json({error: true, errorMsg: 'Unauthenticated', errorObject: {authenticated: false}})} + const device = await deviceController.getDeviceFromDongle(req.params.dongle_id); + if (!device) {return res.status(400).json({error: true, errorMsg: 'no_dongle', errorObject: {authenticated: true, dongle_exists: false}})} + if (device.account_id !== account.id) {return res.status(403).json({error: true, errorMsg: 'unauthorised', errorObject: {authenticated: true, dongle_exists: true, authorised_user: false}})} + + + const data = await req.athenaWebsocketTemp.invoke("setNavDestination", {latitude: req.params.lat, longitude: req.params.long}, device.dongle_id, account.id); + + return res.status(200).json({success: true, dongle_id: device.dongle_id, method: req.params.method, data: data}); +}) + module.exports = router \ No newline at end of file