Athena, logging, etc
parent
32325111c6
commit
f4cb1ef142
|
@ -51,13 +51,17 @@ const authenticateDongle = async (ws, res, cookies) => {
|
|||
|
||||
|
||||
if (verifiedJWT.identify === unsafeJwt.identify) {
|
||||
|
||||
ws.dongleId = device.dongle_id
|
||||
_actionLogger(null, device.id, "ATHENA_DEVICE_AUTHENTICATE_SUCCESS", null, ws._socket.remoteAddress, null);
|
||||
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);
|
||||
console.log("UNAUTHENTICATED DONGLE");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -69,8 +73,14 @@ function commandBuilder(method, params) {
|
|||
|
||||
|
||||
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) {
|
||||
|
@ -82,6 +92,7 @@ async function _actionLogger(account_id, device_id, action, user_ip, device_ip,
|
|||
async function manageConnection(ws, res) {
|
||||
ws.badMessages = 0;
|
||||
ws.isAlive = true;
|
||||
|
||||
ws.heartbeat = Date.now();
|
||||
|
||||
ws.on('pong', heartbeat);
|
||||
|
@ -98,8 +109,21 @@ async function manageConnection(ws, res) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
models.models.athena_returned_data.create({
|
||||
device_id: ws.device_id,
|
||||
type: "UNKNOWN",
|
||||
data: JSON.stringify(message),
|
||||
created_at: Date.now()
|
||||
|
||||
})
|
||||
|
||||
_actionLogger(null, null, "ATHENA_DEVICE_MESSAGE_UNKNOWN", null, ws._socket.remoteAddress, JSON.stringify([message]), ws.dongleId);
|
||||
console.log("unknown message", JSON.stringify(message))
|
||||
const buff = Buffer.from(JSON.stringify(message), 'utf-8');
|
||||
|
||||
// decode buffer as UTF-8
|
||||
console.log(buff.toString('base64'))
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
@ -131,40 +155,26 @@ function _findSocketFromDongle(dongleId) {
|
|||
|
||||
|
||||
|
||||
|
||||
// TODO - This is dumb
|
||||
function rebootDevice(dongleId, accountId) {
|
||||
function invoke(command, params, dongleId, accountId) {
|
||||
const websocket = _findSocketFromDongle(dongleId);
|
||||
|
||||
|
||||
if (!websocket) {
|
||||
return _actionLogger(accountId, null, "ATHENA_USER_INVOKE__REBOOT_FAILED_DISCONNECTED", null, null, null, ws.dongleId);
|
||||
_actionLogger(accountId, null, "ATHENA_USER_INVOKE__FAILED_DISCONNECTED", null, null, null, dongleId);
|
||||
return {connected: false}
|
||||
}
|
||||
|
||||
_actionLogger(accountId, null, "ATHENA_USER_INVOKE__REBOOT_ISSUED", null, ws._socket.remoteAddress, null, ws.dongleId);
|
||||
_actionLogger(accountId, websocket.device_id, "ATHENA_USER_INVOKE__ISSUED", null, websocket._socket.remoteAddress, JSON.stringify({command, params}), websocket.dongleId);
|
||||
|
||||
websocket.send(JSON.stringify(commandBuilder('reboot')))
|
||||
websocket.send(JSON.stringify(commandBuilder(command)))
|
||||
|
||||
return {dispatched: true, heartbeat: websocket.heartbeat}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function getDetails(dongleId, accountId) {
|
||||
function isDeviceConnected(accountId, deviceId, dongleId ) {
|
||||
const websocket = _findSocketFromDongle(dongleId);
|
||||
|
||||
if (!websocket) {
|
||||
return _actionLogger(accountId, null, "ATHENA_USER_INVOKE__GETVERSION_FAILED_DISCONNECTED", null, null, null, ws.dongleId);
|
||||
}
|
||||
|
||||
_actionLogger(accountId, null, "ATHENA_USER_INVOKE__GETVERSION_ISSUED", null, ws._socket.remoteAddress, null, ws.dongleId);
|
||||
|
||||
websocket.send(JSON.stringify(commandBuilder('getVersion')))
|
||||
|
||||
}
|
||||
|
||||
|
||||
function isDeviceConnected(dongleId, accountId) {
|
||||
const websocket = _findSocketFromDongle(dongleId);
|
||||
_actionLogger(null, null, "ATHENA_USER_STATUS__IS_CONNECTED", null, websocket ? websocket._socket.remoteAddress : null, JSON.stringify({connected: websocket ? true : false, heartbeat: websocket ? websocket.heartbeat : null}), 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}
|
||||
|
||||
|
@ -176,7 +186,6 @@ function isDeviceConnected(dongleId, accountId) {
|
|||
|
||||
|
||||
module.exports = {
|
||||
rebootDevice,
|
||||
isDeviceConnected,
|
||||
getDetails
|
||||
invoke,
|
||||
isDeviceConnected
|
||||
}
|
||||
|
|
|
@ -37,6 +37,16 @@ var config = {
|
|||
|
||||
flags: {
|
||||
useUserAdminApi: false,
|
||||
},
|
||||
|
||||
athena: {
|
||||
enabled: true, // Enables Athena service
|
||||
api: {
|
||||
ratelimit: 100 // Maxmium hits to /realtime/* per 30s
|
||||
},
|
||||
socket: {
|
||||
heartbeatFrequency: 5000 // Higher the number = lower traffic, varies on how many devices are connected
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ const config = require('./../config');
|
|||
const authenticationController = require('./authentication');
|
||||
const models_orm = require('./../models/index.model')
|
||||
const sanitize = require('sanitize')();
|
||||
const { Op } = require('sequelize')
|
||||
|
||||
|
||||
async function pairDevice(account, qr_string) {
|
||||
|
@ -116,6 +117,11 @@ async function getAllDevicesFiltered() {
|
|||
}
|
||||
|
||||
|
||||
async function updateLastPing(device_id, dongle_id) {
|
||||
models_orm.models.device.update({ last_ping: Date.now() }, {where: {[Op.or] : [{id: device_id}, {dongle_id: dongle_id}]}})
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
pairDevice: pairDevice,
|
||||
unpairDevice: unpairDevice,
|
||||
|
@ -125,4 +131,5 @@ module.exports = {
|
|||
setIgnoredUploads,
|
||||
getAllDevicesFiltered,
|
||||
pairDeviceToAccountId,
|
||||
updateLastPing
|
||||
}
|
||||
|
|
|
@ -8,16 +8,12 @@ module.exports = (sequelize) => {
|
|||
primaryKey: true,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
account_id: {
|
||||
device_id: {
|
||||
allowNull: false,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
device_id: {
|
||||
allowNull: true,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
type: {
|
||||
allowNull: true,
|
||||
allowNull: false,
|
||||
type: DataTypes.TEXT
|
||||
},
|
||||
data: {
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
"esm": "^3.2.25",
|
||||
"express": "^4.17.1",
|
||||
"express-fileupload": "^1.2.1",
|
||||
"express-rate-limit": "^5.5.0",
|
||||
"express-ws": "^5.0.2",
|
||||
"fast-folder-size": "^1.3.0",
|
||||
"ffprobe": "^1.1.2",
|
||||
|
|
|
@ -3,26 +3,29 @@ const router = require('express').Router();
|
|||
const authenticationController = require('./../../controllers/authentication');
|
||||
const userController = require('./../../controllers/users');
|
||||
const deviceController = require('./../../controllers/devices')
|
||||
const models = require('./../../models/index.model')
|
||||
|
||||
const whitelistParams = {
|
||||
getMessage: false,
|
||||
getVersion: true,
|
||||
setNavDestination: true,
|
||||
listDataDirectory: false,
|
||||
getmessage: false,
|
||||
getversion: true,
|
||||
setnavdestination: true,
|
||||
listdatadirectory: false,
|
||||
reboot: true,
|
||||
uploadFileToUrl: false,
|
||||
listUploadQueue: true,
|
||||
cancelUpload: true,
|
||||
primeActivated: false,
|
||||
getPublicKey: true,
|
||||
getSshAuthorizedKeys: true,
|
||||
getSimInfo: true,
|
||||
getNetworkType: true,
|
||||
getNetworks: true,
|
||||
takeSnapshot: true
|
||||
uploadfiletourl: false,
|
||||
listuploadqueue: true,
|
||||
cancelupload: true,
|
||||
primeactivated: true,
|
||||
getpublickey: true,
|
||||
getsshauthorizedkeys: true,
|
||||
getsiminfo: true,
|
||||
getnetworktype: true,
|
||||
getnetworks: true,
|
||||
takesnapshot: true
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
router.get('/dongle/:dongle_id/connected', 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}})}
|
||||
|
@ -33,14 +36,17 @@ router.get('/dongle/:dongle_id/connected', async (req, res) => {
|
|||
// TODO remove indication of dongle existing
|
||||
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 deviceConnected = await req.athenaWebsocketTemp.isDeviceConnected(device.dongle_id);
|
||||
const deviceConnected = await req.athenaWebsocketTemp.isDeviceConnected(device.id, account.id, device.dongle_id);
|
||||
|
||||
return res.status(200).json({success: true, dongle_id: device.dongle_id, data: deviceConnected});
|
||||
})
|
||||
|
||||
router.get('/dongle/:dongle_id/getDetails', 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}})}
|
||||
|
||||
|
@ -48,28 +54,22 @@ router.get('/dongle/:dongle_id/getDetails', async (req, res) => {
|
|||
// TODO remove indication of dongle existing
|
||||
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 deviceConnected = await req.athenaWebsocketTemp.getDetails(device.dongle_id);
|
||||
|
||||
// return res.status(200).json({success: true, dongle_id: device.dongle_id, data: deviceConnected});
|
||||
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.post('/dongle/:dongle_id/raw', bodyParser.urlencoded({extended: true}), async (req, res) => {
|
||||
if (!req.body.hasOwnProperty('method') { return res.status(403).json({error: true, errorMsg: 'missing_data', errorObject: {missing: [method]}})}
|
||||
router.get('/dongle/:dongle_id/get', 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}})}
|
||||
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}})}
|
||||
|
||||
// TODO support delgation of access
|
||||
// TODO remove indication of dongle existing
|
||||
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 deviceConnected = await req.athenaWebsocketTemp.raw(req.body.method, req.body.params);
|
||||
|
||||
return res.status(200).json({success: true, dongle_id: device.dongle_id, data: deviceConnected});
|
||||
})*/
|
||||
|
||||
res.json(await models.models.athena_returned_data.findAll({where: {device_id: device.id}}))
|
||||
})
|
||||
|
||||
|
||||
module.exports = router
|
30
server.js
30
server.js
|
@ -7,6 +7,7 @@ const https = require('https');
|
|||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const rateLimit = require("express-rate-limit");
|
||||
|
||||
log4js.configure({
|
||||
appenders: {logfile: {type: "file", filename: "server.log"}, out: {type: 'console'} /*{type: "file", filename: "server1.log"}*/},
|
||||
|
@ -22,6 +23,7 @@ let models = require('./models/index');
|
|||
let models_sqli = require('./models/index.model');
|
||||
let controllers = require('./controllers');
|
||||
let routers = require('./routes')
|
||||
const athena = require('./Anetha/index');
|
||||
|
||||
|
||||
|
||||
|
@ -40,9 +42,13 @@ function runAsyncWrapper(callback) {
|
|||
const app = express();
|
||||
|
||||
|
||||
const athenaRateLimit = rateLimit({
|
||||
windowMs: 30000,
|
||||
max: config.athena.api.ratelimit
|
||||
});
|
||||
|
||||
|
||||
|
||||
const athena = require('./Anetha/index');
|
||||
|
||||
|
||||
const web = async () => {
|
||||
|
@ -62,15 +68,21 @@ const web = async () => {
|
|||
app.use(routers.api);
|
||||
app.use(routers.useradmin);
|
||||
|
||||
app.use((req, res, next) => {
|
||||
if (config.athena.enabled) {
|
||||
app.use((req, res, next) => {
|
||||
req.athenaWebsocketTemp = athena;
|
||||
return next();
|
||||
});
|
||||
|
||||
|
||||
app.use('/admin', routers.admin);
|
||||
app.use('/realtime', athenaRateLimit);
|
||||
app.use('/realtime', routers.realtime);
|
||||
} else {
|
||||
logger.log("Athena disabled");
|
||||
}
|
||||
|
||||
req.athenaWebsocketTemp = athena;
|
||||
return next();
|
||||
});
|
||||
|
||||
|
||||
app.use('/admin', routers.admin);
|
||||
app.use('/realtime', routers.realtime);
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue