TODO: Fix admin api auth catching any undefined routes

Removed pointlessly stateful controllers, admin api fleshed out
pull/4/head
AdamSBlack 2021-10-11 19:37:58 +01:00
parent e33b10e7d0
commit 3596013e2f
12 changed files with 252 additions and 72 deletions

View File

@ -1,33 +1,59 @@
const config = require('./../config');
const crypto = require('crypto');
const models_orm = require('./../models/index.model')
let models;
let logger;
let controllers;
async function isCurrentUserAdmin(req) {
// TODO move everythijng away from this dumb intertwined style
const devices = require('./../controllers/devices');
const authentication = require('./../controllers/authentication')
async function isCurrentUserAdmin(hardFail, req) {
const account = await authentication.getAuthenticatedAccount(req);
if (!account) return {isAdmin: false, account:account};
if (account.admin !== 1) { return {isAdmin: false, account: account};}
return {isAdmin: true, account: account};
}
async function banAccount(ban, user) {
if (!user || !ban) return {success: false, status: 400, data: {bad_data: true}}
const banQuery = await models.users.banAccount(ban, user.id);
const account = await models.users.getAccountFromId(user.id)
if (account.banned === ban ? 1 : 0) {
async function banAccount(ban, userId) {
if (!userId || !ban) return {success: false, status: 400, data: {bad_data: true}}
let cleanBan;
if (ban === "true" || ban === "false") {
cleanBan = ban === "true" ? true : false
} else {
return {success: false, status: 400, data: {bad_data: true}}
}
const update = await models_orm.models.accounts.update(
{ banned: cleanBan ? 1 : 0 },
{ where: { id: userId } }
)
const verify = await models_orm.models.accounts.findOne({where: {id: userId}});
if (verify.dataValues && verify.dataValues.banned === cleanBan ? 1 : 0) {
return {success: true, status: 200, data: {banned: ban}}
} else {
return {success: false, status: 500, data: {banned: false}}
}
}
module.exports = (_models, _logger, _controllers) => {
models = _models;
logger = _logger;
controllers = _controllers
return {
banAccount
}
module.exports = {
banAccount,
isCurrentUserAdmin
}

View File

@ -1,5 +1,4 @@
const jwt = require('jsonwebtoken');
let models;
let logger;
const models_orm = require('./../models/index.model')
const crypto = require('crypto');
@ -97,14 +96,10 @@ async function getAuthenticatedAccount(req, res) {
}
module.exports = (_models, _logger) => {
models = _models;
logger = _logger;
return {
validateJWT: validateJWT,
getAuthenticatedAccount: getAuthenticatedAccount,
changePassword: changePassword,
signIn: signIn
}
}
module.exports = {
validateJWT: validateJWT,
getAuthenticatedAccount: getAuthenticatedAccount,
changePassword: changePassword,
signIn: signIn
}

View File

@ -1,8 +1,8 @@
const config = require('./../config');
let models;
let logger;
const authenticationController = require('./authentication')(models, logger);
const authenticationController = require('./authentication');
const models_orm = require('./../models/index.model')
const sanitize = require('sanitize')();
async function pairDevice(account, qr_string) {
@ -13,12 +13,12 @@ async function pairDevice(account, qr_string) {
let deviceQuery;
let pairJWT;
if (qrCodeParts.length > 0) {
deviceQuery = await models_orm.models.devices.findOne({ where: { imei: qrCodeParts[0], serial: qrCodeParts[1] }});
deviceQuery = await models_orm.models.device.findOne({ where: { imei: qrCodeParts[0], serial: qrCodeParts[1] }});
pairJWT = qrCodeParts[2];
} else {
pairJWT = qr_string;
const data = authenticationController.readJWT(qr_string);
deviceQuery = await models_orm.models.devices.findOne({ where: { dongle_id: data.identiy }});
deviceQuery = await models_orm.models.device.findOne({ where: { dongle_id: data.identiy }});
}
if (deviceQuery.dataValues == null) {
@ -38,19 +38,72 @@ async function pairDevice(account, qr_string) {
{ account_id: account.id },
{ where: { dongle_id: device.dongle_id } }
)
return {success: true, paired: true, dongle_id: device.dongle_id, account_id: account.id}
}
async function unpairDevice(account, dongleId) {
const device = await models_orm.models.device.getOne({where: {account_id: account.id, dongle_id: dongleId}});
module.exports = (_models, _logger, _controllers) => {
models = _models;
logger = _logger;
controllers = _controllers
return {
pairDevice: pairDevice
if (device && device.dataValues) {
await models_orm.models.device.update({account_id: 0}, {where: {dongle_id: dongleId}});
return {success: true}
} else {
return {success: false, msg: 'BAD DONGLE', invalidDongle: true};
}
}
async function setDeviceNickname(account, dongleId, nickname) {
const device = await models_orm.models.device.getOne({where: {account_id: account.id, dongle_id: dongleId}});
const cleanNickname = sanitize.value(nickname, 'string')
if (device && device.dataValues) {
await models_orm.models.device.update({nickname: cleanNickname}, {where: {dongle_id: dongleId}});
return {success: true, data: {nickname: cleanNickname}}
} else {
return {success: false, msg: 'BAD DONGLE', invalidDongle: true};
}
}
async function getDevices(accountId) {
const devices = await models_orm.models.device.getOne({where: {account_id: accountId}});
return devices.dataValues || null
}
async function getDeviceFromDongle(dongleId) {
const devices = await models_orm.models.device.getOne({where: {dongle_id: dongleId}});
return devices.dataValues || null
}
async function setIgnoredUploads(dongleId, isIgnored) {
const update = models_orm.models.accounts.update(
{ dongle_id: dongleId },
{ where: { uploads_ignored: isIgnored } }
)
// TODO check this change was processed..
return true;
}
async function getAllDevicesFiltered() {
console.log(models_orm.models.device)
const devices = await models_orm.models.device.findAll();
return devices.dataValues || null
}
module.exports = {
pairDevice: pairDevice,
unpairDevice: unpairDevice,
setDeviceNickname: setDeviceNickname,
getDevices: getDevices,
getDeviceFromDongle,
setIgnoredUploads,
getAllDevicesFiltered,
}

View File

@ -5,13 +5,13 @@ module.exports = async (models, logger, models_sqli) => {
return {
authentication: require('./authentication')(models, logger),
authentication: require('./authentication'),
helpers: require('./helpers')(models, logger),
storage: require('./storage')(models, logger),
mailing: require('./mailing')(models, logger),
users: require('./users')(models, logger),
admin: require('./admin')(models, logger),
devices: require('./devices')(models, logger)
admin: require('./admin'),
devices: require('./devices')
}
}

View File

@ -1,6 +1,7 @@
const config = require('./../config');
const crypto = require('crypto');
const models_orm = require('./../models/index.model')
const models_orm = require('./../models/index.model');
const authentication = require('./authentication');
let models;
let logger;
@ -57,11 +58,17 @@ async function verifyEmailToken(token) {
}
)
return {success: true, status: 200, data: {successfullyVerified: true}}
}
async function getAllUsers() {
const users = await models_orm.models.accounts.findAll({attributes: ['id', 'last_ping', 'created', 'admin', 'banned']})
return users;
}
module.exports = (_models, _logger) => {
models = _models;
@ -70,6 +77,7 @@ module.exports = (_models, _logger) => {
return {
createAccount,
verifyEmailToken,
getAccountFromId
getAccountFromId,
getAllUsers
}
}

View File

@ -0,0 +1,20 @@
let db;
async function getDeviceFromDongleId(email) {
return await db.run('SELECT * FROM devices WHERE dongle_id', Date.now(), email);
}
module.exports = (_db) => {
db = _db;
return {
userPing,
getAccountFromEmail,
createUser,
getAccountFromId,
getAccountFromVerifyToken,
verifyAccountEmail,
banAccount
}
}

View File

@ -32,6 +32,7 @@
"multer": "^1.4.2",
"nodemailer": "^6.6.0",
"proper-lockfile": "^4.1.2",
"sanitize": "^2.1.0",
"sequelize": "^6.6.5",
"sqlite": "^4.0.22",
"sqlite3": "^5.0.2",

View File

@ -1,6 +1,7 @@
const router = require('express').Router();
const bodyParser = require('body-parser');
const crypto = require('crypto');
const { route } = require('../../server');
const config = require('./../../config');
@ -17,30 +18,96 @@ let logger;
// probs should put middleware somewhere else
router.use(async function (req, res, next) {
const currentAdmin = await controllers.admin.isCurrentUserAdmin(true, req);
if (currentAdmin.isAdmin === false) {
return res.status(402).json({error:true, msg: 'NOT AUTHORISED', status: 403}).end();
} else {
next();
}
});
// TODO
// DRIVE & BOOT/CRASH LOG FILE UPLOAD HANDLING
router.get('/admin/user/:userId/ban/:ban', runAsyncWrapper(async (req, res) => {
const account = await controllers.authentication.getAuthenticatedAccount(req, res);
if (!account) return res.status(403).json({error: true, msg: 'BAD ACCOUNT', status: 403});
if (account.admin !== 1) { return res.status(402).json({error:true, msg: 'NOT AUTHORISED', status: 403})}
const banUser = await controllers.users.getAccountFromId(req.params.userId);
if (banUser) {
const banResult = await controllers.admin.banAccount(req.params.ban, banUser)
const banResult = await controllers.admin.banAccount(req.params.ban, req.params.userId)
if (banResult.hasOwnProperty('success') && banResult.success === true) {
res.status(200).json(banResult);
} else {
res.status(500).json(banResult)
}
} else {
res.status(400).json({success: false, error: true, msg: 'NO ACCOUNT FOR ID'})
}
}));
router.get('/admin/user/:userId/get/devices', runAsyncWrapper(async (req, res) => {
if (!req.params.userId) { return req.status(400).json({error: true, msg: 'MISSING DATA', status: 400})}
return res.status(200).json({success: true, data: controllers.devices.getDevices(req.params.userId)})
}));
router.get('/admin/user/', runAsyncWrapper(async (req, res) => {
console.warn("PROCESSED")
return res.status(200).json({success: true, data: await controllers.users.getAllUsers()})
}));
router.get('/admin/device/:dongle_id', runAsyncWrapper(async (req, res) => {
if (!req.params.dongle_id) { return req.status(400).json({error: true, msg: 'MISSING DATA', status: 400})}
return res.status(200).json({success: true, data: await controllers.devices.getDeviceFromDongle(getDeviceFromDongle)})
}));
router.get('/admin/device', runAsyncWrapper(async (req, res) => {
return res.status(200).json({success: true, data: await controllers.devices.getAllDevicesFiltered()})
}));
router.get('/admin/device/:dongle_id/ignore/:ignore_uploads', runAsyncWrapper(async (req, res) => {
if (!req.params.dongle_id || !req.params.ignore_uploads) { return req.status(400).json({error: true, msg: 'MISSING DATA', status: 400})}
}));
router.get('/admin/device/:dongle_id/ignore/:ignore_uploads', runAsyncWrapper(async (req, res) => {
if (!req.params.dongle_id || !req.params.ignore_uploads) { return req.status(400).json({error: true, msg: 'MISSING DATA', status: 400})}
let ignore = null;
switch (req.params.ignore_uploads) {
case "true":
ignore = true
break;
case "false":
ignore = false
break;
default:
return res.json({error: true, msg: 'MISSING DATA'})
break
}
if (ignore === null) {return}
await controllers.devices.setIgnoredUploads(req.params.dongle_id);
return res.status(200).json({success: true});
}));
module.exports = (_models, _controllers, _logger) => {
models = _models;

View File

@ -6,7 +6,7 @@ module.exports = (_models, _controllers, _logger) => {
return {
useradmin: require('./useradmin')(_models, _controllers, _logger),
api: require('./api')(_models, _controllers, _logger),
useradminapi: require('./userAdminApi')(_models, _controllers, _logger)
//adminApi: require('./administration/adminApi')(_models, _controllers, _logger)
useradminapi: require('./userAdminApi')(_models, _controllers, _logger),
admin: require('./administration/adminApi')(_models, _controllers, _logger)
}
}

View File

@ -81,6 +81,7 @@ router.post('/retropilot/0/register/email', bodyParser.urlencoded({extended: tru
}
}));
router.get('/retropilot/0/register/verify/:token', bodyParser.urlencoded({extended: true}), runAsyncWrapper(async (req, res) => {
if (!req.params.token) {
res.json({success: false, status: 400, data: {missingToken: true}}).status(400);
@ -95,7 +96,28 @@ router.get('/retropilot/0/register/verify/:token', bodyParser.urlencoded({extend
} else {
return res.json({success: false, msg: 'contact server admin'}).status(500);
}
}));
router.get('/retropilot/0/dongle/:dongle_id/nickname/:nickname', bodyParser.urlencoded({extended: true}), runAsyncWrapper(async (req, res) => {
if (!req.params.nickname || !req.params.dongle_id) {
return res.json({success: false, status: 400, msg: 'MISSING PRAMS'}).status(400);
}
const account = await controllers.authentication.getAuthenticatedAccount(req, res);
if (account == null) {
return res.redirect('/useradmin?status=' + encodeURIComponent('Invalid or expired session'));
}
const setNickname = await controllers.devices.setDeviceNickname(account, req.params.dongle_id, req.params.nickname)
if (setNickname.status === true) {
res.json({success: true, data: {nickname: setNickname.data.nickname}})
}
}));
/*

View File

@ -229,21 +229,7 @@ router.get('/useradmin/unpair_device/:dongleId', runAsyncWrapper(async (req, res
res.redirect('/useradmin?status=' + encodeURIComponent('Invalid or expired session'));
return;
}
const device = await models.__db.get('SELECT * FROM devices WHERE account_id = ? AND dongle_id = ?', account.id, req.params.dongleId);
if (device == null) {
res.status(400);
res.send('Unauthorized.');
return;
}
const result = await models.__db.run(
'UPDATE devices SET account_id = ? WHERE dongle_id = ?',
0,
req.params.dongleId
);
res.redirect('/useradmin/overview');
})),

View File

@ -57,6 +57,8 @@ const web = async () => {
app.use(routers.api);
app.use(routers.useradmin);
app.use(routers.admin);
//if (config.flags.useUserAdminApi) app.use(routers.useradminapi);
//app.use(routers.useradminapi)