diff --git a/controllers/authentication.js b/controllers/authentication.js index 96bb5b8..aaeac5c 100644 --- a/controllers/authentication.js +++ b/controllers/authentication.js @@ -33,8 +33,6 @@ async function signIn(email, password) { if (account.password === inputPassword) { const token = jsonwebtoken.sign({ accountId: account.id }, config.applicationSalt); - // TODO: INSECURE, DEBUG - console.log('jwt: ', token); return { success: true, jwt: token }; } return { success: false, msg: 'BAD PASSWORD', invalidPassword: true }; diff --git a/controllers/devices.js b/controllers/devices.js index 125d6f5..b908b86 100644 --- a/controllers/devices.js +++ b/controllers/devices.js @@ -277,7 +277,10 @@ async function updateOrCreateDrive(dongleId, identifier, data) { return orm.models.drives.create({ ...data, dongle_Id: dongleId, - identifier, + [Op.or]: [ + { identifier: dongleId }, + { id: dongleId }, + ], }); } @@ -348,4 +351,5 @@ module.exports = { getDriveFromidentifier, updateOrCreateDrive, updateOrCreateDriveSegment, + getDriveSegment, }; diff --git a/controllers/users.js b/controllers/users.js index f033643..6c4a197 100644 --- a/controllers/users.js +++ b/controllers/users.js @@ -6,6 +6,21 @@ async function getAccountFromId(id) { return orm.models.accounts.findByPk(id); } +async function getAccountFromEmail(email) { + if (!email) return null; + + const account = orm.models.accounts.findOne({ where: { email } }); + + if (account.dataValues) return account.dataValues; + return null; +} + +async function _dirtyCreateAccount(email, password, created, banned) { + return orm.models.accounts.create({ + email, password, created, banned, + }); +} + async function createAccount(email, password) { if (!email || !password) { return { success: false, status: 400, data: { missingData: true } }; @@ -73,4 +88,6 @@ module.exports = { verifyEmailToken, getAccountFromId, getAllUsers, + getAccountFromEmail, + _dirtyCreateAccount, }; diff --git a/models/devices.js b/models/devices.js deleted file mode 100644 index 87615de..0000000 --- a/models/devices.js +++ /dev/null @@ -1,19 +0,0 @@ -let db; - -async function getDeviceFromDongleId(email) { - return db.run('SELECT * FROM devices WHERE dongle_id', Date.now(), email); -} - -module.exports = (_db) => { - db = _db; - - return { - userPing, - getAccountFromEmail, - createUser, - getAccountFromId, - getAccountFromVerifyToken, - verifyAccountEmail, - banAccount, - }; -}; diff --git a/models/drives.js b/models/drives.js deleted file mode 100644 index 9cec082..0000000 --- a/models/drives.js +++ /dev/null @@ -1,26 +0,0 @@ -let db; - -function getDrives(dongleId) { - -} - -async function getDevice(dongleId) { - return db.get('SELECT * FROM devices WHERE dongle_id = ?', dongleId); -} - -async function deviceCheckIn(dongleId) { - return db.run( - 'UPDATE devices SET last_ping = ? WHERE dongle_id = ?', - Date.now(), - dongleId, - ); -} - -module.exports = (_db) => { - db = _db; - - return { - getDevice, - deviceCheckIn, - }; -}; diff --git a/models/index.js b/models/index.js deleted file mode 100644 index a1a751f..0000000 --- a/models/index.js +++ /dev/null @@ -1,39 +0,0 @@ -/* eslint-disable global-require */ -const sqlite3 = require('sqlite3'); -const { open } = require('sqlite'); -const config = require('../config'); - -async function validateDatabase(db, logger) { - try { - db = await open({ - filename: config.databaseFile, - driver: sqlite3.Database, - mode: sqlite3.OPEN_READWRITE, - }); - await db.get('SELECT * FROM accounts LIMIT 1'); - await db.get('SELECT * FROM devices LIMIT 1'); - await db.get('SELECT * FROM drives LIMIT 1'); - await db.get('SELECT * FROM drive_segments LIMIT 1'); - } catch (exception) { - logger.error(exception); - process.exit(); - } -} - -async function connect() { - let db; - - try { - db = await open({ - filename: config.databaseFile, - driver: sqlite3.Database, - mode: sqlite3.OPEN_READWRITE, - }); - } catch (exception) { - process.exit(); - } - - return db; -} - -module.exports = connect; diff --git a/models/users.js b/models/users.js deleted file mode 100644 index 5af060b..0000000 --- a/models/users.js +++ /dev/null @@ -1,44 +0,0 @@ -let db; - -async function userPing(email) { - return db.run('UPDATE accounts SET last_ping = ? WHERE email = ?', Date.now(), email); -} - -async function getAccountFromEmail(email) { - return db.get('SELECT * FROM accounts WHERE LOWER(email) = ?', email); -} - -async function getAccountFromVerifyToken(token) { - return db.get('SELECT * FROM accounts WHERE email_verify_token = ?', token); -} - -async function getAccountFromId(id) { - return db.get('SELECT * FROM accounts WHERE id = ?', id); -} - -async function createUser(email, password, created, lastPing, emailToken) { - return db.get('INSERT INTO accounts (email, password, created, last_ping, email_verify_token) VALUES (?,?,?,?,?)', email, password, created, lastPing, emailToken); -} - -async function verifyAccountEmail(email, verified, newToken) { - verified = verified === true ? 1 : 0; - return db.get('UPDATE accounts SET verified=? WHERE email = ?', verified, email); -} - -async function banAccount(ban, userId) { - return db.get('UPDATE accounts SET banned=? WHERE id = ?', ban ? 1 : 0, userId); -} - -module.exports = (_db) => { - db = _db; - - return { - userPing, - getAccountFromEmail, - createUser, - getAccountFromId, - getAccountFromVerifyToken, - verifyAccountEmail, - banAccount, - }; -}; diff --git a/models/users.model.js b/models/users.model.js index ed7c1c0..1a797f4 100644 --- a/models/users.model.js +++ b/models/users.model.js @@ -32,6 +32,10 @@ module.exports = (sequelize) => { allowNull: true, type: DataTypes.INTEGER, }, + email_verify_token: { + allowNull: true, + type: DataTypes.TEXT, + }, }, { timestamps: false, }); diff --git a/routes/api.js b/routes/api.js index d9faeeb..7312366 100644 --- a/routes/api.js +++ b/routes/api.js @@ -65,9 +65,6 @@ router.get('/v1.1/devices/:dongleId/', runAsyncWrapper(async (req, res) => { const { dongleId } = req.params; logger.info(`HTTP.DEVICES called for ${req.params.dongleId}`); - - - const device = deviceController.getDeviceFromDongle(dongleId); if (!device) { diff --git a/routes/useradmin.js b/routes/useradmin.js index bd9d1a0..53c1fc6 100644 --- a/routes/useradmin.js +++ b/routes/useradmin.js @@ -11,16 +11,11 @@ const storageController = require('../controllers/storage'); const helperController = require('../controllers/helpers'); const mailingController = require('../controllers/mailing'); const deviceController = require('../controllers/devices'); +const userController = require('../controllers/users'); const logger = log4js.getLogger('default'); let models; -async function dbConnect() { - models = await require('../models/index')(); -} - -dbConnect(); - // TODO Remove this, pending on removing all auth logic from routes router.use(cookieParser()); @@ -57,10 +52,13 @@ router.get('/useradmin', runAsyncWrapper(async (req, res) => { return; } + /* TODO reimplement const accounts = await models.get('SELECT COUNT(*) AS num FROM accounts'); const devices = await models.get('SELECT COUNT(*) AS num FROM devices'); const drives = await models.get('SELECT COUNT(*) AS num, SUM(distance_meters) as distance, SUM(duration) as duration FROM drives'); + */ + res.status(200); res.send(`

Welcome To The RetroPilot Server Dashboard!

@@ -75,14 +73,16 @@ router.get('/useradmin', runAsyncWrapper(async (req, res) => {

${!config.allowAccountRegistration ? 'User Account Registration is disabled on this Server' : 'Register new Account'}

- Accounts: ${accounts.num} | - Devices: ${devices.num} | - Drives: ${drives.num} | - Distance Traveled: ${Math.round(drives.distance / 1000)} km | - Time Traveled: ${helperController.formatDuration(drives.duration)} | - Storage Used: ${await storageController.getTotalStorageUsed() !== null ? await storageController.getTotalStorageUsed() : '--'}

${config.welcomeMessage} -`); + +`, /* + Accounts: ${accounts.num} | + Devices: ${devices.num} | + Drives: ${drives.num} | + Distance Traveled: ${Math.round(drives.distance / 1000)} km | + Time Traveled: ${helperController.formatDuration(drives.duration)} | + Storage Used: ${await storageController.getTotalStorageUsed() !== null ? await storageController.getTotalStorageUsed() : '--'} +

${config.welcomeMessage}` */); })); router.post('/useradmin/register/token', bodyParser.urlencoded({ extended: true }), runAsyncWrapper(async (req, res) => { @@ -101,7 +101,7 @@ router.post('/useradmin/register/token', bodyParser.urlencoded({ extended: true return res.redirect('/useradmin/overview'); } - const account = await models.get('SELECT * FROM accounts WHERE LOWER(email) = ?', email.trim().toLowerCase()); + const account = await userController.getAccountFromEmail(email.trim().toLowerCase()); if (account != null) { return res.redirect(`/useradmin/register?status=${encodeURIComponent('Email is already registered')}`); } @@ -119,8 +119,7 @@ router.post('/useradmin/register/token', bodyParser.urlencoded({ extended: true } else if (req.body.password !== req.body.password2 || req.body.password.length < 3) { infoText = 'The passwords you entered did not match or were shorter than 3 characters, please try again.

'; } else { - const result = await models.run( - 'INSERT INTO accounts (email, password, created, banned) VALUES (?, ?, ?, ?)', + const result = userController._dirtyCreateAccount( email, crypto.createHash('sha256').update(req.body.password + config.applicationSalt).digest('hex'), Date.now(), @@ -179,8 +178,7 @@ router.get('/useradmin/overview', runAsyncWrapper(async (req, res) => { if (account == null) { return res.redirect(`/useradmin?status=${encodeURIComponent('Invalid or expired session')}`); } - - const devices = await models.all('SELECT * FROM devices WHERE account_id = ? ORDER BY dongle_id ASC', account.id); + const devices = await deviceController.getDevices(account.id); let response = `

Welcome To The RetroPilot Server Dashboard!

@@ -264,12 +262,12 @@ router.get('/useradmin/device/:dongleId', runAsyncWrapper(async (req, res) => { return res.redirect(`/useradmin?status=${encodeURIComponent('Invalid or expired session')}`); } - const device = await models.get('SELECT * FROM devices WHERE account_id = ? AND dongle_id = ?', account.id, dongleId); - if (device == null) { + const device = await deviceController.getDeviceFromDongle(req.params.dongleId); + if (device == null || device.account_id !== account.id) { return res.status(400).send('Unauthorized.'); } - const drives = await models.all('SELECT * FROM drives WHERE dongle_id = ? AND is_deleted = ? ORDER BY created DESC', device.dongle_id, false); + const drives = await deviceController.getDrives(device.dongle_id, false, true); const dongleIdHash = crypto.createHmac('sha256', config.applicationSalt).update(device.dongle_id).digest('hex'); @@ -386,29 +384,20 @@ router.get('/useradmin/drive/:dongleId/:driveIdentifier/:action', runAsyncWrappe return res.redirect(`/useradmin?status=${encodeURIComponent('Invalid or expired session')}`); } - const device = await models.get('SELECT * FROM devices WHERE account_id = ? AND dongle_id = ?', account.id, req.params.dongleId); - if (device == null) { - return res.status(400).send('Unauthorized.'); - } - - const drive = await models.get('SELECT * FROM drives WHERE identifier = ? AND dongle_id = ?', req.params.driveIdentifier, req.params.dongleId); + const drive = await deviceController.getDrive(req.params.dongleId, req.params.driveIdentifier); if (drive == null) { return res.status(400).send('Unauthorized.'); } const { action } = req.params; if (action === 'delete') { - await models.run( - 'UPDATE drives SET is_deleted = ? WHERE id = ?', - true, - drive.id, - ); + await deviceController.updateOrCreateDrive(req.params.dongleId, drive.id, { + is_deleted: true, + }); } else if (action === 'preserve') { - await models.run( - 'UPDATE drives SET is_preserved = ? WHERE id = ?', - true, - drive.id, - ); + await deviceController.updateOrCreateDrive(req.params.dongleId, drive.id, { + is_preserved: true, + }); } return res.redirect(`/useradmin/device/${device.dongle_id}`); @@ -420,12 +409,11 @@ router.get('/useradmin/drive/:dongleId/:driveIdentifier', runAsyncWrapper(async return res.redirect(`/useradmin?status=${encodeURIComponent('Invalid or expired session')}`); } - const device = await models.get('SELECT * FROM devices WHERE account_id = ? AND dongle_id = ?', account.id, req.params.dongleId); - if (device == null) { + const device = await deviceController.getDeviceFromDongle(req.params.dongleId); + if (device == null || device.account_id !== account.id) { return res.status(400).send('Unauthorized.'); } - - const drive = await models.get('SELECT * FROM drives WHERE identifier = ? AND dongle_id = ?', req.params.driveIdentifier, req.params.dongleId); + const drive = await deviceController.getDrive(req.params.dongleId, req.params.driveIdentifier); if (drive == null) { return res.status(400).send('Unauthorized.'); } @@ -606,12 +594,8 @@ router.get('/useradmin/drive/:dongleId/:driveIdentifier', runAsyncWrapper(async // get processed/stalled status let isProcessed = '?'; let isStalled = '?'; - const driveSegment = await models.get( - 'SELECT * FROM drive_segments WHERE segment_id = ? AND drive_identifier = ? AND dongle_id = ?', - parseInt(segment, 10), - drive.identifier, - device.dongle_id, - ); + const driveSegment = await deviceController.getDriveSegment(device.dongle_id, drive.identifier, parseInt(segment, 10)); + if (driveSegment) { isProcessed = driveSegment.is_processed; isStalled = driveSegment.is_stalled;