parent
9361043d83
commit
32325111c6
114
Anetha/index.js
114
Anetha/index.js
|
@ -2,74 +2,103 @@ const WebSocket = require('ws');
|
|||
const fs = require('fs');
|
||||
const cookie = require('cookie')
|
||||
const jsonwebtoken = require('jsonwebtoken');
|
||||
|
||||
const models = require('./../models/index.model')
|
||||
|
||||
const authenticationController = require('./../controllers/authentication');
|
||||
const deviceController = require('./../controllers/devices');
|
||||
const { ws } = require('../routes/api/realtime');
|
||||
|
||||
let wss;
|
||||
|
||||
async function __server() {
|
||||
wss = new WebSocket.WebSocketServer({ path: '/ws/v2/', port: 4040 });
|
||||
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);
|
||||
return ws.terminate();
|
||||
}
|
||||
|
||||
ws.isAlive = false;
|
||||
ws.ping();
|
||||
});
|
||||
}, 5000);
|
||||
|
||||
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)
|
||||
console.log(unsafeJwt)
|
||||
|
||||
|
||||
let verifiedJWT;
|
||||
|
||||
try {
|
||||
verifiedJWT = jsonwebtoken.verify(cookies.jwt, device.public_key, {ignoreNotBefore: true});
|
||||
} catch (err) {
|
||||
console.log("bad JWT");
|
||||
_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
|
||||
console.log("AUTHENTICATED DONGLE")
|
||||
_actionLogger(null, device.id, "ATHENA_DEVICE_AUTHENTICATE_SUCCESS", null, ws._socket.remoteAddress, null);
|
||||
console.log("AUTHENTICATED DONGLE", ws.dongleId )
|
||||
return true;
|
||||
} else {
|
||||
_actionLogger(null, device.id, "ATHENA_DEVICE_AUTHENTICATE_FAILURE", null, ws._socket.remoteAddress, JSON.stringify({jwt: cookies.jwt}), null);
|
||||
console.log("UNAUTHENTICATED DONGLE");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function commandBuilder(method, params) {
|
||||
|
||||
|
||||
return {
|
||||
method,
|
||||
params,
|
||||
"jsonrpc": "2.0",
|
||||
"id": 0
|
||||
}
|
||||
|
||||
function commandBuilder(method, params) {
|
||||
return { method, params, "jsonrpc": "2.0", "id": 0 }
|
||||
}
|
||||
|
||||
|
||||
async function heartbeat() {
|
||||
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) {
|
||||
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) {
|
||||
if (!ws.dongleId) { return null; console.log("unauthenticated message, discarded"); }
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
_actionLogger(null, null, "ATHENA_DEVICE_MESSAGE_UNKNOWN", null, ws._socket.remoteAddress, JSON.stringify([message]), ws.dongleId);
|
||||
console.log("unknown message", JSON.stringify(message))
|
||||
});
|
||||
|
||||
|
@ -80,10 +109,6 @@ async function manageConnection(ws, res) {
|
|||
|
||||
//ws.send(JSON.stringify(await commandBuilder('reboot')))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -96,12 +121,9 @@ function _findSocketFromDongle(dongleId) {
|
|||
|
||||
let websocket = null;
|
||||
wss.clients.forEach((value) => {
|
||||
console.log(value.dongleId)
|
||||
|
||||
if (value.dongleId === dongleId) {
|
||||
websocket = value;
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return websocket;
|
||||
|
@ -110,15 +132,43 @@ function _findSocketFromDongle(dongleId) {
|
|||
|
||||
|
||||
|
||||
|
||||
function rebootDevice(dongleId) {
|
||||
// TODO - This is dumb
|
||||
function rebootDevice(dongleId, accountId) {
|
||||
const websocket = _findSocketFromDongle(dongleId);
|
||||
|
||||
|
||||
if (!websocket) { return false; console.log("bad")}
|
||||
if (!websocket) {
|
||||
return _actionLogger(accountId, null, "ATHENA_USER_INVOKE__REBOOT_FAILED_DISCONNECTED", null, null, null, ws.dongleId);
|
||||
}
|
||||
|
||||
_actionLogger(accountId, null, "ATHENA_USER_INVOKE__REBOOT_ISSUED", null, ws._socket.remoteAddress, null, ws.dongleId);
|
||||
|
||||
websocket.send(JSON.stringify(commandBuilder('reboot')))
|
||||
|
||||
}
|
||||
|
||||
|
||||
function getDetails(dongleId, accountId) {
|
||||
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);
|
||||
|
||||
if (!websocket) return {connected: false}
|
||||
|
||||
return {connected: true, heartbeat: websocket.heartbeat};
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,5 +176,7 @@ function rebootDevice(dongleId) {
|
|||
|
||||
|
||||
module.exports = {
|
||||
rebootDevice
|
||||
rebootDevice,
|
||||
isDeviceConnected,
|
||||
getDetails
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
const { DataTypes } = require('sequelize');
|
||||
|
||||
module.exports = (sequelize) => {
|
||||
sequelize.define('athena_action_log', {
|
||||
id: {
|
||||
allowNull: false,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
account_id: {
|
||||
allowNull: true,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
device_id: {
|
||||
allowNull: true,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
action: {
|
||||
allowNull: true,
|
||||
type: DataTypes.TEXT
|
||||
},
|
||||
user_ip: {
|
||||
allowNull: true,
|
||||
type: DataTypes.TEXT
|
||||
},
|
||||
device_ip: {
|
||||
allowNull: true,
|
||||
type: DataTypes.TEXT
|
||||
},
|
||||
meta: {
|
||||
allowNull: true,
|
||||
type: DataTypes.TEXT
|
||||
},
|
||||
created_at: {
|
||||
allowNull: true,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
dongle_id: {
|
||||
allowNull: true,
|
||||
type: DataTypes.TEXT
|
||||
}
|
||||
}, {
|
||||
timestamps: false,
|
||||
});
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
const { DataTypes } = require('sequelize');
|
||||
|
||||
module.exports = (sequelize) => {
|
||||
sequelize.define('athena_returned_data', {
|
||||
id: {
|
||||
allowNull: false,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
account_id: {
|
||||
allowNull: false,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
device_id: {
|
||||
allowNull: true,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
type: {
|
||||
allowNull: true,
|
||||
type: DataTypes.TEXT
|
||||
},
|
||||
data: {
|
||||
allowNull: true,
|
||||
type: DataTypes.BLOB
|
||||
},
|
||||
created_at: {
|
||||
allowNull: true,
|
||||
type: DataTypes.TEXT
|
||||
},
|
||||
|
||||
}, {
|
||||
timestamps: false,
|
||||
});
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
const { DataTypes } = require('sequelize');
|
||||
|
||||
module.exports = (sequelize) => {
|
||||
sequelize.define('device_authorised_users', {
|
||||
id: {
|
||||
allowNull: false,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
account_id: {
|
||||
allowNull: false,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
device_id: {
|
||||
allowNull: true,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
athena: {
|
||||
allowNull: true,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
unpair: {
|
||||
allowNull: true,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
view_drives: {
|
||||
allowNull: true,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
created_at: {
|
||||
allowNull: true,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
|
||||
}, {
|
||||
timestamps: false,
|
||||
});
|
||||
};
|
|
@ -10,6 +10,9 @@ const modelDefiners = [
|
|||
require('./devices.model'),
|
||||
require('./drives.model'),
|
||||
require('./users.model'),
|
||||
require('./athena_action_log.model'),
|
||||
require('./athena_returned_data.model'),
|
||||
require('./device_authorised_users.model'),
|
||||
];
|
||||
|
||||
for (const modelDefiner of modelDefiners) {
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
const router = require('express').Router();
|
||||
|
||||
const authenticationController = require('./../../controllers/authentication');
|
||||
const userController = require('./../../controllers/users');
|
||||
const deviceController = require('./../../controllers/devices')
|
||||
|
||||
const whitelistParams = {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
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}})}
|
||||
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.isDeviceConnected(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) => {
|
||||
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.getDetails(device.dongle_id);
|
||||
|
||||
// return res.status(200).json({success: true, dongle_id: device.dongle_id, data: deviceConnected});
|
||||
})
|
||||
|
||||
|
||||
/*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]}})}
|
||||
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});
|
||||
})*/
|
||||
|
||||
|
||||
|
||||
module.exports = router
|
|
@ -7,6 +7,7 @@ module.exports = (_models, _controllers, _logger) => {
|
|||
useradmin: require('./useradmin')(_models, _controllers, _logger),
|
||||
api: require('./api')(_models, _controllers, _logger),
|
||||
useradminapi: require('./userAdminApi')(_models, _controllers, _logger),
|
||||
admin: require('./administration/adminApi')(_models, _controllers, _logger)
|
||||
admin: require('./administration/adminApi')(_models, _controllers, _logger),
|
||||
realtime: require('./api/realtime')
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue